ft: implement group3a/b instructions

This commit is contained in:
2025-05-14 11:46:09 +09:00
parent 04493b1179
commit 38a2782cc6
3 changed files with 64 additions and 33 deletions

View File

@@ -8,7 +8,7 @@ use crate::{
Args, Args,
instructions::{Instruction, Mnemonic}, instructions::{Instruction, Mnemonic},
}; };
use crate::{modrmb, modrmgpr1b, modrmgpr1v, modrms, modrmv}; use crate::{modrmb, modrms, modrmv};
#[derive(Debug)] #[derive(Debug)]
/// Generic errors, which are encountered during parsing. /// Generic errors, which are encountered during parsing.
@@ -204,9 +204,10 @@ impl Disassembler {
} }
/// Match the modrm reg bits to the GPR1 mnemonics. /// Match the modrm reg bits to the GPR1 mnemonics.
/// GPR always has an imm value as second operand, but is available in both /// Group 1 always have an ModRM target (all modrm bits, without reg) as
/// Byte and Word length. /// first and an imm value as second operand (which has to be parsed before
pub fn modrm_reg_to_mnemonic(reg: u8, target: ModRmTarget, imm: Operand) -> Mnemonic { /// call to this function), but is available in both Byte and Word length.
pub fn modrm_reg_to_grp1(reg: u8, target: ModRmTarget, imm: Operand) -> Mnemonic {
match imm { match imm {
Operand::Byte(b) => match reg { Operand::Byte(b) => match reg {
0b000 => Mnemonic::ADD_Ib(target, b), 0b000 => Mnemonic::ADD_Ib(target, b),
@@ -217,7 +218,7 @@ impl Disassembler {
0b101 => Mnemonic::SUB_Ib(target, b), 0b101 => Mnemonic::SUB_Ib(target, b),
0b110 => Mnemonic::XOR_Ib(target, b), 0b110 => Mnemonic::XOR_Ib(target, b),
0b111 => Mnemonic::CMP_Ib(target, b), 0b111 => Mnemonic::CMP_Ib(target, b),
_ => panic!("Illegal GPR1 mnemonic"), _ => panic!("Illegal Group 1 mnemonic"),
}, },
Operand::Word(w) => match reg { Operand::Word(w) => match reg {
0b000 => Mnemonic::ADD_Iv(target, w), 0b000 => Mnemonic::ADD_Iv(target, w),
@@ -228,11 +229,31 @@ impl Disassembler {
0b101 => Mnemonic::SUB_Iv(target, w), 0b101 => Mnemonic::SUB_Iv(target, w),
0b110 => Mnemonic::XOR_Iv(target, w), 0b110 => Mnemonic::XOR_Iv(target, w),
0b111 => Mnemonic::CMP_Iv(target, w), 0b111 => Mnemonic::CMP_Iv(target, w),
_ => panic!("Illegal GPR1 mnemonic"), _ => panic!("Illegal Group 1 mnemonic"),
}, },
} }
} }
/// Match the modrm reg bits to the GPR3a/b mnemonics.
/// Group 3 only has a single operand, which is the ModRmTarget selected
/// by modrm bits.
pub fn modrm_reg_to_grp3(&mut self, reg: u8, target: ModRmTarget, width: Operand) -> Mnemonic {
match reg {
0b000 => match width {
Operand::Byte(_) => Mnemonic::TEST_Ib(target, self.parse_byte()),
Operand::Word(_) => Mnemonic::TEST_Iv(target, self.parse_word()),
},
// 0b001 => // unused
0b010 => Mnemonic::NOT(target),
0b011 => Mnemonic::NEG(target),
0b100 => Mnemonic::MUL(target),
0b101 => Mnemonic::IMUL(target),
0b110 => Mnemonic::DIV(target),
0b111 => Mnemonic::IDIV(target),
_ => panic!("Illegal Group 3 mnemonic"),
}
}
/// 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:
@@ -388,9 +409,22 @@ impl Disassembler {
0x7F => Mnemonic::JG(self.parse_byte()), 0x7F => Mnemonic::JG(self.parse_byte()),
// Group 1 // Group 1
0x80 => modrmgpr1b!(self), 0x80 => {
0x81 => modrmgpr1v!(self), let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
0x82 => modrmgpr1b!(self), // same as 0x80 let imm = self.parse_byte();
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))
}
0x81 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
let imm = self.parse_word();
Self::modrm_reg_to_grp1(reg, target, Operand::Word(imm))
}
0x82 => {
// same as 0x80
let (target, reg) = self.parse_modrm_byte(Operand::Byte(0));
let imm = self.parse_byte();
Self::modrm_reg_to_grp1(reg, target, Operand::Byte(imm))
}
0x83 => panic!("Sign extented GPR1 not yet implemented"), 0x83 => panic!("Sign extented GPR1 not yet implemented"),
0x84 => modrmb!(self, TEST), 0x84 => modrmb!(self, TEST),
@@ -490,6 +524,15 @@ impl Disassembler {
0xCD => Mnemonic::INT(self.parse_byte()), 0xCD => Mnemonic::INT(self.parse_byte()),
// Group 3 // Group 3
0xF6 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
self.modrm_reg_to_grp3(reg, target, Operand::Byte(0))
}
0xF7 => {
let (target, reg) = self.parse_modrm_byte(Operand::Word(0));
self.modrm_reg_to_grp3(reg, target, Operand::Word(0))
}
_ => { _ => {
eprintln!("Encountered unknown instruction '0x{:x}'", opcode); eprintln!("Encountered unknown instruction '0x{:x}'", opcode);
eprintln!("Offset might be misaligned and data is being interpreted."); eprintln!("Offset might be misaligned and data is being interpreted.");

View File

@@ -24,27 +24,3 @@ macro_rules! modrms {
Mnemonic::$variant(target, SegmentRegister::by_id(reg)) Mnemonic::$variant(target, SegmentRegister::by_id(reg))
}}; }};
} }
#[macro_export]
/// Generate the resulting Mnemonic from a GPR instruction with Byte-sized
/// Immediate, encoded in a ModRM byte.
/// GPR always has an imm value as second operand.
macro_rules! modrmgpr1b {
($self:ident) => {{
let (target, reg) = $self.parse_modrm_byte(Operand::Byte(0));
let imm = $self.parse_byte();
Self::modrm_reg_to_mnemonic(reg, target, Operand::Byte(imm))
}};
}
#[macro_export]
/// Generate the resulting Mnemonic from a GPR instruction with Word-sized
/// Immediate, encoded in a ModRM byte.
/// GPR always has an imm value as second operand.
macro_rules! modrmgpr1v {
($self:ident) => {{
let (target, reg) = $self.parse_modrm_byte(Operand::Word(0));
let imm = $self.parse_word();
Self::modrm_reg_to_mnemonic(reg, target, Operand::Word(imm))
}};
}

View File

@@ -160,6 +160,8 @@ pub enum Mnemonic {
JG(Byte), JG(Byte),
// TEST // TEST
TEST(ModRmTarget, Register), TEST(ModRmTarget, Register),
TEST_Ib(ModRmTarget, Byte),
TEST_Iv(ModRmTarget, Word),
TEST_ALIb(Byte), TEST_ALIb(Byte),
TEST_AXIv(Word), TEST_AXIv(Word),
//XHCG //XHCG
@@ -222,6 +224,16 @@ pub enum Mnemonic {
// Load ES/DS Register // Load ES/DS Register
LES(ModRmTarget), LES(ModRmTarget),
LDS(ModRmTarget), LDS(ModRmTarget),
// NOT
NOT(ModRmTarget),
// NEG
NEG(ModRmTarget),
// MUL
MUL(ModRmTarget),
IMUL(ModRmTarget),
// DIV
DIV(ModRmTarget),
IDIV(ModRmTarget),
// INT // INT
INT(Byte), INT(Byte),
} }