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:
@@ -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
8
src/disasm_macros.rs
Normal 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))
|
||||||
|
}};
|
||||||
|
}
|
||||||
@@ -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"),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
Reference in New Issue
Block a user