From 2f9867664191bcfe0b7f7209de7463df30f775de Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 30 Jun 2019 12:56:08 -0700 Subject: add more x86 instructions (bt, btr, bts, bsf, ...) and xadd --- src/display.rs | 26 +++++++++- src/lib.rs | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- test/test.rs | 8 +++ 3 files changed, 182 insertions(+), 5 deletions(-) diff --git a/src/display.rs b/src/display.rs index ca2b2f7..cbf3e61 100644 --- a/src/display.rs +++ b/src/display.rs @@ -183,6 +183,13 @@ impl Colorize for Operand { impl fmt::Display for Opcode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { + &Opcode::XADD => write!(f, "{}", "xadd"), + &Opcode::BT => write!(f, "{}", "bt"), + &Opcode::BTS => write!(f, "{}", "bts"), + &Opcode::BTR => write!(f, "{}", "btr"), + &Opcode::BTC => write!(f, "{}", "btc"), + &Opcode::BSF => write!(f, "{}", "bsf"), + &Opcode::BSR => write!(f, "{}", "bsr"), &Opcode::MOVSS => write!(f, "{}", "movss"), &Opcode::SQRTSS => write!(f, "{}", "sqrtss"), &Opcode::ADDSS => write!(f, "{}", "addss"), @@ -350,8 +357,11 @@ impl fmt::Display for Opcode { &Opcode::DIV => write!(f, "{}", "div"), &Opcode::IDIV => write!(f, "{}", "idiv"), &Opcode::CMPXCHG => write!(f, "{}", "cmpxchg"), + &Opcode::MOVSX_b => write!(f, "{}", "movsx"), + &Opcode::MOVSX_w => write!(f, "{}", "movsx"), &Opcode::MOVZX_b => write!(f, "{}", "movzx"), &Opcode::MOVZX_w => write!(f, "{}", "movzx"), + &Opcode::MOVSXD => write!(f, "{}", "movsxd"), &Opcode::MOVSX => write!(f, "{}", "movsx"), &Opcode::SETO => write!(f, "{}", "seto"), &Opcode::SETNO => write!(f, "{}", "setno"), @@ -387,11 +397,10 @@ impl Colorize for Opcode { Opcode::SUBSS | Opcode::MULSS | Opcode::DIVSS | - Opcode::MOVDDUP | - Opcode::MOVSLDUP | Opcode::HADDPS | Opcode::HSUBPS | Opcode::ADDSUBPS | + Opcode::XADD| Opcode::DIV | Opcode::IDIV | Opcode::MUL | @@ -415,6 +424,12 @@ impl Colorize for Opcode { Opcode::ADD | Opcode::ADC | Opcode::SUB | + Opcode::BT | + Opcode::BTS | + Opcode::BTR | + Opcode::BTC | + Opcode::BSF | + Opcode::BSR | Opcode::IMUL => { write!(out, "{}", colors.arithmetic_op(self)) } Opcode::POPF | Opcode::PUSHF | @@ -471,6 +486,8 @@ impl Colorize for Opcode { Opcode::STC | Opcode::STI | Opcode::STD | + Opcode::MOVDDUP | + Opcode::MOVSLDUP | Opcode::MOV | Opcode::MOVSD | Opcode::CBW | @@ -482,9 +499,12 @@ impl Colorize for Opcode { Opcode::MOVS | Opcode::INS | Opcode::OUTS | + Opcode::MOVSX_b | + Opcode::MOVSX_w | Opcode::MOVZX_b | Opcode::MOVZX_w | Opcode::MOVSX | + Opcode::MOVSXD | Opcode::XCHG | Opcode::CMOVA | Opcode::CMOVB | @@ -627,6 +647,7 @@ impl ShowContextual], T> for Instructi } }; match self.opcode { + Opcode::MOVSX_b | Opcode::MOVZX_b => { match context.and_then(|xs| xs[1].as_ref()) { Some(s) => { write!(out, ", {}", s) } @@ -653,6 +674,7 @@ impl ShowContextual], T> for Instructi } } }, + Opcode::MOVSX_w | Opcode::MOVZX_w => { match context.and_then(|xs| xs[1].as_ref()) { Some(s) => { write!(out, ", {}", s) } diff --git a/src/lib.rs b/src/lib.rs index 95e727a..7dcfb5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -236,6 +236,13 @@ pub enum Segment { #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Opcode { + XADD, + BT, + BTS, + BTC, + BTR, + BSF, + BSR, MOVSS, ADDSS, SUBSS, @@ -266,9 +273,12 @@ pub enum Opcode { CVTSS2SI, CVTSS2SD, LDDQU, + MOVSX_b, + MOVSX_w, MOVZX_b, MOVZX_w, MOVSX, + MOVSXD, SAR, SAL, SHR, @@ -654,6 +664,7 @@ pub enum OperandCode { ModRM_0x0f00, ModRM_0x0f01, ModRM_0x0fae, + ModRM_0x0fba, Rq_Cq_0, Rq_Dq_0, Cq_Rq_0, @@ -703,6 +714,7 @@ pub enum OperandCode { Gb_Eb, Gv_Eb, Gv_Ew, + Gv_Ed, Gv_Ev, G_E_xmm, Gv_M, @@ -1013,6 +1025,11 @@ fn read_opcode_0f_map>(bytes_iter: &mut T, instruction: &mu instruction.opcode = Opcode::UD2; Ok(OperandCode::Nothing) } + 0x0d => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::NOP; + Ok(OperandCode::Ev) + } 0x1f => { instruction.prefixes = prefixes; instruction.opcode = Opcode::NOP; @@ -1255,6 +1272,11 @@ fn read_opcode_0f_map>(bytes_iter: &mut T, instruction: &mu instruction.opcode = Opcode::CPUID; Ok(OperandCode::Nothing) } + 0xa3 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::BT; + Ok(OperandCode::Gv_Ev) + } 0xa8 => { instruction.prefixes = prefixes; instruction.opcode = Opcode::PUSH; @@ -1269,6 +1291,11 @@ fn read_opcode_0f_map>(bytes_iter: &mut T, instruction: &mu instruction.prefixes = prefixes; Ok(OperandCode::ModRM_0x0fae) } + 0xaf => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::IMUL; + Ok(OperandCode::Gv_Ev) + } 0xb0 => { instruction.prefixes = prefixes; instruction.opcode = Opcode::CMPXCHG; @@ -1289,6 +1316,45 @@ fn read_opcode_0f_map>(bytes_iter: &mut T, instruction: &mu instruction.opcode = Opcode::MOVZX_w; Ok(OperandCode::Gv_Ew) } + 0xba => { + instruction.prefixes = prefixes; + Ok(OperandCode::ModRM_0x0fba) + } + 0xbb => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::BTC; + Ok(OperandCode::Gv_Ev) + } + 0xbc => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::BSF; + Ok(OperandCode::Gv_Ev) + } + 0xbd => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::BSR; + Ok(OperandCode::Gv_Ev) + } + 0xbe => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::MOVSX_b; + Ok(OperandCode::Gv_Eb) + } + 0xbf => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::MOVSX_w; + Ok(OperandCode::Gv_Ew) + } + 0xc0 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::XADD; + Ok(OperandCode::Eb_Gb) + } + 0xc1 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::XADD; + Ok(OperandCode::Ev_Gv) + } _ => { Err(format!("Unknown opcode: 0f{:x}", b)) } @@ -1391,6 +1457,11 @@ fn read_opcode>(bytes_iter: &mut T, instruction: &mut Instr instruction.opcode = op; return Ok(OperandCode::Zv(x)); }, + 0x63 => { + instruction.prefixes = prefixes; + instruction.opcode = Opcode::MOVSXD; + return Ok(OperandCode::Gv_Ed); + }, 0x64 => { prefixes.set_fs(); alternate_opcode_map = None; @@ -1577,12 +1648,12 @@ fn read_opcode>(bytes_iter: &mut T, instruction: &mut Instr 0x9c => { instruction.prefixes = prefixes; instruction.opcode = Opcode::PUSHF; - return Ok(OperandCode::Fw); + return Ok(OperandCode::Nothing); }, 0x9d => { instruction.prefixes = prefixes; instruction.opcode = Opcode::POPF; - return Ok(OperandCode::Fw); + return Ok(OperandCode::Nothing); }, 0x9e => { instruction.prefixes = prefixes; @@ -1768,6 +1839,20 @@ fn read_opcode>(bytes_iter: &mut T, instruction: &mut Instr instruction.opcode = Opcode::Invalid; return Ok(operand); }, + 0xdc => { + // TODO: WRONG + // x87 instructions + instruction.opcode = Opcode::NOP; + let _ = read_imm_unsigned(bytes_iter, 2, length)?; + return Ok(OperandCode::Nothing); + } + 0xdd => { + // x87 instructions + // TODO: WRONG + instruction.opcode = Opcode::NOP; + let _ = read_imm_unsigned(bytes_iter, 2, length)?; + return Ok(OperandCode::Nothing); + } // TODO: GAP 0xe8 => { instruction.prefixes = prefixes; @@ -2631,6 +2716,26 @@ fn read_operands>( } }, // TODO: verify M + OperandCode::Gv_Ed => { + let opwidth = 4; + // TODO: ... + let modrm = match bytes_iter.next() { + Some(b) => b, + None => return Err("Out of bytes".to_string()) + }; + *length += 1; + let (mod_bits, r, m) = octets_of(modrm); + +// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); + match read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[1], length) { + Ok(()) => { + instruction.operands[0] = + Operand::Register(RegSpec::gp_from_parts(r, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present())); + Ok(()) + }, + Err(reason) => Err(reason) + } + }, OperandCode::Gv_Ev | OperandCode::Gv_M => { let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, &instruction.prefixes); // TODO: ... @@ -2947,7 +3052,8 @@ fn read_operands>( instruction.operands = [Operand::Nothing, Operand::Nothing]; Ok(()) } else { - panic!("Unsupported instruction: 0x0f01 with modrm: 11 110 r >= 2"); + // panic!("Unsupported instruction: 0x0f01 with modrm: 11 110 r >= 2"); + Err("unsupported 0x0f01 variant".to_string()) } } else { instruction.opcode = Opcode::INVLPG; @@ -3049,6 +3155,47 @@ fn read_operands>( _ => { unreachable!("r < 6"); } } } + OperandCode::ModRM_0x0fba => { + let opwidth = imm_width_from_prefixes_64(SizeCode::vq, &instruction.prefixes); + let modrm = match bytes_iter.next() { + Some(b) => b, + None => return Err("Out of bytes".to_string()) + }; + *length += 1; + let (mod_bits, r, m) = octets_of(modrm); + match r { + 0 | 1 | 2 | 3 => { + instruction.opcode = Opcode::Invalid; + return Err("invalid instruction".to_string()); + }, + 4 => { + instruction.opcode = Opcode::BT; + } + 5 => { + instruction.opcode = Opcode::BTS; + } + 6 => { + instruction.opcode = Opcode::BTR; + } + 7 => { + instruction.opcode = Opcode::BTC; + } + _ => { + unreachable!("r < 8"); + } + } + + read_E(bytes_iter, &instruction.prefixes, m, mod_bits, opwidth, &mut instruction.operands[0], length)?; + + match read_imm_signed(bytes_iter, 1, 1, length) { + Ok(op) => { + instruction.operands[1] = op; + Ok(()) + }, + Err(reason) => Err(reason) + } + } + OperandCode::Rq_Cq_0 => { let modrm = match bytes_iter.next() { Some(b) => b, diff --git a/test/test.rs b/test/test.rs index 3a7aee9..5d5f3b0 100644 --- a/test/test.rs +++ b/test/test.rs @@ -98,6 +98,7 @@ fn test_mov() { test_display(&[0x0f, 0xb7, 0x06], "movzx eax, word [rsi]"); test_display(&[0x89, 0x55, 0x94], "mov [rbp - 0x6c], edx"); test_display(&[0x65, 0x4c, 0x89, 0x04, 0x25, 0xa8, 0x01, 0x00, 0x00], "mov gs:[0x1a8], r8"); + test_display(&[0x0f, 0xbe, 0x83, 0xb4, 0x00, 0x00, 0x00], "movsx eax, byte [rbx + 0xb4]"); test_display(&[0x48, 0x63, 0x04, 0xba], "movsxd rax, [rdx + rdi * 4]"); } @@ -146,7 +147,14 @@ fn test_push_pop() { } #[test] +fn test_bitwise() { + test_display(&[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d"); + test_display(&[0x48, 0x0f, 0xa3, 0xd0], "bt rax, rdx"); +} + +#[test] fn test_misc() { + test_display(&[0x9c], "pushf"); test_display(&[0x48, 0x98], "cdqe"); test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop cs:[rax + rax]"); test_display(&[0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00], "nop cs:[rax + rax]"); -- cgit v1.1