ft: Implement memory pointer (Mp) operand
This commit is contained in:
@@ -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"),
|
||||||
|
|||||||
@@ -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}"),
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user