ft: introduce modrm macro for leaner matching

All instructions which use a modrm instruction
for memory reads from or into a register can
make use of this macro
This commit is contained in:
2025-05-12 19:53:25 +09:00
parent 317b5e5db4
commit 51b28b3bac
4 changed files with 51 additions and 16 deletions

View File

@@ -2,7 +2,8 @@ use core::fmt;
use std::{fs::File, io::Read, process::exit}; use std::{fs::File, io::Read, process::exit};
use crate::aout::Aout; use crate::aout::Aout;
use crate::instructions::{Displacement, MemoryIndex}; use crate::instructions::{Displacement, MemoryIndex, RegisterId, SegmentRegister};
use crate::modrm;
use crate::{ use crate::{
Args, Args,
instructions::{ImmediateByte, ImmediateWord, Instruction, Opcode, Register}, instructions::{ImmediateByte, ImmediateWord, Instruction, Opcode, Register},
@@ -99,7 +100,7 @@ impl Disassembler {
/// Parse a single modrm byte, return the resulting MemoryIndex and advance the offset. /// Parse a single modrm byte, return the resulting MemoryIndex and advance the offset.
/// Returns the parsed modrm memory access and the source register /// Returns the parsed modrm memory access and the source register
pub fn parse_modrm_byte_to_memindex(&mut self) -> (MemoryIndex, Register) { pub fn parse_modrm_byte(&mut self) -> (MemoryIndex, RegisterId) {
// advance to operand // advance to operand
self.offset += 1; self.offset += 1;
let modrm = self.text[self.offset]; let modrm = self.text[self.offset];
@@ -109,7 +110,7 @@ impl Disassembler {
// Calculate ModRM byte with bitmask // Calculate ModRM byte with bitmask
let modulo = modrm >> 6; let modulo = modrm >> 6;
let reg = (modrm >> 3) & 7; let reg_id = (modrm >> 3) & 7;
let rm = modrm & 7; let rm = modrm & 7;
let displacement = match modulo { let displacement = match modulo {
@@ -183,7 +184,7 @@ impl Disassembler {
_ => panic!("Invalid ModRM byte encountered"), _ => panic!("Invalid ModRM byte encountered"),
}; };
(index, Register::by_id(reg)) (index, reg_id)
} }
/// Decode instructions from the text section of the provided binary /// Decode instructions from the text section of the provided binary
@@ -205,14 +206,23 @@ impl Disassembler {
self.instruction.raw.push(opcode); self.instruction.raw.push(opcode);
self.instruction.opcode = match opcode { self.instruction.opcode = match opcode {
// ADD // ADD
0x00 => { 0x00 => modrm!(self, ADD_EbGb),
let (idx, reg) = self.parse_modrm_byte_to_memindex(); 0x01 => modrm!(self, ADD_EvGv),
Opcode::ADD_EbGb(idx, reg) 0x02 => modrm!(self, ADD_GbEb),
} 0x03 => modrm!(self, ADD_GvEv),
0x04 => Opcode::ADD_ALIb(ImmediateByte(self.parse_byte())),
0x05 => Opcode::ADD_AXIv(ImmediateWord(self.parse_word())),
// PUSH
0x06 => Opcode::PUSH(SegmentRegister::by_id(self.parse_modrm_byte().1)),
// POP
0x07 => Opcode::POP(SegmentRegister::by_id(self.parse_modrm_byte().1)),
// OR
0x08 => modrm!(self, OR_EbGb),
0x0A => modrm!(self, OR_GbEb),
// INT // INT
0xCD => Opcode::INT(ImmediateByte(self.parse_byte())), 0xCD => Opcode::INT(ImmediateByte(self.parse_byte())),
// MOV // MOV
0xBB => Opcode::MOV_BXIv(Register::BX, ImmediateWord(self.parse_word())), 0xBB => Opcode::MOV_BXIv(ImmediateWord(self.parse_word())),
_ => { _ => {
eprintln!( eprintln!(
"Encountered unknown self.instructionuction '0x{:x}'", "Encountered unknown self.instructionuction '0x{:x}'",

8
src/disasm_macros.rs Normal file
View File

@@ -0,0 +1,8 @@
#[macro_export]
/// Generate an Opcode for 'normal' ModRM instructions with mem access and a reg
macro_rules! modrm {
($self:ident, $variant:ident) => {{
let (idx, reg) = $self.parse_modrm_byte();
Opcode::$variant(idx, Register::by_id(reg))
}};
}

View File

@@ -43,10 +43,22 @@ pub enum Opcode {
NOP(), NOP(),
// ADD // ADD
ADD_EbGb(MemoryIndex, Register), ADD_EbGb(MemoryIndex, Register),
// MOV ADD_EvGv(MemoryIndex, Register),
MOV_BXIv(Register, ImmediateWord), ADD_GbEb(MemoryIndex, Register),
ADD_GvEv(MemoryIndex, Register),
ADD_ALIb(ImmediateByte),
ADD_AXIv(ImmediateWord),
// PUSH
PUSH(SegmentRegister),
// POP
POP(SegmentRegister),
// OR
OR_EbGb(MemoryIndex, Register),
OR_GbEb(MemoryIndex, Register),
// INT // INT
INT(ImmediateByte), INT(ImmediateByte),
// MOV
MOV_BXIv(ImmediateWord),
} }
impl fmt::Display for Opcode { impl fmt::Display for Opcode {
@@ -54,7 +66,8 @@ impl fmt::Display for Opcode {
match self { match self {
Self::INT(byte) => write!(f, "INT, {:x}", byte), Self::INT(byte) => write!(f, "INT, {:x}", byte),
Self::ADD_EbGb(mem, reg) => write!(f, "ADD {}, {}", mem, reg), Self::ADD_EbGb(mem, reg) => write!(f, "ADD {}, {}", mem, reg),
Self::MOV_BXIv(reg, word) => write!(f, "MOV {}, {:04x}", reg, word), Self::ADD_GbEb(mem, reg) => write!(f, "ADD {}, {}", reg, mem),
Self::MOV_BXIv(word) => write!(f, "MOV BX, {:04x}", word),
_ => write!(f, "display not yet implemented"), _ => write!(f, "display not yet implemented"),
} }
} }
@@ -83,10 +96,13 @@ pub enum Register {
SP, SP,
} }
/// Selector for Register or Segment Register
pub type RegisterId = u8;
#[allow(dead_code)] #[allow(dead_code)]
impl Register { impl Register {
/// Find the register corresponding to the 8086 bytecode ID /// Find the register corresponding to the 8086 bytecode ID
pub fn by_id(id: u8) -> Self { pub fn by_id(id: RegisterId) -> Self {
match id { match id {
0x00 => Self::AL, 0x00 => Self::AL,
0x01 => Self::CL, 0x01 => Self::CL,
@@ -133,7 +149,7 @@ impl fmt::Display for Register {
} }
/// Segment Registers of a 8086 processor /// Segment Registers of a 8086 processor
#[derive(Debug)] #[derive(Debug, Clone)]
#[allow(dead_code)] #[allow(dead_code)]
pub enum SegmentRegister { pub enum SegmentRegister {
DS, DS,
@@ -213,13 +229,13 @@ impl fmt::Display for MemoryIndex {
}, },
None => match &self.displacement { None => match &self.displacement {
Some(displacement) => write!(f, "[{}+{}]", base, displacement), Some(displacement) => write!(f, "[{}+{}]", base, displacement),
None => write!(f, "[{}]", base), None => write!(f, "{}", base),
}, },
}, },
None => match &self.index { None => match &self.index {
Some(index) => match &self.displacement { Some(index) => match &self.displacement {
Some(displacement) => write!(f, "{}+{}", index, displacement), Some(displacement) => write!(f, "{}+{}", index, displacement),
None => write!(f, "[{}]", index), None => write!(f, "{}", index),
}, },
None => panic!("Invalid MemoryIndex encountered"), None => panic!("Invalid MemoryIndex encountered"),
}, },

View File

@@ -2,6 +2,7 @@ use clap::{Parser, Subcommand};
mod aout; mod aout;
mod disasm; mod disasm;
mod disasm_macros;
mod instructions; mod instructions;
#[derive(Subcommand, Debug)] #[derive(Subcommand, Debug)]