From 0c8dccaf591748e6acb9b437d69ba028e59a73cf Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 17 Mar 2021 23:45:16 -0700 Subject: support several new extensions, 3dnow, and nuance in invalid operands --- src/long_mode/display.rs | 94 +++++++++++++- src/long_mode/mod.rs | 319 ++++++++++++++++++++++++++++++++++++++++++++--- test/long_mode/mod.rs | 107 +++++++++++++++- 3 files changed, 496 insertions(+), 24 deletions(-) diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 52018da..df7237d 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -422,6 +422,8 @@ const MNEMONICS: &[&'static str] = &[ "setle", "setg", "cpuid", + "ud0", + "ud1", "ud2", "wbinvd", "invd", @@ -652,7 +654,6 @@ const MNEMONICS: &[&'static str] = &[ "sysexit", "ucomisd", "ucomiss", - "ud2e", "vmread", "vmwrite", "xorps", @@ -1212,6 +1213,50 @@ const MNEMONICS: &[&'static str] = &[ "loopz", "loop", "jrcxz", + "movdir64b", + "movdiri", + "aesdec128kl", + "aesdec256kl", + "aesdecwide128kl", + "aesdecwide256kl", + "aesenc128kl", + "aesenc256kl", + "aesencwide128kl", + "aesencwide256kl", + "encodekey128", + "encodekey256", + "loadiwkey", + + // 3dnow + "femms", + "pi2fw", + "pi2fd", + "pi2iw", + "pi2id", + "pmulhrw", + "pfcmpge", + "pfmin", + "pfrcp", + "pfrsqrt", + "pfsub", + "pfadd", + "pfcmpgt", + "pfmax", + "pfrcpit1", + "pfrsqit1", + "pfsubr", + "pfacc", + "pfcmpeq", + "pfmul", + "pfrcpit2", + "pfnacc", + "pswapd", + "pfpnacc", + "pavgusb", + + // ENQCMD + "enqcmd", + "enqcmds", ]; impl Opcode { @@ -1425,6 +1470,21 @@ impl > Colorize> Colorize { write!(out, "{}", colors.control_flow_op(self)) } /* Data transfer */ + Opcode::PI2FW | + Opcode::PI2FD | + Opcode::PF2ID | + Opcode::PF2IW | Opcode::VCVTDQ2PD | Opcode::VCVTDQ2PS | Opcode::VCVTPD2DQ | @@ -1698,6 +1762,8 @@ impl > Colorize> Colorize> Colorize> Colorize> Colorize { write!(out, "{}", colors.platform_op(self)) } Opcode::CRC32 | @@ -2180,6 +2253,17 @@ impl > Colorize> Colorize { write!(out, "{}", colors.misc_op(self)) } + Opcode::UD0 | + Opcode::UD1 | Opcode::UD2 | Opcode::Invalid => { write!(out, "{}", colors.invalid_op(self)) } } @@ -2331,7 +2417,7 @@ fn contextualize_intel>( } _ => { out.write_str(", word ")?; - if let Some(prefix) = instr.segment_override_for_op(1) { + if let Some(prefix) = instr.segment_override_for_op(i) { write!(out, "{}:", prefix)?; } } @@ -2346,7 +2432,7 @@ fn contextualize_intel>( }, _ => { out.write_str(", ")?; - if let Some(prefix) = instr.segment_override_for_op(1) { + if let Some(prefix) = instr.segment_override_for_op(i) { write!(out, "{}:", prefix)?; } let x = Operand::from_spec(instr, instr.operands[i as usize]); diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 6349aa4..15a1318 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -1071,6 +1071,8 @@ pub enum Opcode { SETLE, SETG, CPUID, + UD0, + UD1, UD2, WBINVD, INVD, @@ -1305,7 +1307,6 @@ pub enum Opcode { SYSEXIT, UCOMISD, UCOMISS, - UD2E, VMREAD, VMWRITE, XORPS, @@ -1878,6 +1879,54 @@ pub enum Opcode { LOOPZ, LOOP, JRCXZ, + + // started shipping in Tremont, 2020 sept 23 + MOVDIR64B, + MOVDIRI, + + // started shipping in Tiger Lake, 2020 sept 2 + AESDEC128KL, + AESDEC256KL, + AESDECWIDE128KL, + AESDECWIDE256KL, + AESENC128KL, + AESENC256KL, + AESENCWIDE128KL, + AESENCWIDE256KL, + ENCODEKEY128, + ENCODEKEY256, + LOADIWKEY, + + // 3dnow + FEMMS, + PI2FW, + PI2FD, + PF2IW, + PF2ID, + PMULHRW, + PFCMPGE, + PFMIN, + PFRCP, + PFRSQRT, + PFSUB, + PFADD, + PFCMPGT, + PFMAX, + PFRCPIT1, + PFRSQIT1, + PFSUBR, + PFACC, + PFCMPEQ, + PFMUL, + PFRCPIT2, + PFNACC, + PSWAPD, + PFPNACC, + PAVGUSB, + + // ENQCMD + ENQCMD, + ENQCMDS, } #[derive(Debug)] @@ -3913,6 +3962,7 @@ enum OperandCode { ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(40).bits(), ModRM_0x0f01 = OperandCodeBuilder::new().read_modrm().special_case(41).bits(), ModRM_0x0f0d = OperandCodeBuilder::new().read_modrm().special_case(42).bits(), + ModRM_0x0f0f = OperandCodeBuilder::new().read_modrm().special_case(65).bits(), // 3dnow ModRM_0x0fae = OperandCodeBuilder::new().read_modrm().special_case(43).bits(), ModRM_0x0fba = OperandCodeBuilder::new().read_modrm().special_case(44).bits(), ModRM_0xf30fae = OperandCodeBuilder::new().read_modrm().special_case(46).bits(), @@ -4121,6 +4171,7 @@ enum OperandCode { Gb_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().reg_mem().bits(), Gv_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().bits(), Gv_M = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().operand_case(25).bits(), + MOVDIR64B = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(108).bits(), Gb_Eb_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().with_imm(false, 0).byte_operands().reg_mem().operand_case(40).bits(), Gv_Ev_Iv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(41).bits(), Rv_Gmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_modrm().read_E().reg_mem().operand_case(55).bits(), @@ -5065,8 +5116,8 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), // 0x10 OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::G_E_xmm), OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::E_G_xmm), @@ -5256,7 +5307,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX_b), OperandCode::Gv_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX_w), OperandCode::Gv_Ew), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // JMPE, ITANIUM - OpcodeRecord(Interpretation::Instruction(Opcode::UD2E), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::TZCNT), OperandCode::Gv_Ev), @@ -5334,7 +5385,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_mm), OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_mm), OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_mm), - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gdq_Ed), ]; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -5493,8 +5544,8 @@ const OPCODES: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x83_Ev_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::Ev_Gv), - OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Gb_Eb), - OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Gv_Ev), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Eb_Gb), + OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gb_Eb), @@ -5975,19 +6026,18 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in } prefixes.rex_from(0); - escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map); match b { 0x26 => { - prefixes.set_es(); +// prefixes.set_es(); }, 0x2e => { - prefixes.set_cs(); +// prefixes.set_cs(); }, 0x36 => { - prefixes.set_ss(); +// prefixes.set_ss(); }, 0x3e => { - prefixes.set_ds(); +// prefixes.set_ds(); }, 0x64 => { prefixes.set_fs(); @@ -5996,6 +6046,7 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in prefixes.set_gs(); }, 0x66 => { + escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map); alternate_opcode_map = Some(OpcodeMap::Map66); }, 0x67 => { @@ -6007,9 +6058,11 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in prefixes.set_lock(); }, 0xf2 => { + escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map); alternate_opcode_map = Some(OpcodeMap::MapF2); }, 0xf3 => { + escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map); alternate_opcode_map = Some(OpcodeMap::MapF3); }, _ => { unsafe { unreachable_unchecked(); } } @@ -6833,6 +6886,110 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; instruction.operand_count = 1; } + OperandCode::ModRM_0x0f0f => { + let opcode = read_modrm(&mut bytes_iter, length)?; + match opcode { + 0x0c => { + instruction.opcode = Opcode::PI2FW; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x0d => { + instruction.opcode = Opcode::PI2FD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x1c => { + instruction.opcode = Opcode::PF2IW; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x1d => { + instruction.opcode = Opcode::PF2ID; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x59 => { + instruction.opcode = Opcode::PMULHRW; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x90 => { + instruction.opcode = Opcode::PFCMPGE; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x94 => { + instruction.opcode = Opcode::PFMIN; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x96 => { + instruction.opcode = Opcode::PFRCP; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x97 => { + instruction.opcode = Opcode::PFRSQRT; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x9a => { + instruction.opcode = Opcode::PFSUB; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0x9e => { + instruction.opcode = Opcode::PFADD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xa0 => { + instruction.opcode = Opcode::PFCMPGT; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xa4 => { + instruction.opcode = Opcode::PFMAX; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xa6 => { + instruction.opcode = Opcode::PFRCPIT1; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xa7 => { + instruction.opcode = Opcode::PFRSQIT1; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xaa => { + instruction.opcode = Opcode::PFSUBR; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xae => { + instruction.opcode = Opcode::PFACC; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xb0 => { + instruction.opcode = Opcode::PFCMPEQ; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xb4 => { + instruction.opcode = Opcode::PFMUL; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xb6 => { + instruction.opcode = Opcode::PFRCPIT2; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xba => { + instruction.opcode = Opcode::PFNACC; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xbb => { + instruction.opcode = Opcode::PSWAPD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xbe => { + instruction.opcode = Opcode::PFPNACC; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + 0xbf => { + instruction.opcode = Opcode::PAVGUSB; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm, length); + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } OperandCode::ModRM_0x0f38 => { let opcode = read_modrm(&mut bytes_iter, length)?; @@ -6861,6 +7018,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter match low { 0 => OperandCode::Gv_Ev, 1 => OperandCode::Ev_Gv, + 9 => OperandCode::M_G_xmm, _ => { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -6899,6 +7057,13 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 0xcc => Opcode::SHA256MSG1, 0xcd => Opcode::SHA256MSG2, 0xf0 | 0xf1 => Opcode::MOVBE, + 0xf9 => { + // TODO: always 32-bit mov, be careful about memory size + instruction.opcode = Opcode::MOVDIRI; + read_operands(decoder, bytes_iter, instruction, OperandCode::M_G_xmm, length)?; + instruction.modrm_rrr.bank = RegisterBank::D; + return Ok(()); + } _ => { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -6915,6 +7080,9 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } else if opcode == 0x0f { instruction.opcode = Opcode::PALIGNR; return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm_Ib, length); + } else { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); } }, OperandCode::ModRM_0x0fc7 => { @@ -7120,6 +7288,10 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = Opcode::CRC32; return read_operands(decoder, bytes_iter, instruction, OperandCode::Gdq_Ev, length); } + 0xf8 => { + instruction.opcode = Opcode::ENQCMD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::Gdq_Ev, length); + } _ => { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -7129,10 +7301,101 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter OperandCode::ModRM_0xf30f38 => { let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?; match op { + 0xd8 => { + let modrm = read_modrm(&mut bytes_iter, length)?; + let r = (modrm >> 3) & 7; + match r { + 0b000 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::AESENCWIDE128KL; + instruction.operands[0] = read_M(&mut bytes_iter, instruction, modrm, length)?; + return Ok(()); + } + 0b001 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::AESDECWIDE128KL; + instruction.operands[0] = read_M(&mut bytes_iter, instruction, modrm, length)?; + return Ok(()); + } + 0b010 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::AESENCWIDE256KL; + instruction.operands[0] = read_M(&mut bytes_iter, instruction, modrm, length)?; + return Ok(()); + } + 0b011 => { + if modrm >= 0b11_000_000 { + return Err(DecodeError::InvalidOperand); + } + instruction.opcode = Opcode::AESDECWIDE256KL; + instruction.operands[0] = read_M(&mut bytes_iter, instruction, modrm, length)?; + return Ok(()); + } + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + 0xdc => { + read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm, length)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + instruction.opcode = Opcode::LOADIWKEY; + } else { + instruction.opcode = Opcode::AESENC128KL; + } + } + 0xdd => { + read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm, length)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } else { + instruction.opcode = Opcode::AESDEC128KL; + } + } + 0xde => { + read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm, length)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } else { + instruction.opcode = Opcode::AESENC256KL; + } + } + 0xde => { + read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm, length)?; + if let OperandSpec::RegMMM = instruction.operands[1] { + return Err(DecodeError::InvalidOperand); + } else { + instruction.opcode = Opcode::AESDEC256KL; + } + } 0xf6 => { instruction.opcode = Opcode::ADOX; return read_operands(decoder, bytes_iter, instruction, OperandCode::Gv_Ev, length); } + 0xf8 => { + instruction.opcode = Opcode::ENQCMDS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::Gdq_Ev, length); + } + 0xfb => { + instruction.opcode = Opcode::ENCODEKEY128; + read_operands(decoder, bytes_iter, instruction, OperandCode::G_U_xmm, length)?; + instruction.modrm_rrr.bank = RegisterBank::D; + instruction.modrm_mmm.bank = RegisterBank::D; + return Ok(()); + } + 0xfb => { + instruction.opcode = Opcode::ENCODEKEY256; + read_operands(decoder, bytes_iter, instruction, OperandCode::G_U_xmm, length)?; + instruction.modrm_rrr.bank = RegisterBank::D; + instruction.modrm_mmm.bank = RegisterBank::D; + return Ok(()); + } _ => { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -7209,6 +7472,10 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = Opcode::ADCX; return read_operands(decoder, bytes_iter, instruction, OperandCode::Gv_Ev, length); } + 0xf8 => { + instruction.opcode = Opcode::MOVDIR64B; + return read_operands(decoder, bytes_iter, instruction, OperandCode::MOVDIR64B, length); + } _ => { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -7242,6 +7509,14 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = Opcode::ROUNDSD; return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); } + 0x0c => { + instruction.opcode = Opcode::BLENDPS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x0d => { + instruction.opcode = Opcode::BLENDPD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } 0x0e => { instruction.opcode = Opcode::PBLENDW; return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); @@ -7296,6 +7571,10 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = Opcode::MPSADBW; return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); } + 0x44 => { + instruction.opcode = Opcode::PCLMULQDQ; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } 0x60 => { instruction.opcode = Opcode::PCMPESTRM; @@ -7794,10 +8073,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } } OperandCode::ModRM_0x0f18 => { - if mem_oper == OperandSpec::RegMMM { + let rrr = instruction.modrm_rrr.num & 0b111; + // only PREFETCH* are invalid on reg operand + if mem_oper == OperandSpec::RegMMM && rrr < 4{ return Err(DecodeError::InvalidOperand); } - let rrr = instruction.modrm_rrr.num & 0b111; instruction.operands[0] = mem_oper; instruction.operand_count = 1; instruction.opcode = match rrr { @@ -8446,6 +8726,17 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter OperandCode::x87_df => { return decode_x87(decoder, bytes_iter, instruction, operand_code, length); } + OperandCode::MOVDIR64B => { + // at this point we've done a read as if it was Gv_M (`lea` operands). because the + // first operand is actually a memory address, and this is the only x86 instruction + // other than movs to have two memory operands, the first operand has to be sized by + // address-size, not operand-size. + if instruction.prefixes.address_size() { + instruction.modrm_rrr.bank = RegisterBank::D; + } else { + instruction.modrm_rrr.bank = RegisterBank::Q; + }; + } _ => { // TODO: this should be unreachable - safe to panic now? // can't simply delete this arm because the non-unlikely operands are handled outside diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs index 2fb8833..a1e8c36 100644 --- a/test/long_mode/mod.rs +++ b/test/long_mode/mod.rs @@ -134,7 +134,7 @@ fn test_mmx() { test_invalid(&[0x0f, 0xe7, 0xc3]); test_display(&[0x4f, 0x0f, 0xc3, 0x03], "movnti [r11], r8"); - test_display(&[0x66, 0x0f, 0xc3, 0x03], "movnti [rbx], eax"); + test_invalid(&[0x66, 0x0f, 0xc3, 0x03]); test_display(&[0x0f, 0xc3, 0x03], "movnti [rbx], eax"); test_invalid(&[0x0f, 0xc3, 0xc3]); @@ -299,8 +299,8 @@ fn test_sse2() { test_instr(&[0x66, 0x4f, 0x0f, 0x50, 0xc1], "movmskpd r8d, xmm9"); test_instr(&[0x66, 0x4f, 0x0f, 0x51, 0x01], "sqrtpd xmm8, [r9]"); test_instr(&[0xf2, 0x4f, 0x0f, 0x51, 0x01], "sqrtsd xmm8, [r9]"); - test_instr(&[0x66, 0x4f, 0x0f, 0x52, 0x01], "rsqrtps xmm8, [r9]"); // note: NOT "rsqrtpd" - no such instruction exists, so fall back to just 0f52 parse. - test_instr(&[0x66, 0x4f, 0x0f, 0x53, 0x01], "rcpps xmm8, [r9]"); // note: NOT "rcppd" - no such instruction exists, so fall back to just 0f53 parse. + test_invalid(&[0x66, 0x4f, 0x0f, 0x52, 0x01]); + test_invalid(&[0x66, 0x4f, 0x0f, 0x53, 0x01]); test_instr(&[0x66, 0x4f, 0x0f, 0x54, 0x01], "andpd xmm8, [r9]"); test_instr(&[0x66, 0x4f, 0x0f, 0x55, 0x01], "andnpd xmm8, [r9]"); test_instr(&[0x66, 0x4f, 0x0f, 0x56, 0x01], "orpd xmm8, [r9]"); @@ -1318,7 +1318,7 @@ fn test_misc() { test_display(&[0x48, 0x98], "cdqe"); test_display(&[0x98], "cwde"); test_display(&[0x66, 0x99], "cwd"); - test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop cs:[rax + rax * 1]"); + test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop [rax + rax * 1]"); test_display(&[0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00], "nop [rax + rax * 1]"); test_display(&[0x48, 0x8d, 0xa4, 0xc7, 0x20, 0x00, 0x00, 0x12], "lea rsp, [rdi + rax * 8 + 0x12000020]"); test_display(&[0x33, 0xc0], "xor eax, eax"); @@ -1642,8 +1642,8 @@ fn prefixed_660f() { #[test] fn prefixed_f20f() { - test_display(&[0xf2, 0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7"); - test_display(&[0xf2, 0x4d, 0x0f, 0x16, 0xcf], "movlhps xmm9, xmm15"); + test_invalid(&[0xf2, 0x0f, 0x16, 0xcf]); + test_invalid(&[0xf2, 0x4d, 0x0f, 0x16, 0xcf]); test_display(&[0x40, 0x66, 0xf2, 0x66, 0x4d, 0x0f, 0x16, 0xcf], "movlhps xmm9, xmm15"); } @@ -2136,3 +2136,98 @@ fn test_x87() { test_invalid(&[0xdf, 0xfe]); test_invalid(&[0xdf, 0xff]); } + +#[test] +fn test_mishegos_finds() { + test_display(&[0x65, 0x67, 0x65, 0x65, 0x0f, 0x0e], "femms"); + test_display(&[0x26, 0x66, 0x67, 0x41, 0x0f, 0x38, 0xdf, 0xe4], "aesdeclast xmm4, xmm12"); + test_display(&[0x65, 0x66, 0x66, 0x64, 0x48, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, fs:[rdi]"); + /* + test_display(&[652e662e0f3814ff], "blendvps"); + test_display(&[66666565450f3acf2b4b], "gf2 "); + test_display(&[2e64f2f3400f38fbf8], "encodekey256"); + */ + + // might just be yax trying to do a f20f decode when it should not be f2 + // impossible instruction if operands could be read: lock is illegal here. + // test_display(&[f06565f2640f16], "???"); +// test_display(&[0x0f, 0x38, 0xf6, 0x8c, 0x98, 0x4d, 0x33, 0xf5, 0xd3, ], "wrssd"); + test_display(&[0x26, 0x36, 0x0f, 0x0f, 0x70, 0xfb, 0x0c], "pi2fw"); + test_display(&[0x0f, 0xc7, 0x0f], "cmpxchg8b [rdi]"); + test_display(&[0x4f, 0x0f, 0xc7, 0x0f], "cmpxchg16b [r15]"); + test_display(&[0x66, 0x3e, 0x26, 0x2e, 0x2e, 0x0f, 0x38, 0x2a, 0x2b, ], "movntdqa xmm5, [rbx]"); + test_display(&[0x66, 0x2e, 0x67, 0x0f, 0x3a, 0x0d, 0xb8, 0xf0, 0x2f, 0x7c, 0xf0, 0x63, ], "blendpd xmm7, [eax - 0xf83d010], 0x63"); + test_display(&[0x66, 0x66, 0x64, 0x3e, 0x0f, 0x38, 0x23, 0x9d, 0x69, 0x0f, 0xa8, 0x2d, ], "pmovsxwd xmm3, [rbp + 0x2da80f69]"); + test_display(&[0x2e, 0x66, 0x26, 0x64, 0x49, 0x0f, 0x3a, 0x21, 0x0b, 0xb1, ], "insertps xmm1, fs:[r11], -0x4f"); + test_display(&[0x66, 0x26, 0x45, 0x0f, 0x3a, 0x42, 0x96, 0x74, 0x29, 0x96, 0xf9, 0x6a], "mpsadbw xmm10, [r14 - 0x669d68c], 0x6a"); + test_display(&[0x67, 0x26, 0x66, 0x65, 0x0f, 0x38, 0x3f, 0x9d, 0xcc, 0x03, 0xb3, 0xfa], "pmaxud xmm3, gs:[ebp - 0x54cfc34]"); + test_display(&[0x36, 0x36, 0x2e, 0x0f, 0x38, 0xf9, 0x55, 0x3e, ], "movdiri [rbp + 0x3e], edx"); + test_display(&[0x36, 0x26, 0x66, 0x0f, 0x38, 0xf8, 0xad, 0x0b, 0x08, 0x29, 0x07], "movdir64b rbp, [rbp + 0x729080b]"); + test_display(&[0x36, 0x26, 0x66, 0x67, 0x0f, 0x38, 0xf8, 0xad, 0x0b, 0x08, 0x29, 0x07], "movdir64b ebp, [ebp + 0x729080b]"); + test_display(&[0x67, 0x66, 0x65, 0x3e, 0x0f, 0x6d, 0xd1], "punpckhqdq xmm2, xmm1"); + test_display(&[0x2e, 0x66, 0x40, 0x0f, 0x3a, 0x0d, 0x40, 0x2d, 0x57], "blendpd xmm0, [rax + 0x2d], 0x57"); + test_display(&[0xf2, 0x3e, 0x26, 0x67, 0x0f, 0xf0, 0xa0, 0x1b, 0x5f, 0xcd, 0xd7], "lddqu xmm4, [eax - 0x2832a0e5]"); + test_display(&[0x2e, 0x3e, 0x66, 0x3e, 0x49, 0x0f, 0x3a, 0x41, 0x30, 0x48], "dppd xmm6, [r8], 0x48"); + + test_display(&[0x2e, 0x36, 0x47, 0x0f, 0x18, 0xe7], "nop r15d"); + test_display(&[0x65, 0xf0, 0x87, 0x0f], "lock xchg gs:[rdi], ecx"); + test_display(&[0x66, 0x4e, 0x0f, 0x3a, 0x44, 0x88, 0xb3, 0xad, 0x26, 0x35, 0x75], "pclmulqdq xmm9, [rax + 0x3526adb3], 0x75"); + test_display(&[0x4c, 0x0f, 0xff, 0x6b, 0xac], "ud0 r13, [rbx - 0x54]"); + + test_display(&[0xf2, 0xf2, 0x2e, 0x36, 0x47, 0x0f, 0x38, 0xf8, 0x83, 0x09, 0x1c, 0x9d, 0x3f], "enqcmd r8d, [r11 + 0x3f9d1c09]"); + test_display(&[0x3e, 0x64, 0xf3, 0x64, 0x0f, 0x38, 0xf8, 0x72, 0x54], "enqcmds esi, fs:[rdx + 0x54]"); + + test_display(&[0xf3, 0x64, 0x2e, 0x65, 0x0f, 0x38, 0xdc, 0xe8], "loadiwkey xmm5, xmm0"); + + test_invalid(&[0xf3, 0x2e, 0x0f, 0x6a, 0x18]); +} + +#[test] +fn test_cet() { + // see + // https://software.intel.com/sites/default/files/managed/4d/2a/control-flow-enforcement-technology-preview.pdf + // includes encodings: + // wruss{d,q} 066 f 38 f5 + // wrss{d,q} 0f 38 f6 + // rstorssp f3 0f 01 /5 + // saveprevssp f3 0f 01 ea + // rdssp{d,q} f3 0f 1e + // incssp{d,q} f3 0f ae /5 + // test_display(&[0x0f, 0x38, 0xf6, 0x8c, 0x98, 0x4d, 0x33, 0xf5, 0xd3, ], "wrssd [rax + rbx * 4 - 0x2c0accb3], ecx"); + // setssbsy f3 0f 01 e8 + // clrssbsy f3 0f ae /6 + // endbr64 f3 0f ae fa + // endbr32 f3 0f ae fb +} + +#[test] +fn test_sse4a() { + // really gotta get some test cases for this +} + +#[test] +fn test_3dnow() { + test_display(&[0x65, 0x67, 0x65, 0x65, 0x0f, 0x0e], "femms"); + test_display(&[0x3e, 0xf3, 0x2e, 0xf2, 0x0f, 0x0f, 0x64, 0x93, 0x93, 0xa4], "pfmax mm4, [rbx + rdx * 4 - 0x6d]"); + test_display(&[0x26, 0x36, 0x0f, 0x0f, 0x70, 0xfb, 0x0c], "pi2fw"); +} + +// first appeared in tremont +#[test] +fn test_direct_stores() { + test_display(&[0x36, 0x36, 0x2e, 0x0f, 0x38, 0xf9, 0x55, 0x3e, ], "movdiri [rbp + 0x3e], edx"); + test_display(&[0x36, 0x26, 0x66, 0x0f, 0x38, 0xf8, 0xad, 0x0b, 0x08, 0x29, 0x07], "movdir64b rbp, [rbp + 0x729080b]"); + test_display(&[0x36, 0x26, 0x66, 0x67, 0x0f, 0x38, 0xf8, 0xad, 0x0b, 0x08, 0x29, 0x07], "movdir64b ebp, [ebp + 0x729080b]"); +} + +#[test] +fn test_key_locker() { + test_display(&[0xf3, 0x64, 0x2e, 0x65, 0x0f, 0x38, 0xdc, 0xe8], "loadiwkey xmm5, xmm0"); +} + +// started shipping in sapphire rapids +#[test] +fn test_enqcmd() { + test_display(&[0xf2, 0xf2, 0x2e, 0x36, 0x47, 0x0f, 0x38, 0xf8, 0x83, 0x09, 0x1c, 0x9d, 0x3f], "enqcmd r8d, [r11 + 0x3f9d1c09]"); + test_display(&[0x3e, 0x64, 0xf3, 0x64, 0x0f, 0x38, 0xf8, 0x72, 0x54], "enqcmds esi, fs:[rdx + 0x54]"); +} -- cgit v1.1