diff options
| -rw-r--r-- | src/lib.rs | 32 | ||||
| -rw-r--r-- | test/test.rs | 67 | 
2 files changed, 83 insertions, 16 deletions
@@ -2433,7 +2433,6 @@ pub enum OperandCode {      Gv_Eb = 0x60,      Gv_Ew = 0x61,      Gdq_Ed = 0x62, -    G_E_xmm = 0x63,      G_E_mm_Ib = 0x64,      G_E_xmm_Ib = 0x65,      AL_Ib = 0x66, @@ -2490,6 +2489,8 @@ pub enum OperandCode {      G_U_mm = 0xf1,      Ev_Gv_Ib = 0xf3,      Ev_Gv_CL = 0xf5, +    G_M_xmm = 0xf7, +    G_E_xmm = 0xf9,  }  fn base_opcode_map(v: u8) -> Opcode { @@ -2649,8 +2650,8 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::HADDPD), OperandCode::G_E_xmm), +    OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPD), OperandCode::G_E_xmm),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0x80 @@ -2739,7 +2740,7 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0xd0 -    OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), +    OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPD), OperandCode::G_E_xmm),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -3054,7 +3055,7 @@ const OPCODE_F20F_MAP: [OpcodeRecord; 256] = [      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),  // 0xf0 -    OpcodeRecord(Interpretation::Instruction(Opcode::LDDQU), OperandCode::G_E_xmm), +    OpcodeRecord(Interpretation::Instruction(Opcode::LDDQU), OperandCode::G_M_xmm),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),      OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -4758,16 +4759,21 @@ pub fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter              instruction.modrm_mmm.num &= 0b111;              instruction.operand_count = 2;          }, -        OperandCode::G_E_xmm => { -            let modrm = read_modrm(&mut bytes_iter, instruction, length)?; -            bytes_read = 1; - -//                println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); -            instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?; -            instruction.modrm_rrr = -                RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); +        op @ OperandCode::G_M_xmm | +        op @ OperandCode::G_E_xmm => { +            instruction.modrm_rrr.bank = RegisterBank::X;              instruction.operands[0] = OperandSpec::RegRRR; +            instruction.operands[1] = mem_oper;              instruction.operand_count = 2; +            if instruction.operands[1] == OperandSpec::RegMMM { +                if op == OperandCode::G_M_xmm { +                    instruction.opcode = Opcode::Invalid; +                    return Err(()); +                } else { +                    // fix the register to XMM +                    instruction.modrm_mmm.bank = RegisterBank::X; +                } +            }          },          OperandCode::G_E_mm_Ib => {              let modrm = read_modrm(&mut bytes_iter, instruction, length)?; diff --git a/test/test.rs b/test/test.rs index b8c14a7..e2c52fe 100644 --- a/test/test.rs +++ b/test/test.rs @@ -28,7 +28,7 @@ fn test_invalid(data: &[u8]) {  fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) {      if let Some(inst) = decoder.decode(data.into_iter().cloned()) { -        assert_eq!(inst.opcode, yaxpeax_x86::Opcode::Invalid); +        assert_eq!(inst.opcode, yaxpeax_x86::Opcode::Invalid, "decoded {:?} from {:02x?} under decoder {}", inst.opcode, data, decoder);      } else {          // this is fine      } @@ -48,15 +48,16 @@ fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str              let text = format!("{}", instr);              assert!(                  text == expected, -                "display error for {}:\n  decoded: {:?}\n displayed: {}\n expected: {}\n", +                "display error for {}:\n  decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n",                  hex,                  instr, +                decoder,                  text,                  expected              );          },          None => { -            assert!(false, "decode error for {}:\n  expected: {}\n", hex, expected); +            assert!(false, "decode error for {} under decoder {}:\n  expected: {}\n", hex, decoder, expected);          }      }  } @@ -97,6 +98,66 @@ fn test_cvt() {  }  #[test] +fn test_sse3() { +    fn test_instr(bytes: &[u8], text: &'static str) { +        test_display_under(&InstDecoder::minimal().with_sse3(), bytes, text); +        test_invalid_under(&InstDecoder::minimal(), bytes); +        // avx doesn't imply older instructions are necessarily valid +        test_invalid_under(&InstDecoder::minimal().with_avx(), bytes); +        // sse4 doesn't imply older instructions are necessarily valid +        test_invalid_under(&InstDecoder::minimal().with_sse4_1(), bytes); +        test_invalid_under(&InstDecoder::minimal().with_sse4_2(), bytes); +    } + +    fn test_instr_invalid(bytes: &[u8]) { +        test_invalid_under(&InstDecoder::minimal().with_sse3(), bytes); +        test_invalid_under(&InstDecoder::default(), bytes); +    } + +    test_instr(&[0xf2, 0x0f, 0xf0, 0x0f], "lddqu xmm1, [rdi]"); +    test_instr_invalid(&[0xf2, 0x0f, 0xf0, 0xcf]); +    test_instr(&[0xf2, 0x0f, 0xd0, 0x0f], "addsubps xmm1, [rdi]"); +    test_instr(&[0xf2, 0x0f, 0xd0, 0xcf], "addsubps xmm1, xmm7"); +    test_instr(&[0xf2, 0x4f, 0x0f, 0xd0, 0xcf], "addsubps xmm9, xmm15"); +    test_instr(&[0x66, 0x0f, 0xd0, 0x0f], "addsubpd xmm1, [rdi]"); +    test_instr(&[0x66, 0x0f, 0xd0, 0xcf], "addsubpd xmm1, xmm7"); +    test_instr(&[0x66, 0x4f, 0x0f, 0xd0, 0xcf], "addsubpd xmm9, xmm15"); + +    test_instr(&[0xf2, 0x0f, 0x7c, 0x0f], "haddps xmm1, [rdi]"); +    test_instr(&[0xf2, 0x0f, 0x7c, 0xcf], "haddps xmm1, xmm7"); +    test_instr(&[0xf2, 0x4f, 0x0f, 0x7c, 0xcf], "haddps xmm9, xmm15"); +    test_instr(&[0x66, 0x0f, 0x7c, 0x0f], "haddpd xmm1, [rdi]"); +    test_instr(&[0x66, 0x0f, 0x7c, 0xcf], "haddpd xmm1, xmm7"); +    test_instr(&[0x66, 0x4f, 0x0f, 0x7c, 0xcf], "haddpd xmm9, xmm15"); + +    test_instr(&[0xf2, 0x0f, 0x7d, 0x0f], "hsubps xmm1, [rdi]"); +    test_instr(&[0xf2, 0x0f, 0x7d, 0xcf], "hsubps xmm1, xmm7"); +    test_instr(&[0xf2, 0x4f, 0x0f, 0x7d, 0xcf], "hsubps xmm9, xmm15"); +    test_instr(&[0x66, 0x0f, 0x7d, 0x0f], "hsubpd xmm1, [rdi]"); +    test_instr(&[0x66, 0x0f, 0x7d, 0xcf], "hsubpd xmm1, xmm7"); +    test_instr(&[0x66, 0x4f, 0x0f, 0x7d, 0xcf], "hsubpd xmm9, xmm15"); + +    test_instr(&[0xf3, 0x0f, 0x12, 0x0f], "movsldup xmm1, [rdi]"); +    test_instr(&[0xf3, 0x0f, 0x12, 0xcf], "movsldup xmm1, xmm7"); +    test_instr(&[0xf3, 0x4f, 0x0f, 0x12, 0xcf], "movsldup xmm9, xmm15"); +    test_instr(&[0xf3, 0x0f, 0x16, 0x0f], "movshdup xmm1, [rdi]"); +    test_instr(&[0xf3, 0x0f, 0x16, 0xcf], "movshdup xmm1, xmm7"); +    test_instr(&[0xf3, 0x4f, 0x0f, 0x16, 0xcf], "movshdup xmm9, xmm15"); + +    test_instr(&[0xf2, 0x0f, 0x12, 0x0f], "movddup xmm1, [rdi]"); +    test_instr(&[0xf2, 0x0f, 0x12, 0xcf], "movddup xmm1, xmm7"); +    test_instr(&[0xf2, 0x4f, 0x0f, 0x12, 0xcf], "movddup xmm9, xmm15"); + +    test_instr(&[0x66, 0x0f, 0x01, 0xc8], "monitor"); +    test_instr(&[0xf2, 0x0f, 0x01, 0xc8], "monitor"); +    test_instr(&[0xf3, 0x0f, 0x01, 0xc8], "monitor"); + +    test_instr(&[0x66, 0x0f, 0x01, 0xc9], "mwait"); +    test_instr(&[0xf2, 0x0f, 0x01, 0xc9], "mwait"); +    test_instr(&[0xf3, 0x0f, 0x01, 0xc9], "mwait"); +} + +#[test]  fn test_0f01() {      // drawn heavily from "Table A-6.  Opcode Extensions for One- and Two-byte Opcodes by Group      // Number"  | 
