diff options
| author | iximeow <me@iximeow.net> | 2021-08-21 14:03:08 -0700 | 
|---|---|---|
| committer | iximeow <me@iximeow.net> | 2021-08-21 14:03:08 -0700 | 
| commit | d7208834963c46a6da74a3837d9e82bad33dfd7f (patch) | |
| tree | 6df2525647cc29b719ce1db376d271b801c47371 | |
| parent | e4131e4eb64595d9b24493eb31a9af4c5e21b1eb (diff) | |
fix incorrect decoding of 0x9*-series instructions with rex.b
| -rw-r--r-- | CHANGELOG | 2 | ||||
| -rw-r--r-- | src/long_mode/mod.rs | 14 | ||||
| -rw-r--r-- | test/long_mode/mod.rs | 4 | 
3 files changed, 16 insertions, 4 deletions
@@ -14,6 +14,8 @@      the *read*, not the corresponding write of pushing `{e}ip` to the stack.      documentation has been added to `mem_size` more specifically describing      this circumstance. +* correct `rex.b` incorrectly applying to the `*ax` register - `4f91` is `xchg rax, r9`, not `xchg r8, r9`. +* correct `nop` incorrectly ignoring `rex.b` - `4190` is `xchg rax, r8`, not `nop`.  ## 1.0.4 diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index a01e854..22b6a99 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -5118,7 +5118,7 @@ enum OperandCode {      Zv_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 5).bits(),      Zv_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 6).bits(),      Zv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 7).bits(), -    // Zv_AX_R0 = 0x48, +    Zv_AX_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 0).bits(),      Zv_AX_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 1).bits(),      Zv_AX_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 2).bits(),      Zv_AX_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 3).bits(), @@ -5447,7 +5447,7 @@ const OPCODES: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::LEA), OperandCode::Gv_M),      OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Sw_Ew),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x8f_Ev), -    OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R0),      OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R1),      OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R2),      OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R3), @@ -7428,6 +7428,13 @@ fn read_operands<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpe                      }                      1 => {                          // Zv_AX +                        // in 64-bit mode, rex.b is able to make "nop" into an `xchg`, as in `4190` +                        // aka `xchg eax, r8d. +                        if reg == 0 && !instruction.prefixes.rex_unchecked().b() { +                            instruction.opcode = Opcode::NOP; +                            instruction.operand_count = 0; +                            return Ok(()); +                        }                          let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);                          let bank = if opwidth == 4 {                              RegisterBank::D @@ -7436,8 +7443,9 @@ fn read_operands<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpe                          } else {                              RegisterBank::Q                          }; +                        // always *ax, but size is determined by prefixes (or lack thereof)                          instruction.regs[0] = -                            RegSpec::from_parts(0, instruction.prefixes.rex_unchecked().b(), bank); +                            RegSpec::from_parts(0, false, bank);                          instruction.operands[1] = OperandSpec::RegMMM;                          instruction.regs[1] =                              RegSpec::from_parts(reg, instruction.prefixes.rex_unchecked().b(), bank); diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 61ea63d..015f1c6 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -1176,8 +1176,10 @@ fn test_mov() {  fn test_xchg() {      test_display(&[0x90], "nop");      test_display(&[0x91], "xchg eax, ecx"); -    test_display(&[0x4f, 0x91], "xchg r8, r9"); +    test_display(&[0x4f, 0x91], "xchg rax, r9");      test_display(&[0x66, 0x91], "xchg ax, cx"); +    test_display(&[0x4f, 0x90], "xchg rax, r8"); +    test_display(&[0x41, 0x90], "xchg eax, r8d");  }  #[test]  | 
