aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-03-17 23:45:16 -0700
committeriximeow <me@iximeow.net>2021-03-17 23:45:16 -0700
commit0c8dccaf591748e6acb9b437d69ba028e59a73cf (patch)
tree9d487f6cc1e2d305768162acb8a991f382612d19
parentf314ecafcdf3f80cce2d79214bda046cd1535e8c (diff)
support several new extensions, 3dnow, and nuance in invalid operands
-rw-r--r--src/long_mode/display.rs94
-rw-r--r--src/long_mode/mod.rs319
-rw-r--r--test/long_mode/mod.rs107
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 <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::HADDPS |
Opcode::HSUBPS |
Opcode::ADDSUBPS |
+ Opcode::PMULHRW |
+ Opcode::PFRCP |
+ Opcode::PFRSQRT |
+ Opcode::PFSUB |
+ Opcode::PFADD |
+ Opcode::PFRCPIT1 |
+ Opcode::PFRSQIT1 |
+ Opcode::PFSUBR |
+ Opcode::PFACC |
+ Opcode::PFMUL |
+ Opcode::PFRCPIT2 |
+ Opcode::PFNACC |
+ Opcode::PSWAPD |
+ Opcode::PFPNACC |
+ Opcode::PAVGUSB |
Opcode::XADD|
Opcode::DIV |
Opcode::IDIV |
@@ -1631,6 +1691,10 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::JG => { 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 <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::VMOVNTDQA |
Opcode::VMOVNTPD |
Opcode::VMOVNTPS |
+ Opcode::MOVDIR64B |
+ Opcode::MOVDIRI |
Opcode::MOVNTDQA |
Opcode::VMOVQ |
Opcode::VMOVSHDUP |
@@ -2040,6 +2106,11 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::PMINUB |
Opcode::PMINUD |
Opcode::PMINUW |
+ Opcode::PFCMPGE |
+ Opcode::PFMIN |
+ Opcode::PFCMPGT |
+ Opcode::PFMAX |
+ Opcode::PFCMPEQ |
Opcode::CMPS |
Opcode::SCAS |
Opcode::TEST |
@@ -2119,6 +2190,7 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::VERW |
Opcode::JMPE |
Opcode::EMMS |
+ Opcode::FEMMS |
Opcode::GETSEC |
Opcode::LFS |
Opcode::LGS |
@@ -2126,7 +2198,6 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::RSM |
Opcode::SYSENTER |
Opcode::SYSEXIT |
- Opcode::UD2E |
Opcode::VMREAD |
Opcode::VMWRITE |
Opcode::VMCLEAR |
@@ -2164,6 +2235,8 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::WRPKRU |
Opcode::RDPRU |
Opcode::CLZERO |
+ Opcode::ENQCMD |
+ Opcode::ENQCMDS |
Opcode::LAR => { write!(out, "{}", colors.platform_op(self)) }
Opcode::CRC32 |
@@ -2180,6 +2253,17 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::FFREEP |
Opcode::FDECSTP |
Opcode::FINCSTP |
+ Opcode::AESDEC128KL |
+ Opcode::AESDEC256KL |
+ Opcode::AESDECWIDE128KL |
+ Opcode::AESDECWIDE256KL |
+ Opcode::AESENC128KL |
+ Opcode::AESENC256KL |
+ Opcode::AESENCWIDE128KL |
+ Opcode::AESENCWIDE256KL |
+ Opcode::ENCODEKEY128 |
+ Opcode::ENCODEKEY256 |
+ Opcode::LOADIWKEY |
Opcode::AESDEC |
Opcode::AESDECLAST |
Opcode::AESENC |
@@ -2193,6 +2277,8 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::VAESIMC |
Opcode::VAESKEYGENASSIST => { 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<T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>>(
}
_ => {
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<T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>>(
},
_ => {
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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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<T: Iterator<Item=u8>>(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]");
+}