From 2eebbc76c7185a21bc22e7b78db0e6cbc4bd3de2 Mon Sep 17 00:00:00 2001 From: iximeow Date: Thu, 30 Jul 2020 03:15:55 -0700 Subject: sse4.2 tests and missing instructions --- src/long_mode/display.rs | 2 ++ src/long_mode/mod.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++-- test/long_mode/mod.rs | 37 +++++++++++++++++++++++++++++ 3 files changed, 97 insertions(+), 2 deletions(-) diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 694bc75..17f2c86 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -1138,6 +1138,7 @@ const MNEMONICS: &[&'static str] = &[ "rdgsbase", "wrfsbase", "wrgsbase", + "crc32", ]; impl Opcode { @@ -1989,6 +1990,7 @@ impl > Colorize { write!(out, "{}", colors.platform_op(self)) } + Opcode::CRC32 | Opcode::RDSEED | Opcode::RDRAND | Opcode::SHA1RNDS4 | diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 7deab18..065d1ae 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -1433,6 +1433,8 @@ pub enum Opcode { RDGSBASE, WRFSBASE, WRGSBASE, + + CRC32, } #[derive(Debug)] @@ -2338,6 +2340,7 @@ impl InstDecoder { return Err(DecodeError::InvalidOpcode); } } + Opcode::CRC32 | Opcode::PCMPESTRI | Opcode::PCMPESTRM | Opcode::PCMPISTRI | @@ -3419,11 +3422,11 @@ pub enum OperandCode { ModRM_0x0f0d = OperandCodeBuilder::new().read_modrm().special_case(2).bits(), ModRM_0x0fae = OperandCodeBuilder::new().read_modrm().special_case(3).bits(), ModRM_0x0fba = OperandCodeBuilder::new().read_modrm().special_case(4).bits(), - ModRM_0xf238 = OperandCodeBuilder::new().read_modrm().special_case(5).bits(), ModRM_0xf30fae = OperandCodeBuilder::new().read_modrm().special_case(6).bits(), ModRM_0x660fae = OperandCodeBuilder::new().read_modrm().special_case(7).bits(), ModRM_0xf30fc7 = OperandCodeBuilder::new().read_modrm().special_case(8).bits(), ModRM_0x660f38 = OperandCodeBuilder::new().read_modrm().special_case(9).bits(), + ModRM_0xf20f38 = OperandCodeBuilder::new().read_modrm().special_case(24).bits(), ModRM_0xf30f38 = OperandCodeBuilder::new().read_modrm().special_case(10).bits(), ModRM_0x660f3a = OperandCodeBuilder::new().read_modrm().special_case(11).bits(), ModRM_0x0f38 = OperandCodeBuilder::new().read_modrm().special_case(12).bits(), @@ -3617,6 +3620,7 @@ pub enum OperandCode { Gv_Ew = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(5).bits(), Gv_Ew_LSL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(7).bits(), Gdq_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(6).bits(), + Gdq_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(10).bits(), G_E_mm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(2).bits(), G_E_xmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(8).bits(), AL_Ob = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(0).bits(), @@ -4029,7 +4033,7 @@ const OPCODE_F20F_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::ModRM_0xf238), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf20f38), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -5958,6 +5962,24 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present()); instruction.operand_count = 2; }, + OperandCode::Gdq_Ev => { + let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); + let modrm = read_modrm(&mut bytes_iter, length)?; + +// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); + instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; + // `opwidth` can be 2, 4, or 8 here. if opwidth is 2, the first operand is a dword. + // if opwidth is 4, both registers are dwords. and if opwidth is 8, both registers are + // qword. + let regwidth = if opwidth == 2 { + 4 + } else { + opwidth + }; + instruction.modrm_rrr = + RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex().r(), regwidth, instruction.prefixes.rex().present()); + instruction.operand_count = 2; + }, OperandCode::Ev => { instruction.operands[0] = mem_oper; instruction.operand_count = 1; @@ -6474,6 +6496,23 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?; instruction.operand_count = 2; } + OperandCode::ModRM_0xf20f38 => { + let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?; + match op { + 0xf0 => { + instruction.opcode = Opcode::CRC32; + return read_operands(decoder, bytes_iter, instruction, OperandCode::Gv_Eb, length); + } + 0xf1 => { + instruction.opcode = Opcode::CRC32; + return read_operands(decoder, bytes_iter, instruction, OperandCode::Gdq_Ev, length); + } + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + }; + } OperandCode::ModRM_0xf30f38 => { let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?; match op { @@ -6535,6 +6574,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 0x34 => { instruction.opcode = Opcode::PMOVZXWQ; } 0x35 => { instruction.opcode = Opcode::PMOVZXDQ; } + 0x37 => { instruction.opcode = Opcode::PCMPGTQ; } 0x38 => { instruction.opcode = Opcode::PMINSB; } 0x39 => { instruction.opcode = Opcode::PMINSD; } 0x3a => { instruction.opcode = Opcode::PMINUW; } @@ -6644,6 +6684,22 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); } + 0x60 => { + instruction.opcode = Opcode::PCMPESTRM; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x61 => { + instruction.opcode = Opcode::PCMPESTRI; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x62 => { + instruction.opcode = Opcode::PCMPISTRM; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x63 => { + instruction.opcode = Opcode::PCMPISTRI; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } 0xcc => { instruction.opcode = Opcode::SHA1RNDS4; diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 9ce4019..a9a894a 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -586,6 +586,41 @@ fn test_sse3() { } #[test] +fn test_sse4_2() { + fn test_instr(bytes: &[u8], text: &'static str) { + test_display_under(&InstDecoder::minimal().with_sse4_2(), 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); + } + + #[allow(unused)] + fn test_instr_invalid(bytes: &[u8]) { + test_invalid_under(&InstDecoder::minimal().with_sse4_2(), bytes); + test_invalid_under(&InstDecoder::default(), bytes); + } + + test_instr(&[0x66, 0x0f, 0x38, 0x37, 0x03], "pcmpgtq xmm0, [rbx]"); + test_instr(&[0x66, 0x0f, 0x38, 0x37, 0xc3], "pcmpgtq xmm0, xmm3"); + + test_instr(&[0xf2, 0x0f, 0x38, 0xf0, 0x06], "crc32 eax, [rsi]"); + test_instr(&[0xf2, 0x0f, 0x38, 0xf0, 0xc6], "crc32 eax, dh"); + test_instr(&[0xf2, 0x0f, 0x38, 0xf1, 0x06], "crc32 eax, [rsi]"); + test_instr(&[0xf2, 0x0f, 0x38, 0xf1, 0xc6], "crc32 eax, esi"); + test_instr(&[0x66, 0xf2, 0x0f, 0x38, 0xf1, 0xc6], "crc32 eax, si"); + test_instr(&[0x66, 0xf2, 0x48, 0x0f, 0x38, 0xf1, 0xc6], "crc32 rax, rsi"); + + test_instr(&[0x66, 0x0f, 0x3a, 0x60, 0xc6, 0x54], "pcmpestrm xmm0, xmm6, 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x60, 0x06, 0x54], "pcmpestrm xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x61, 0xc6, 0x54], "pcmpestri xmm0, xmm6, 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x61, 0x06, 0x54], "pcmpestri xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x62, 0xc6, 0x54], "pcmpistrm xmm0, xmm6, 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x62, 0x06, 0x54], "pcmpistrm xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x63, 0xc6, 0x54], "pcmpistri xmm0, xmm6, 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x63, 0x06, 0x54], "pcmpistri xmm0, [rsi], 0x54"); +} + +#[test] fn test_sse4_1() { fn test_instr(bytes: &[u8], text: &'static str) { test_display_under(&InstDecoder::minimal().with_sse4_1(), bytes, text); @@ -690,6 +725,8 @@ fn test_sse4_1() { test_instr(&[0x66, 0x0f, 0x3a, 0x14, 0x06, 0x31], "pextrb xmm0, [rsi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x14, 0x06]); + test_instr(&[0x66, 0x0f, 0x3a, 0x15, 0x06, 0x31], "pextrw xmm0, [rsi], 0x31"); + test_invalid(&[0x0f, 0x3a, 0x15, 0x06]); test_instr(&[0x66, 0x0f, 0x3a, 0x16, 0x06, 0x31], "pextrd xmm0, [rsi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x16, 0x06]); test_instr(&[0x66, 0x48, 0x0f, 0x3a, 0x16, 0x06, 0x31], "pextrq xmm0, [rsi], 0x31"); -- cgit v1.1