From 2af4578c8b967d49a4bd76ad30008ad75e27edf6 Mon Sep 17 00:00:00 2001 From: Marco Thomas Date: Wed, 7 May 2025 15:48:44 +0900 Subject: [PATCH] ft: initial disasm of example data This only contains two instructions of which I know the correct output. --- .gitignore | 1 + Cargo.lock | 403 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 ++ src/aout.rs | 62 +++++++ src/decode.rs | 1 + src/disasm.rs | 103 +++++++++++ src/instructions.rs | 183 ++++++++++++++++++++ src/main.rs | 41 +++++ 8 files changed, 804 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 src/aout.rs create mode 100644 src/decode.rs create mode 100644 src/disasm.rs create mode 100644 src/instructions.rs create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..c7e8dd0 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8a0ff26 --- /dev/null +++ b/Cargo.toml @@ -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" diff --git a/src/aout.rs b/src/aout.rs new file mode 100644 index 0000000..80a6979 --- /dev/null +++ b/src/aout.rs @@ -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, + pub data: Vec, +} + +impl Aout { + pub fn new(buf: Vec) -> 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 +} diff --git a/src/decode.rs b/src/decode.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/src/decode.rs @@ -0,0 +1 @@ + diff --git a/src/disasm.rs b/src/disasm.rs new file mode 100644 index 0000000..26e5182 --- /dev/null +++ b/src/disasm.rs @@ -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), + IoError(std::io::Error), +} + +impl From 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, 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, 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, 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) +} diff --git a/src/instructions.rs b/src/instructions.rs new file mode 100644 index 0000000..103746c --- /dev/null +++ b/src/instructions.rs @@ -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, // 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) { + 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"), + } + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..0df0873 --- /dev/null +++ b/src/main.rs @@ -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, +} + +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"), + } +}