ft: Implement memory pointer (Mp) operand

This commit is contained in:
2025-05-25 11:00:47 +09:00
parent 6762195378
commit 73b1a99cbd
3 changed files with 63 additions and 19 deletions

View File

@@ -19,6 +19,7 @@ pub enum DisasmError {
NoFile(Option<String>), NoFile(Option<String>),
IoError(std::io::Error), IoError(std::io::Error),
OpcodeUndefined(u8), OpcodeUndefined(u8),
IndexOutOfBounds(usize),
} }
impl From<std::io::Error> for DisasmError { impl From<std::io::Error> for DisasmError {
@@ -37,6 +38,7 @@ impl fmt::Display for DisasmError {
"Instruction '{:#x} is considered undefined by the Spec", "Instruction '{:#x} is considered undefined by the Spec",
opcode opcode
), ),
DisasmError::IndexOutOfBounds(msg) => write!(f, "Out of bounds read at {}", msg),
} }
} }
} }
@@ -67,7 +69,7 @@ fn path_to_buf(args: &Args) -> Result<Vec<u8>, DisasmError> {
} }
#[derive(Debug)] #[derive(Debug)]
struct Disassembler { pub struct Disassembler {
pub offset: usize, // the current offset in the disasm process pub offset: usize, // the current offset in the disasm process
pub text: Vec<u8>, // the aout binary pub text: Vec<u8>, // the aout binary
pub instruction: Instruction, // the instruction, which is currently being parsed pub instruction: Instruction, // the instruction, which is currently being parsed
@@ -97,6 +99,7 @@ impl Disassembler {
pub fn parse_word(&mut self) -> u16 { pub fn parse_word(&mut self) -> u16 {
// advance to operand // advance to operand
self.offset += 1; self.offset += 1;
// XXX: wrap in Result<>
let byte1 = self.text[self.offset]; let byte1 = self.text[self.offset];
let byte2 = self.text[self.offset + 1]; let byte2 = self.text[self.offset + 1];
// jump onto last operand // jump onto last operand
@@ -327,6 +330,15 @@ impl Disassembler {
} }
} }
/// Parse an Mp Operand (Memory Pointer).
/// An Mp is a ModRM byte with the `reg` bits ignored and an additional
/// 2 words parsed for a `Pointer` type.
pub fn modrm_mp(&mut self) -> Result<(ModRmTarget, Pointer), DisasmError> {
let (target, _) = self.parse_modrm_byte(Operand::Byte(0));
let ptr = Pointer::new(self)?;
Ok((target, ptr))
}
/// Decode instructions from the text section of the provided binary /// Decode instructions from the text section of the provided binary
pub fn decode_instructions(&mut self) -> Result<Vec<Instruction>, DisasmError> { pub fn decode_instructions(&mut self) -> Result<Vec<Instruction>, DisasmError> {
// naive approach: // naive approach:
@@ -602,7 +614,14 @@ impl Disassembler {
0xC2 => Mnemonic::RET_Iw(self.parse_word()), 0xC2 => Mnemonic::RET_Iw(self.parse_word()),
0xC3 => Mnemonic::RET, 0xC3 => Mnemonic::RET,
0xC4..=0xC5 => todo!("LES and LDS not yet implemented"), 0xC4 => {
let (target, ptr) = self.modrm_mp()?;
Mnemonic::LES(target, ptr)
}
0xC5 => {
let (target, ptr) = self.modrm_mp()?;
Mnemonic::LDS(target, ptr)
}
0xC6 => { 0xC6 => {
let (target, _) = self.parse_modrm_byte(Operand::Byte(0)); let (target, _) = self.parse_modrm_byte(Operand::Byte(0));
@@ -664,16 +683,7 @@ impl Disassembler {
0xE8 => Mnemonic::CALL_v(self.parse_j_word()), 0xE8 => Mnemonic::CALL_v(self.parse_j_word()),
0xE9 => Mnemonic::JMP_v(self.parse_j_word()), 0xE9 => Mnemonic::JMP_v(self.parse_j_word()),
0xEA => Mnemonic::JMP_p(Pointer { 0xEA => Mnemonic::JMP_p(Pointer::new(self)?),
raw: DWord::from_le_bytes([
self.text[self.offset],
self.text[self.offset + 1],
self.text[self.offset + 2],
self.text[self.offset + 3],
]),
segment: self.parse_word(),
offset: self.parse_word(),
}),
0xEB => Mnemonic::JMP_b(self.parse_j_byte()), 0xEB => Mnemonic::JMP_b(self.parse_j_byte()),
0xEC => Mnemonic::IN_ALDX, 0xEC => Mnemonic::IN_ALDX,
@@ -722,9 +732,9 @@ impl Disassembler {
0b000 => Mnemonic::INC_Mod(target), 0b000 => Mnemonic::INC_Mod(target),
0b001 => Mnemonic::DEC_Mod(target), 0b001 => Mnemonic::DEC_Mod(target),
0b010 => Mnemonic::CALL_Mod(target), 0b010 => Mnemonic::CALL_Mod(target),
0b011 => todo!("Implement CALL Mp"), 0b011 => Mnemonic::CALL_Mp(target, Pointer::new(self)?),
0b100 => Mnemonic::JMP_Mod(target), 0b100 => Mnemonic::JMP_Mod(target),
0b101 => todo!("Implement JMP Mp"), 0b101 => Mnemonic::JMP_Mp(target, Pointer::new(self)?),
0b110 => Mnemonic::PUSH_Mod(target), 0b110 => Mnemonic::PUSH_Mod(target),
// 0b111 => unused // 0b111 => unused
_ => panic!("Illegal Group 5 mnemonic"), _ => panic!("Illegal Group 5 mnemonic"),

View File

@@ -206,11 +206,13 @@ pub enum Mnemonic {
CALL_p(Pointer), CALL_p(Pointer),
CALL_v(isize), CALL_v(isize),
CALL_Mod(ModRmTarget), CALL_Mod(ModRmTarget),
CALL_Mp(ModRmTarget, Pointer),
// JUMP // JUMP
JMP_p(Pointer), JMP_p(Pointer),
JMP_b(isize), // parses IByte, but stores as isize JMP_b(isize), // parses IByte, but stores as isize
JMP_v(isize), // parwses IWord, but stores as isize JMP_v(isize), // parwses IWord, but stores as isize
JMP_Mod(ModRmTarget), JMP_Mod(ModRmTarget),
JMP_Mp(ModRmTarget, Pointer),
// WAIT // WAIT
WAIT, WAIT,
// Push/Pop Flags // Push/Pop Flags
@@ -236,8 +238,8 @@ pub enum Mnemonic {
RETF, RETF,
IRET, IRET,
// Load ES/DS Register // Load ES/DS Register
LES(ModRmTarget), LES(ModRmTarget, Pointer),
LDS(ModRmTarget), LDS(ModRmTarget, Pointer),
// NOT // NOT
NOT(ModRmTarget), NOT(ModRmTarget),
// NEG // NEG
@@ -443,11 +445,13 @@ impl fmt::Display for Mnemonic {
Self::CALL_p(ptr) => write!(f, "call {ptr}"), Self::CALL_p(ptr) => write!(f, "call {ptr}"),
Self::CALL_v(word) => write!(f, "call {word:#04x}"), Self::CALL_v(word) => write!(f, "call {word:#04x}"),
Self::CALL_Mod(target) => write!(f, "call {target}"), Self::CALL_Mod(target) => write!(f, "call {target}"),
Self::CALL_Mp(target, ptr) => write!(f, "call {target}, {ptr}"),
Self::JMP_p(ptr) => write!(f, "jmp {ptr}"), Self::JMP_p(ptr) => write!(f, "jmp {ptr}"),
Self::JMP_b(byte) => write!(f, "jmp {byte:#04x}"), Self::JMP_b(byte) => write!(f, "jmp {byte:#04x}"),
Self::JMP_v(word) => write!(f, "jmp {word:#04x}"), Self::JMP_v(word) => write!(f, "jmp {word:#04x}"),
Self::JMP_Mod(target) => write!(f, "jmp {target}"), Self::JMP_Mod(target) => write!(f, "jmp {target}"),
Self::JMP_Mp(target, ptr) => write!(f, "jmp {target}, {ptr}"),
Self::WAIT => write!(f, "wait"), Self::WAIT => write!(f, "wait"),
@@ -473,8 +477,8 @@ impl fmt::Display for Mnemonic {
Self::RETF => write!(f, "retf"), Self::RETF => write!(f, "retf"),
Self::IRET => write!(f, "iret"), Self::IRET => write!(f, "iret"),
Self::LES(target) => write!(f, "les {target}"), Self::LES(target, ptr) => write!(f, "les {target}, {ptr}"),
Self::LDS(target) => write!(f, "lds {target}"), Self::LDS(target, ptr) => write!(f, "lds {target}, {ptr}"),
Self::NOT(target) => write!(f, "not {target}"), Self::NOT(target) => write!(f, "not {target}"),
Self::NEG(target) => write!(f, "neg {target}"), Self::NEG(target) => write!(f, "neg {target}"),

View File

@@ -1,7 +1,10 @@
//! All types which a Mnemonic can have as some kind of operand. //! All types which a Mnemonic can have as some kind of operand.
//! This includes things such as immediates, ModRM byte targets, etc. etc. //! This includes things such as immediates, ModRM byte targets, etc. etc.
use crate::register::Register; use crate::{
disasm::{DisasmError, Disassembler},
register::Register,
};
use core::fmt; use core::fmt;
pub type Byte = u8; // b pub type Byte = u8; // b
@@ -136,6 +139,33 @@ pub struct Pointer {
pub offset: Word, pub offset: Word,
} }
impl Pointer {
pub fn new(disasm: &mut Disassembler) -> Result<Self, DisasmError> {
let byte0 = disasm
.text
.get(disasm.offset)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset))?;
let byte1 = disasm
.text
.get(disasm.offset + 1)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset + 1))?;
let byte2 = disasm
.text
.get(disasm.offset + 2)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset + 2))?;
let byte3 = disasm
.text
.get(disasm.offset + 3)
.ok_or(DisasmError::IndexOutOfBounds(disasm.offset + 3))?;
Ok(Pointer {
raw: DWord::from_le_bytes([*byte0, *byte1, *byte2, *byte3]),
segment: disasm.parse_word(),
offset: disasm.parse_word(),
})
}
}
impl std::fmt::Display for Pointer { impl std::fmt::Display for Pointer {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "[{:#04x}] ({}:{})", self.raw, self.segment, self.offset) write!(f, "[{:#04x}] ({}:{})", self.raw, self.segment, self.offset)