diff --git a/src/disasm.rs b/src/disasm.rs index ade724e..219e6e4 100644 --- a/src/disasm.rs +++ b/src/disasm.rs @@ -8,7 +8,7 @@ use crate::{ Args, instructions::{Instruction, Mnemonic}, }; -use crate::{modrmb, modrmgpr1b, modrmgpr1v, modrms, modrmv}; +use crate::{modrmb, modrms, modrmv}; #[derive(Debug)] /// Generic errors, which are encountered during parsing. @@ -204,9 +204,10 @@ impl Disassembler { } /// Match the modrm reg bits to the GPR1 mnemonics. - /// GPR always has an imm value as second operand, but is available in both - /// Byte and Word length. - pub fn modrm_reg_to_mnemonic(reg: u8, target: ModRmTarget, imm: Operand) -> Mnemonic { + /// Group 1 always have an ModRM target (all modrm bits, without reg) as + /// first and an imm value as second operand (which has to be parsed before + /// 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 { Operand::Byte(b) => match reg { 0b000 => Mnemonic::ADD_Ib(target, b), @@ -217,7 +218,7 @@ impl Disassembler { 0b101 => Mnemonic::SUB_Ib(target, b), 0b110 => Mnemonic::XOR_Ib(target, b), 0b111 => Mnemonic::CMP_Ib(target, b), - _ => panic!("Illegal GPR1 mnemonic"), + _ => panic!("Illegal Group 1 mnemonic"), }, Operand::Word(w) => match reg { 0b000 => Mnemonic::ADD_Iv(target, w), @@ -228,11 +229,31 @@ impl Disassembler { 0b101 => Mnemonic::SUB_Iv(target, w), 0b110 => Mnemonic::XOR_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 pub fn decode_instructions(&mut self) -> Result, DisasmError> { // naive approach: @@ -388,9 +409,22 @@ impl Disassembler { 0x7F => Mnemonic::JG(self.parse_byte()), // Group 1 - 0x80 => modrmgpr1b!(self), - 0x81 => modrmgpr1v!(self), - 0x82 => modrmgpr1b!(self), // same as 0x80 + 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)) + } + 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"), 0x84 => modrmb!(self, TEST), @@ -490,6 +524,15 @@ impl Disassembler { 0xCD => Mnemonic::INT(self.parse_byte()), // 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!("Offset might be misaligned and data is being interpreted."); diff --git a/src/disasm_macros.rs b/src/disasm_macros.rs index fd4a60a..00c62bd 100644 --- a/src/disasm_macros.rs +++ b/src/disasm_macros.rs @@ -24,27 +24,3 @@ macro_rules! modrms { 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)) - }}; -} diff --git a/src/instructions.rs b/src/instructions.rs index ac4fd50..04ed1ee 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -160,6 +160,8 @@ pub enum Mnemonic { JG(Byte), // TEST TEST(ModRmTarget, Register), + TEST_Ib(ModRmTarget, Byte), + TEST_Iv(ModRmTarget, Word), TEST_ALIb(Byte), TEST_AXIv(Word), //XHCG @@ -222,6 +224,16 @@ pub enum Mnemonic { // Load ES/DS Register LES(ModRmTarget), LDS(ModRmTarget), + // NOT + NOT(ModRmTarget), + // NEG + NEG(ModRmTarget), + // MUL + MUL(ModRmTarget), + IMUL(ModRmTarget), + // DIV + DIV(ModRmTarget), + IDIV(ModRmTarget), // INT INT(Byte), }