ft: implement group3a/b instructions
This commit is contained in:
@@ -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.");
|
||||||
|
|||||||
@@ -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))
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user