diff --git a/src/aout.rs b/src/aout.rs index 4c8451e..85de4e6 100644 --- a/src/aout.rs +++ b/src/aout.rs @@ -1,3 +1,5 @@ +//! Internal a.out File abstraction. + use std::ffi::{c_uchar, c_ushort}; #[allow(non_camel_case_types)] diff --git a/src/disasm.rs b/src/disasm.rs index a8583aa..705b907 100644 --- a/src/disasm.rs +++ b/src/disasm.rs @@ -1,14 +1,15 @@ -use core::fmt; -use std::{fs::File, io::Read, process::exit}; +//! The main dissembling logic. use crate::aout::Aout; -use crate::instructions::{Displacement, IByte, IWord, MemoryIndex, ModRmTarget, Operand, Pointer}; +use crate::operands::{Displacement, IByte, IWord, MemoryIndex, ModRmTarget, Operand, Pointer}; use crate::register::{Register, RegisterId, SegmentRegister}; use crate::{ Args, instructions::{Instruction, Mnemonic}, }; use crate::{modrmb, modrms, modrmv}; +use core::fmt; +use std::{fs::File, io::Read, process::exit}; #[derive(Debug)] /// Generic errors, which are encountered during parsing. diff --git a/src/disasm_macros.rs b/src/disasm_macros.rs index 00c62bd..f717d79 100644 --- a/src/disasm_macros.rs +++ b/src/disasm_macros.rs @@ -1,3 +1,5 @@ +//! Some macros to help with disassembly parsing. + #[macro_export] /// Generate a Mnemonic for an 8-bit Register from a ModRM byte. macro_rules! modrmb { diff --git a/src/instructions.rs b/src/instructions.rs index c6a9e2e..d31d489 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -1,38 +1,11 @@ +//! Internal abstraction of the 8086 instructions. + +use crate::{ + operands::{Byte, MemoryIndex, ModRmTarget, Pointer, Word}, + register::{Register, SegmentRegister}, +}; use core::fmt; -use crate::register::{Register, SegmentRegister}; - -pub type Byte = u8; // b -pub type IByte = i8; // used for displacements of memory access -pub type Word = u16; // w or v -pub type IWord = i16; // used for displacement of memory access - -#[derive(Debug, Clone)] -#[allow(dead_code)] -/// Encodes either Byte- or Word-sized operands. -pub enum Operand { - Byte(Byte), - Word(Word), -} - -impl fmt::Display for Operand { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Self::Byte(byte) => write!(f, "{}", byte), - Self::Word(word) => write!(f, "{}", word), - } - } -} - -impl fmt::LowerHex for Operand { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Byte(b) => fmt::LowerHex::fmt(b, f), - Self::Word(v) => fmt::LowerHex::fmt(v, f), - } - } -} - #[derive(Debug, Clone)] #[allow(dead_code)] /// A single 'line' of executable ASM is called an Instruction, which @@ -561,108 +534,3 @@ impl fmt::Display for Mnemonic { } } } - -#[derive(Debug, Clone)] -/// ModRM byte can either target a memory location or some register -pub enum ModRmTarget { - Memory(MemoryIndex), - Register(Register), -} - -impl std::fmt::Display for ModRmTarget { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::Memory(idx) => write!(f, "{}", idx), - Self::Register(reg) => write!(f, "{}", reg), - } - } -} - -#[derive(Debug, Clone)] -/// Memory displacements are signed versions of u8 and u16. -/// Encodes either Byte- or Word-sized operands. -pub enum Displacement { - IByte(i8), - IWord(i16), -} - -impl fmt::LowerHex for Displacement { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::IByte(b) => fmt::LowerHex::fmt(b, f), - Self::IWord(v) => fmt::LowerHex::fmt(v, f), - } - } -} - -impl std::fmt::Display for Displacement { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - match self { - Self::IByte(b) => { - if *b > 0 { - write!(f, " + {:#x}", b) - } else { - write!(f, " - {:#x}", b * -1) - } - } - Self::IWord(w) => { - if *w > 0 { - write!(f, " + {:#x}", w) - } else { - write!(f, " - {:#x}", w * -1) - } - } - } - } -} - -/// A memory index operand is usually created by ModRM bytes or words. -/// e.g. [bx+si] -#[derive(Debug, Clone)] -pub struct MemoryIndex { - pub base: Option, - pub index: Option, - pub displacement: Option, -} - -impl fmt::Display for MemoryIndex { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match &self.base { - Some(base) => match &self.index { - Some(index) => match &self.displacement { - Some(displacement) => { - write!(f, "[{} + {}{}]", base, index, displacement) - } - None => write!(f, "[{} + {}]", base, index), - }, - None => match &self.displacement { - Some(displacement) => write!(f, "[{}{}]", base, displacement), - None => write!(f, "[{}]", base), - }, - }, - None => match &self.index { - Some(index) => match &self.displacement { - Some(displacement) => write!(f, "[{}{}]", index, displacement), - None => write!(f, "[{}]", index), - }, - None => match &self.displacement { - Some(displacement) => write!(f, "[{:#x}]", displacement), - None => panic!("Memory Index without base, index and displacement"), - }, - }, - } - } -} - -#[derive(Debug, Clone)] -/// 32-bit segment:offset pointer (e.g. for CALL instruction) -pub struct Pointer { - pub segment: Word, - pub offset: Word, -} - -impl std::fmt::Display for Pointer { - fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "{}:{}", self.segment, self.offset) - } -} diff --git a/src/main.rs b/src/main.rs index c93e8da..7ca83ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod aout; mod disasm; mod disasm_macros; mod instructions; +mod operands; mod register; #[derive(Subcommand, Debug)] diff --git a/src/operands.rs b/src/operands.rs new file mode 100644 index 0000000..318579f --- /dev/null +++ b/src/operands.rs @@ -0,0 +1,141 @@ +//! All types which a Mnemonic can have as some kind of operand. +//! This includes things such as immediates, ModRM byte targets, etc. etc. + +use crate::register::Register; +use core::fmt; + +pub type Byte = u8; // b +pub type IByte = i8; // used for displacements of memory access +pub type Word = u16; // w or v +pub type IWord = i16; // used for displacement of memory access + +#[derive(Debug, Clone)] +#[allow(dead_code)] +/// Encodes either Byte- or Word-sized operands. +pub enum Operand { + Byte(Byte), + Word(Word), +} + +impl fmt::Display for Operand { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Byte(byte) => write!(f, "{}", byte), + Self::Word(word) => write!(f, "{}", word), + } + } +} + +impl fmt::LowerHex for Operand { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Byte(b) => fmt::LowerHex::fmt(b, f), + Self::Word(v) => fmt::LowerHex::fmt(v, f), + } + } +} + +#[derive(Debug, Clone)] +/// ModRM byte can either target a memory location or some register +pub enum ModRmTarget { + Memory(MemoryIndex), + Register(Register), +} + +impl std::fmt::Display for ModRmTarget { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::Memory(idx) => write!(f, "{}", idx), + Self::Register(reg) => write!(f, "{}", reg), + } + } +} + +#[derive(Debug, Clone)] +/// Memory displacements are signed versions of u8 and u16. +/// Encodes either Byte- or Word-sized operands. +pub enum Displacement { + IByte(i8), + IWord(i16), +} + +impl fmt::LowerHex for Displacement { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::IByte(b) => fmt::LowerHex::fmt(b, f), + Self::IWord(v) => fmt::LowerHex::fmt(v, f), + } + } +} + +impl std::fmt::Display for Displacement { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::IByte(b) => { + if *b > 0 { + write!(f, " + {:#x}", b) + } else { + write!(f, " - {:#x}", b * -1) + } + } + Self::IWord(w) => { + if *w > 0 { + write!(f, " + {:#x}", w) + } else { + write!(f, " - {:#x}", w * -1) + } + } + } + } +} + +/// A memory index operand is usually created by ModRM bytes or words. +/// e.g. [bx+si] +#[derive(Debug, Clone)] +pub struct MemoryIndex { + pub base: Option, + pub index: Option, + pub displacement: Option, +} + +impl fmt::Display for MemoryIndex { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match &self.base { + Some(base) => match &self.index { + Some(index) => match &self.displacement { + Some(displacement) => { + write!(f, "[{} + {}{}]", base, index, displacement) + } + None => write!(f, "[{} + {}]", base, index), + }, + None => match &self.displacement { + Some(displacement) => write!(f, "[{}{}]", base, displacement), + None => write!(f, "[{}]", base), + }, + }, + None => match &self.index { + Some(index) => match &self.displacement { + Some(displacement) => write!(f, "[{}{}]", index, displacement), + None => write!(f, "[{}]", index), + }, + None => match &self.displacement { + Some(displacement) => write!(f, "[{:#x}]", displacement), + None => panic!("Memory Index without base, index and displacement"), + }, + }, + } + } +} + +#[derive(Debug, Clone)] +/// 32-bit segment:offset pointer (e.g. for CALL instruction) +pub struct Pointer { + pub segment: Word, + pub offset: Word, +} + +impl std::fmt::Display for Pointer { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}:{}", self.segment, self.offset) + } +} diff --git a/src/register.rs b/src/register.rs index a9d1d2e..c0c864d 100644 --- a/src/register.rs +++ b/src/register.rs @@ -1,6 +1,7 @@ -use core::fmt; +//! Internal abstraction of all 8086 registers for disassembly. -use crate::instructions::Operand; +use crate::operands::Operand; +use core::fmt; #[derive(Debug, Clone)] #[allow(dead_code)]