fix: fix modrm parsing

Previously the wrong register was read in, now
the byte is deconstructed correctly
This commit is contained in:
2025-05-12 15:38:20 +09:00
parent 1dcd231f51
commit 317b5e5db4
2 changed files with 48 additions and 33 deletions

View File

@@ -74,8 +74,10 @@ impl Disassembler {
/// Parse a single byte of binary, return it and advance the offset.
/// Returns the read byte.
pub fn parse_byte(&mut self) -> u8 {
// advance to operand
self.offset += 1;
let byte = self.text[self.offset];
// jump to right after operand
self.offset += 1;
self.instruction.raw.push(byte);
byte
@@ -84,9 +86,11 @@ impl Disassembler {
/// Parse a single word of binary, return it and advance the offset.
/// Returns the read word.
pub fn parse_word(&mut self) -> u16 {
// advance to operand
self.offset += 1;
let byte1 = self.text[self.offset];
let byte2 = self.text[self.offset + 1];
// jump right after operand
self.offset += 2;
self.instruction.raw.push(byte1);
self.instruction.raw.push(byte2);
@@ -94,75 +98,84 @@ impl Disassembler {
}
/// Parse a single modrm byte, return the resulting MemoryIndex and advance the offset.
/// Returns the parsed modrm memory access, as well as all read raw bytes
pub fn parse_modrm_byte(&mut self) -> MemoryIndex {
/// Returns the parsed modrm memory access and the source register
pub fn parse_modrm_byte_to_memindex(&mut self) -> (MemoryIndex, Register) {
// advance to operand
self.offset += 1;
let modrm = self.text[self.offset];
self.instruction.raw.push(modrm);
// jump right after operand
self.offset += 1;
// Calculate ModRM byte with bitmask
let opcode = self.text[self.offset];
let modulo = opcode >> 6;
let reg = (opcode >> 3) & 7;
let rm = opcode & 7;
let modulo = modrm >> 6;
let reg = (modrm >> 3) & 7;
let rm = modrm & 7;
let displacement = match modulo {
0 => {
if rm == 6 {
// XXX: handle special case
panic!("Handle modulo == 0, rm == 6");
0b00 => {
if rm == 0b110 {
log::debug!("Additional word during ModRM parsing was read with mod 0.");
Some(Displacement::Word(self.parse_word()))
} else {
None
}
}
0b01 => {
log::debug!("Additional byte during ModRM parsing was read.");
Some(Displacement::Byte(self.parse_byte()))
}
0b10 => {
log::debug!("Additional word during ModRM parsing was read.");
Some(Displacement::Word(self.parse_word()))
}
0b11 => {
// XXX is this correct?
log::debug!(
"No displacement, as reg to reg - maybe some implementation is missing here"
);
None
}
1 => {
// self.offset += 2; // one additional byte was read
let byte = self.parse_byte();
log::debug!("Additional byte during ModRM parsing was read.");
Some(Displacement::Byte(byte))
}
2 => {
// self.offset += 3; // two additional bytes (word) was read
let word = self.parse_word();
log::debug!("Additional two bytes during ModRM parsing was read.");
Some(Displacement::Word(word))
}
3 => panic!("TODO: handle modulo == 3"),
_ => panic!("Invalid ModRM byte encountered"),
};
let index = match rm {
0 => MemoryIndex {
0b0000 => MemoryIndex {
base: Some(Register::BX),
index: Some(Register::SI),
displacement,
},
1 => MemoryIndex {
0b0001 => MemoryIndex {
base: Some(Register::BX),
index: Some(Register::DI),
displacement,
},
2 => MemoryIndex {
0b0010 => MemoryIndex {
base: Some(Register::BP),
index: Some(Register::SI),
displacement,
},
3 => MemoryIndex {
0b0011 => MemoryIndex {
base: Some(Register::BP),
index: Some(Register::DI),
displacement,
},
4 => MemoryIndex {
0b0100 => MemoryIndex {
base: None,
index: Some(Register::SI),
displacement,
},
5 => MemoryIndex {
0b0101 => MemoryIndex {
base: None,
index: Some(Register::DI),
displacement,
},
6 => MemoryIndex {
0b0110 => MemoryIndex {
base: Some(Register::BP),
index: None,
displacement,
},
7 => MemoryIndex {
0b0111 => MemoryIndex {
base: Some(Register::BX),
index: None,
displacement,
@@ -170,7 +183,7 @@ impl Disassembler {
_ => panic!("Invalid ModRM byte encountered"),
};
index
(index, Register::by_id(reg))
}
/// Decode instructions from the text section of the provided binary
@@ -193,7 +206,8 @@ impl Disassembler {
self.instruction.opcode = match opcode {
// ADD
0x00 => {
Opcode::ADD_EbGb(self.parse_modrm_byte(), Register::by_id(self.parse_byte()))
let (idx, reg) = self.parse_modrm_byte_to_memindex();
Opcode::ADD_EbGb(idx, reg)
}
// INT
0xCD => Opcode::INT(ImmediateByte(self.parse_byte())),

View File

@@ -61,6 +61,7 @@ impl fmt::Display for Opcode {
}
/// Registers of a 8086 processor
/// -x are 16bit, -l are 8bit
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub enum Register {