From d8efc7b6fca3e1c6a9ebf0ada6759a927c12558f Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 5 Jan 2019 15:26:46 -0800 Subject: add more test cases, fix movzx support, add 0xf6 opcodes --- src/lib.rs | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- test/test.rs | 7 ++- 2 files changed, 142 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 1a8a5fc..6b33cdc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -224,6 +224,9 @@ impl fmt::Display for Opcode { &Opcode::DIV => write!(f, "{}", "div"), &Opcode::IDIV => write!(f, "{}", "idiv"), &Opcode::CMPXCHG => write!(f, "{}", "cmpxchg"), + &Opcode::MOVZX_b => write!(f, "{}", "movzx"), + &Opcode::MOVZX_w => write!(f, "{}", "movzx"), + &Opcode::MOVSX => write!(f, "{}", "movsx"), &Opcode::Invalid => write!(f, "{}", "invalid") } } @@ -231,6 +234,9 @@ impl fmt::Display for Opcode { #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Opcode { + MOVZX_b, + MOVZX_w, + MOVSX, SAR, SAL, SHR, @@ -427,12 +433,42 @@ impl fmt::Display for Instruction { write!(f, " {}", x) } }; - match &self.operands[1] { - &Operand::Nothing => { - return Ok(()); + match self.opcode { + Opcode::MOVZX_b => { + match &self.operands[1] { + &Operand::Nothing => { + return Ok(()); + }, + x @ &Operand::Register(_) => { + write!(f, ", {}", x) + } + x @ _ => { + write!(f, ", byte {}", x) + } + } }, - x @ &_ => { - write!(f, ", {}", x) + Opcode::MOVZX_w => { + match &self.operands[1] { + &Operand::Nothing => { + return Ok(()); + }, + x @ &Operand::Register(_) => { + write!(f, ", {}", x) + } + x @ _ => { + write!(f, ", word {}", x) + } + } + }, + _ => { + match &self.operands[1] { + &Operand::Nothing => { + return Ok(()); + }, + x @ &_ => { + write!(f, ", {}", x) + } + } } } } @@ -440,6 +476,7 @@ impl fmt::Display for Instruction { #[derive(Copy, Clone, Debug)] pub enum OperandCode { + ModRM_0xf6, ModRM_0xf7, Gv_Ev_Iv, Gb_Eb_Ib, @@ -478,6 +515,8 @@ pub enum OperandCode { Ew_Sw, Fw, Gb_Eb, + Gv_Eb, + Gv_Ew, Gv_Ev, Gv_M, I_3, @@ -704,6 +743,16 @@ fn read_opcode_0f_map(bytes_iter: &mut Iterator, instruction: &mut Ins instruction.opcode = Opcode::CMPXCHG; Ok(OperandCode::Ev_Gv) } + 0xb6 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::MOVZX_b; + Ok(OperandCode::Gv_Eb) + }, + 0xb7 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::MOVZX_w; + Ok(OperandCode::Gv_Ew) + } _ => { Err(format!("Unknown opcode: 0f{:x}", b)) } @@ -1192,7 +1241,11 @@ fn read_opcode(bytes_iter: &mut Iterator, instruction: &mut Instructio instruction.opcode = Opcode::HLT; return Ok(OperandCode::Nothing); }, - 0xf6 => { }, + 0xf6 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::Invalid; + return Ok(OperandCode::ModRM_0xf6); + }, 0xf7 => { instruction.prefixes = prefixes; instruction.opcode = Opcode::Invalid; @@ -1581,6 +1634,48 @@ fn read_operands( Err(reason) => Err(reason) } }, + OperandCode::ModRM_0xf6 => { + let opwidth = 1; + let modrm = bytes_iter.next().unwrap(); + let (mod_bits, r, m) = octets_of(*modrm); + match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0]) { + Ok(()) => { }, + Err(reason) => { return Err(reason); } + }; + match r { + 0 | 1 => { + instruction.opcode = Opcode::TEST; + match read_imm_signed(bytes_iter, 1, opwidth) { + Ok(imm) => { + instruction.operands[1] = imm; + }, + Err(reason) => { return Err(reason); } + } + }, + 2 => { + instruction.opcode = Opcode::NOT; + }, + 3 => { + instruction.opcode = Opcode::NEG; + }, + 4 => { + instruction.opcode = Opcode::MUL; + }, + 5 => { + instruction.opcode = Opcode::IMUL; + }, + 6 => { + instruction.opcode = Opcode::DIV; + }, + 7 => { + instruction.opcode = Opcode::IDIV; + }, + _ => { + unsafe { unreachable_unchecked(); } + } + } + Ok(()) + }, OperandCode::ModRM_0xf7 => { let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); let modrm = bytes_iter.next().unwrap(); @@ -1743,6 +1838,42 @@ fn read_operands( Err(reason) => Err(reason) } }, + OperandCode::Gv_Eb => { + let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); + // TODO: ... + let modrm = bytes_iter.next().unwrap(); + let (mod_bits, r, m) = octets_of(*modrm); + + match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1]) { + Ok(()) => { + instruction.operands[0] = + Operand::Register(RegSpec { + num: r, + bank: width_to_gp_reg_bank(opwidth) + }); + Ok(()) + }, + Err(reason) => Err(reason) + } + }, + OperandCode::Gv_Ew => { + let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); + // TODO: ... + let modrm = bytes_iter.next().unwrap(); + let (mod_bits, r, m) = octets_of(*modrm); + + match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, 2, &mut instruction.operands[1]) { + Ok(()) => { + instruction.operands[0] = + Operand::Register(RegSpec { + num: r + if instruction.prefixes.rex().b() { 0b1000 } else { 0 }, + bank: width_to_gp_reg_bank(opwidth) + }); + Ok(()) + }, + Err(reason) => Err(reason) + } + }, // TODO: verify M OperandCode::Gv_Ev | OperandCode::Gv_M => { let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); diff --git a/test/test.rs b/test/test.rs index c4133e6..83f24f9 100644 --- a/test/test.rs +++ b/test/test.rs @@ -22,7 +22,7 @@ fn test_mov() { &[0x48, 0x89, 0x43, 0x18] ).unwrap()), "mov [rbx + 0x18], rax"); assert_eq!(&format!("{}", decode( - &[0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00] + &[0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00] ).unwrap()), "mov [rbx + 0x10], 0x0"); assert_eq!(&format!("{}", decode( &[0x49, 0x89, 0x4e, 0x08] @@ -35,10 +35,13 @@ fn test_mov() { ).unwrap()), "mov [r14 + 0x10], rax"); assert_eq!(&format!("{}", decode( &[0x4d, 0x0f, 0x43, 0xec, 0x49] - ).unwrap()), "cmovae r13, r12"); + ).unwrap()), "cmovnb r13, r12"); assert_eq!(&format!("{}", decode( &[0x0f, 0xb6, 0x06] ).unwrap()), "movzx eax, byte [rsi]"); + assert_eq!(&format!("{}", decode( + &[0x0f, 0xb7, 0x06] + ).unwrap()), "movzx eax, word [rsi]"); } #[test] -- cgit v1.1