ft: initial disasm of example data
This only contains two instructions of which I know the correct output.
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
403
Cargo.lock
generated
Normal file
403
Cargo.lock
generated
Normal file
@@ -0,0 +1,403 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.6.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "env"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc95de49ad098572c02d3fbf368c9a020bfff5ae78483685b77f51d8a7e9486d"
|
||||
dependencies = [
|
||||
"num_threads",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_filter"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"env_filter",
|
||||
"jiff",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "jiff"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d07d8d955d798e7a4d6f9c58cd1f1916e790b42b092758a9ef6e16fef9f1b3fd"
|
||||
dependencies = [
|
||||
"jiff-static",
|
||||
"log",
|
||||
"portable-atomic",
|
||||
"portable-atomic-util",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jiff-static"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f244cfe006d98d26f859c7abd1318d85327e1882dc9cef80f62daeeb0adcf300"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "mimix-8086-rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"env",
|
||||
"env_logger",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic-util"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
|
||||
dependencies = [
|
||||
"portable-atomic",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "mimix-8086-rs"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
clap = { version = "4.5.37", features = ["derive"] }
|
||||
env = "1.0.1"
|
||||
env_logger = "0.11.8"
|
||||
log = "0.4.27"
|
||||
62
src/aout.rs
Normal file
62
src/aout.rs
Normal file
@@ -0,0 +1,62 @@
|
||||
use std::ffi::{c_uchar, c_ushort};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type c_long = i32; // we use a a.out with 32 byte
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Aout {
|
||||
pub header: Header,
|
||||
pub text: Vec<u8>,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Aout {
|
||||
pub fn new(buf: Vec<u8>) -> Self {
|
||||
let hdr = Header {
|
||||
magic: [buf[0], buf[1]],
|
||||
flags: buf[2],
|
||||
cpu: buf[3],
|
||||
hdrlen: buf[4],
|
||||
unused: buf[5],
|
||||
version: c_ushort::from_be_bytes([buf[6], buf[7]]),
|
||||
text: c_long::from_le_bytes([buf[8], buf[9], buf[10], buf[11]]),
|
||||
data: c_long::from_le_bytes([buf[12], buf[13], buf[14], buf[15]]),
|
||||
bss: c_long::from_le_bytes([buf[16], buf[17], buf[18], buf[19]]),
|
||||
entry: c_long::from_le_bytes([buf[20], buf[21], buf[22], buf[23]]),
|
||||
total: c_long::from_le_bytes([buf[24], buf[25], buf[26], buf[27]]),
|
||||
syms: c_long::from_le_bytes([buf[28], buf[29], buf[30], buf[31]]),
|
||||
};
|
||||
|
||||
let text_start = hdr.hdrlen as usize;
|
||||
let text_end = text_start + hdr.text as usize;
|
||||
let data_start = text_end + 1;
|
||||
let data_end = data_start + hdr.data as usize;
|
||||
|
||||
let text_section = &buf[text_start..text_end];
|
||||
let data_section = &buf[data_start..data_end];
|
||||
|
||||
Aout {
|
||||
header: hdr,
|
||||
text: Vec::from(text_section),
|
||||
data: Vec::from(data_section),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct Header {
|
||||
pub magic: [c_uchar; 2], // magic number
|
||||
pub flags: c_uchar, // flags, see below
|
||||
pub cpu: c_uchar, // cpu id
|
||||
pub hdrlen: c_uchar, // length of header
|
||||
pub unused: c_uchar, // reserved for future use
|
||||
pub version: c_ushort, // version stamp
|
||||
pub text: c_long, // size of text segment in bytes
|
||||
pub data: c_long, // size of data segment in bytes
|
||||
pub bss: c_long, // size of bss segment in bytes
|
||||
pub entry: c_long, // entry point
|
||||
pub total: c_long, // total memory allocated
|
||||
pub syms: c_long, // size of symbol table
|
||||
}
|
||||
1
src/decode.rs
Normal file
1
src/decode.rs
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
103
src/disasm.rs
Normal file
103
src/disasm.rs
Normal file
@@ -0,0 +1,103 @@
|
||||
use core::fmt;
|
||||
use std::{fs::File, io::Read, process::exit};
|
||||
|
||||
use crate::aout::Aout;
|
||||
use crate::{
|
||||
Args,
|
||||
instructions::{ImmediateByte, ImmediateWord, Instruction, MetaInstruction, Register},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DisasmError {
|
||||
NoFile(Option<String>),
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for DisasmError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
DisasmError::IoError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DisasmError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
DisasmError::NoFile(msg) => write!(f, "No file error: {:?}", msg),
|
||||
DisasmError::IoError(msg) => write!(f, "{}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Disassemble the binary in `path` into a vector of instructions
|
||||
/// This function just calls all other
|
||||
pub fn disasm(args: &Args) -> Result<Vec<MetaInstruction>, DisasmError> {
|
||||
let contents = path_to_buf(args)?;
|
||||
let aout = Aout::new(contents);
|
||||
|
||||
// XXX: 00 is just 0, maybe this could be a problem?
|
||||
log::debug!("{:?}", aout);
|
||||
|
||||
let instructions = decode_instructions(&aout)?;
|
||||
|
||||
Ok(instructions)
|
||||
}
|
||||
|
||||
/// Read a filepath into a buffer
|
||||
fn path_to_buf(args: &Args) -> Result<Vec<u8>, DisasmError> {
|
||||
let path = args
|
||||
.path
|
||||
.clone()
|
||||
.ok_or(DisasmError::NoFile(args.path.clone()))?;
|
||||
let mut file = File::open(path)?;
|
||||
let mut buf = Vec::new();
|
||||
file.read_to_end(&mut buf)?;
|
||||
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Decode instructions from the text section of the provided binary
|
||||
fn decode_instructions(aout: &Aout) -> Result<Vec<MetaInstruction>, DisasmError> {
|
||||
// naive approach:
|
||||
// 1. read byte
|
||||
// 2. pattern match to see which instruction it is
|
||||
// 3. read as many bytes as this instruction needs (registers, immidiates, ...)
|
||||
// repeat until no bytes left
|
||||
|
||||
let instructions = Vec::new();
|
||||
let mut offset = 0;
|
||||
|
||||
let text = &aout.text;
|
||||
while offset < aout.text.len() {
|
||||
let mut instr = MetaInstruction::new();
|
||||
instr.start = offset;
|
||||
|
||||
let opcode = text[offset];
|
||||
match opcode {
|
||||
// 0x00 => {} // ADD
|
||||
// INT
|
||||
0xCD => {
|
||||
instr.take_n_bytes(2, &mut offset, text);
|
||||
instr.instruction = Instruction::INT(ImmediateByte(instr.raw[1]));
|
||||
}
|
||||
// MOV
|
||||
0xBB => {
|
||||
instr.take_n_bytes(3, &mut offset, text);
|
||||
instr.instruction = Instruction::MOV_RI(
|
||||
Register::BX,
|
||||
ImmediateWord(u16::from_le_bytes([instr.raw[1], instr.raw[2]])),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
eprintln!("Encountered unknown instruction '0x{:x}'", opcode);
|
||||
eprintln!("Offset might be misaligned and data is being interpreted.");
|
||||
eprintln!("Existing to avoid further misinterpretation...");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
println!("{}", instr);
|
||||
// dbg!(&instr);
|
||||
}
|
||||
|
||||
Ok(instructions)
|
||||
}
|
||||
183
src/instructions.rs
Normal file
183
src/instructions.rs
Normal file
@@ -0,0 +1,183 @@
|
||||
use core::fmt;
|
||||
|
||||
pub type MemAddress = u8;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
/// A single 'line' of executable ASM is called a MetaInstruction, which
|
||||
/// contains the `Instruction`, which will be executed, alongside some Meta
|
||||
/// Informations.
|
||||
pub struct MetaInstruction {
|
||||
pub start: usize, // location of the instruction start
|
||||
pub size: usize, // size of the instruction in bytes
|
||||
pub raw: Vec<u8>, // raw value of instruction
|
||||
pub instruction: Instruction, // actual instruction
|
||||
}
|
||||
|
||||
impl MetaInstruction {
|
||||
pub fn new() -> Self {
|
||||
MetaInstruction {
|
||||
start: 0,
|
||||
size: 0,
|
||||
raw: Vec::new(),
|
||||
instruction: Instruction::NOP(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse n bytes from text section and advance offet.
|
||||
/// Used to get the operands.
|
||||
pub fn take_n_bytes(&mut self, size: usize, offset: &mut usize, text: &Vec<u8>) {
|
||||
self.size = size;
|
||||
self.raw = text[*offset as usize..]
|
||||
.iter()
|
||||
.take(size)
|
||||
.cloned()
|
||||
.collect();
|
||||
*offset += size;
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for MetaInstruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:04x}: ", self.start).unwrap();
|
||||
for b in self.raw.iter() {
|
||||
write!(f, "{:02x}", b).unwrap();
|
||||
}
|
||||
write!(f, "\t{}", self.instruction)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code, non_camel_case_types)]
|
||||
pub enum Instruction {
|
||||
NOP(),
|
||||
// ADD
|
||||
ADD_RM(Register, Memory),
|
||||
ADD_MR(Memory, Register),
|
||||
ADD_RR(Register, Register),
|
||||
ADD_MI(Memory, ImmediateByte),
|
||||
ADD_RI(Register, ImmediateByte),
|
||||
// MOV
|
||||
MOV_RM(Register, Memory),
|
||||
MOV_MR(Memory, Register),
|
||||
MOV_RR(Register, Register),
|
||||
MOV_MI(Memory, ImmediateByte),
|
||||
MOV_RI(Register, ImmediateWord),
|
||||
MOV_SM(SRegister, Memory),
|
||||
MOV_MS(Memory, SRegister),
|
||||
MOV_RS(Register, SRegister),
|
||||
MOV_SR(SRegister, Register),
|
||||
// INT
|
||||
INT(ImmediateByte),
|
||||
}
|
||||
|
||||
impl fmt::Display for Instruction {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::INT(byte) => write!(f, "INT, {:x}", byte),
|
||||
Self::MOV_RI(reg, word) => write!(f, "MOV {}, {:04x}", reg, word),
|
||||
_ => write!(f, "display not yet implemented"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Types for operand encoding
|
||||
#[derive(Debug)]
|
||||
pub struct Memory(pub MemAddress);
|
||||
#[derive(Debug)]
|
||||
pub struct ImmediateByte(pub u8);
|
||||
#[derive(Debug)]
|
||||
pub struct ImmediateWord(pub u16);
|
||||
|
||||
// ... and the displays for all of them
|
||||
impl fmt::Display for Memory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for ImmediateByte {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl fmt::LowerHex for ImmediateByte {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::LowerHex::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for ImmediateWord {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
impl fmt::LowerHex for ImmediateWord {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::LowerHex::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers of a 8086 processor
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Register {
|
||||
AX,
|
||||
BX,
|
||||
CX,
|
||||
DX,
|
||||
AH,
|
||||
AL,
|
||||
BL,
|
||||
BH,
|
||||
CH,
|
||||
CL,
|
||||
DH,
|
||||
DL,
|
||||
DI,
|
||||
SI,
|
||||
BP,
|
||||
SP,
|
||||
}
|
||||
|
||||
impl fmt::Display for Register {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::AX => write!(f, "AX"),
|
||||
Self::BX => write!(f, "BX"),
|
||||
Self::CX => write!(f, "CX"),
|
||||
Self::DX => write!(f, "DX"),
|
||||
Self::AH => write!(f, "AH"),
|
||||
Self::AL => write!(f, "AL"),
|
||||
Self::BL => write!(f, "BL"),
|
||||
Self::BH => write!(f, "BH"),
|
||||
Self::CH => write!(f, "CH"),
|
||||
Self::CL => write!(f, "CL"),
|
||||
Self::DH => write!(f, "DH"),
|
||||
Self::DL => write!(f, "DL"),
|
||||
Self::DI => write!(f, "DI"),
|
||||
Self::SI => write!(f, "SI"),
|
||||
Self::BP => write!(f, "BP"),
|
||||
Self::SP => write!(f, "SP"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// SRegisters of a 8086 processor
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum SRegister {
|
||||
DS,
|
||||
ES,
|
||||
SS,
|
||||
CS,
|
||||
}
|
||||
|
||||
impl fmt::Display for SRegister {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::DS => write!(f, "DS"),
|
||||
Self::ES => write!(f, "ES"),
|
||||
Self::SS => write!(f, "SS"),
|
||||
Self::CS => write!(f, "CS"),
|
||||
}
|
||||
}
|
||||
}
|
||||
41
src/main.rs
Normal file
41
src/main.rs
Normal file
@@ -0,0 +1,41 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
|
||||
mod aout;
|
||||
mod decode;
|
||||
mod disasm;
|
||||
mod instructions;
|
||||
|
||||
#[derive(Subcommand, Debug)]
|
||||
enum Command {
|
||||
/// Disassemble the binary into 8086 instructions
|
||||
Disasm,
|
||||
|
||||
/// Interpret the binary as 8086 Minix
|
||||
Interpret,
|
||||
}
|
||||
|
||||
/// Simple prgram to diasm and interpret Minix binaries
|
||||
#[derive(Parser, Debug)]
|
||||
#[command(version, about, long_about = None)]
|
||||
struct Args {
|
||||
#[command(subcommand)]
|
||||
command: Command,
|
||||
|
||||
/// Path of the binary
|
||||
#[arg(short, long, global = true)]
|
||||
path: Option<String>,
|
||||
}
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let args = Args::parse();
|
||||
log::debug!("{:?}", args);
|
||||
|
||||
match args.command {
|
||||
Command::Disasm => {
|
||||
let _instructions = disasm::disasm(&args).unwrap();
|
||||
}
|
||||
_ => panic!("Command not yet implemented"),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user