chore: split up some structs and add comments

This commit is contained in:
2025-05-20 18:59:09 +09:00
parent 48eeff16fa
commit 058afeb7ba
7 changed files with 159 additions and 143 deletions

View File

@@ -1,3 +1,5 @@
//! Internal a.out File abstraction.
use std::ffi::{c_uchar, c_ushort}; use std::ffi::{c_uchar, c_ushort};
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]

View File

@@ -1,14 +1,15 @@
use core::fmt; //! The main dissembling logic.
use std::{fs::File, io::Read, process::exit};
use crate::aout::Aout; 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::register::{Register, RegisterId, SegmentRegister};
use crate::{ use crate::{
Args, Args,
instructions::{Instruction, Mnemonic}, instructions::{Instruction, Mnemonic},
}; };
use crate::{modrmb, modrms, modrmv}; use crate::{modrmb, modrms, modrmv};
use core::fmt;
use std::{fs::File, io::Read, process::exit};
#[derive(Debug)] #[derive(Debug)]
/// Generic errors, which are encountered during parsing. /// Generic errors, which are encountered during parsing.

View File

@@ -1,3 +1,5 @@
//! Some macros to help with disassembly parsing.
#[macro_export] #[macro_export]
/// Generate a Mnemonic for an 8-bit Register from a ModRM byte. /// Generate a Mnemonic for an 8-bit Register from a ModRM byte.
macro_rules! modrmb { macro_rules! modrmb {

View File

@@ -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 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)] #[derive(Debug, Clone)]
#[allow(dead_code)] #[allow(dead_code)]
/// A single 'line' of executable ASM is called an Instruction, which /// 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<Register>,
pub index: Option<Register>,
pub displacement: Option<Displacement>,
}
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)
}
}

View File

@@ -4,6 +4,7 @@ mod aout;
mod disasm; mod disasm;
mod disasm_macros; mod disasm_macros;
mod instructions; mod instructions;
mod operands;
mod register; mod register;
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]

141
src/operands.rs Normal file
View File

@@ -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<Register>,
pub index: Option<Register>,
pub displacement: Option<Displacement>,
}
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)
}
}

View File

@@ -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)] #[derive(Debug, Clone)]
#[allow(dead_code)] #[allow(dead_code)]