aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs2
-rw-r--r--src/protected_mode/display.rs2124
-rw-r--r--src/protected_mode/mod.rs6454
-rw-r--r--src/protected_mode/vex.rs2513
-rw-r--r--test/long_mode/mod.rs1094
-rw-r--r--test/long_mode/regspec.rs (renamed from test/regspec.rs)0
-rw-r--r--test/protected_mode/mod.rs1035
-rw-r--r--test/protected_mode/regspec.rs20
-rw-r--r--test/test.rs1096
9 files changed, 13242 insertions, 1096 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e7ca97d..30ac2e7 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -13,7 +13,7 @@ extern crate yaxpeax_arch;
pub mod long_mode;
pub use long_mode::Arch as x86_64;
-mod protected_mode;
+pub mod protected_mode;
pub use protected_mode::Arch as x86_32;
mod real_mode;
diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs
new file mode 100644
index 0000000..a5624d6
--- /dev/null
+++ b/src/protected_mode/display.rs
@@ -0,0 +1,2124 @@
+extern crate yaxpeax_arch;
+
+use core::fmt;
+
+use yaxpeax_arch::{Colorize, ShowContextual, NoColors, YaxColors};
+use yaxpeax_arch::display::*;
+
+use crate::protected_mode::{RegSpec, RegisterBank, Opcode, Operand, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec, DecodeError};
+
+impl fmt::Display for DecodeError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ DecodeError::ExhaustedInput => { write!(f, "exhausted input") },
+ DecodeError::InvalidOpcode => { write!(f, "invalid opcode") },
+ DecodeError::InvalidOperand => { write!(f, "invalid operand") },
+ DecodeError::InvalidPrefixes => { write!(f, "invalid prefixes") },
+ DecodeError::TooLong => { write!(f, "too long") },
+ DecodeError::IncompleteDecoder => { write!(f, "the decoder is incomplete") },
+ }
+ }
+}
+
+impl fmt::Display for InstDecoder {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self == &InstDecoder::default() {
+ return write!(f, "<all features>");
+ } else if self == &InstDecoder::minimal() {
+ return write!(f, "<no features>");
+ }
+ if self.sse3() { write!(f, "sse3 ")? }
+ if self.ssse3() { write!(f, "ssse3 ")? }
+ if self.monitor() { write!(f, "monitor ")? }
+ if self.vmx() { write!(f, "vmx ")? }
+ if self.fma3() { write!(f, "fma3 ")? }
+ if self.cmpxchg16b() { write!(f, "cmpxchg16b ")? }
+ if self.sse4_1() { write!(f, "sse4_1 ")? }
+ if self.sse4_2() { write!(f, "sse4_2 ")? }
+ if self.movbe() { write!(f, "movbe ")? }
+ if self.popcnt() { write!(f, "popcnt ")? }
+ if self.aesni() { write!(f, "aesni ")? }
+ if self.xsave() { write!(f, "xsave ")? }
+ if self.rdrand() { write!(f, "rdrand ")? }
+ if self.sgx() { write!(f, "sgx ")? }
+ if self.bmi1() { write!(f, "bmi1 ")? }
+ if self.avx2() { write!(f, "avx2 ")? }
+ if self.bmi2() { write!(f, "bmi2 ")? }
+ if self.invpcid() { write!(f, "invpcid ")? }
+ if self.mpx() { write!(f, "mpx ")? }
+ if self.avx512_f() { write!(f, "avx512_f ")? }
+ if self.avx512_dq() { write!(f, "avx512_dq ")? }
+ if self.rdseed() { write!(f, "rdseed ")? }
+ if self.adx() { write!(f, "adx ")? }
+ if self.avx512_fma() { write!(f, "avx512_fma ")? }
+ if self.pcommit() { write!(f, "pcommit ")? }
+ if self.clflushopt() { write!(f, "clflushopt ")? }
+ if self.clwb() { write!(f, "clwb ")? }
+ if self.avx512_pf() { write!(f, "avx512_pf ")? }
+ if self.avx512_er() { write!(f, "avx512_er ")? }
+ if self.avx512_cd() { write!(f, "avx512_cd ")? }
+ if self.sha() { write!(f, "sha ")? }
+ if self.avx512_bw() { write!(f, "avx512_bw ")? }
+ if self.avx512_vl() { write!(f, "avx512_vl ")? }
+ if self.prefetchwt1() { write!(f, "prefetchwt1 ")? }
+ if self.avx512_vbmi() { write!(f, "avx512_vbmi ")? }
+ if self.avx512_vbmi2() { write!(f, "avx512_vbmi2 ")? }
+ if self.gfni() { write!(f, "gfni ")? }
+ if self.vaes() { write!(f, "vaes ")? }
+ if self.pclmulqdq() { write!(f, "pclmulqdq ")? }
+ if self.avx_vnni() { write!(f, "avx_vnni ")? }
+ if self.avx512_bitalg() { write!(f, "avx512_bitalg ")? }
+ if self.avx512_vpopcntdq() { write!(f, "avx512_vpopcntdq ")? }
+ if self.avx512_4vnniw() { write!(f, "avx512_4vnniw ")? }
+ if self.avx512_4fmaps() { write!(f, "avx512_4fmaps ")? }
+ if self.cx8() { write!(f, "cx8 ")? }
+ if self.syscall() { write!(f, "syscall ")? }
+ if self.rdtscp() { write!(f, "rdtscp ")? }
+ if self.abm() { write!(f, "abm ")? }
+ if self.sse4a() { write!(f, "sse4a ")? }
+ if self._3dnowprefetch() { write!(f, "_3dnowprefetch ")? }
+ if self.xop() { write!(f, "xop ")? }
+ if self.skinit() { write!(f, "skinit ")? }
+ if self.tbm() { write!(f, "tbm ")? }
+ if self.intel_quirks() { write!(f, "intel_quirks ")? }
+ if self.amd_quirks() { write!(f, "amd_quirks ")? }
+ if self.avx() { write!(f, "avx ")? }
+ Ok(())
+ }
+}
+
+impl fmt::Display for PrefixVex {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.present() {
+ write!(f, "vex:{}{}{}{}",
+ if self.w() { "w" } else { "-" },
+ if self.r() { "r" } else { "-" },
+ if self.x() { "x" } else { "-" },
+ if self.b() { "b" } else { "-" },
+ )
+ } else {
+ write!(f, "rex:none")
+ }
+ }
+}
+
+impl fmt::Display for Segment {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Segment::CS => write!(f, "cs"),
+ Segment::DS => write!(f, "ds"),
+ Segment::ES => write!(f, "es"),
+ Segment::FS => write!(f, "fs"),
+ Segment::GS => write!(f, "gs"),
+ Segment::SS => write!(f, "ss"),
+ }
+ }
+}
+
+pub(crate) fn regspec_label(spec: &RegSpec) -> &'static str {
+ match spec.bank {
+ RegisterBank::D => {
+ ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"][spec.num as usize]
+ },
+ RegisterBank::W => {
+ ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"][spec.num as usize]
+ },
+ RegisterBank::B => {
+ ["al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"][spec.num as usize]
+ },
+ RegisterBank::EIP => { "eip" },
+ RegisterBank::EFlags => { "eflags" },
+ RegisterBank::CR => {
+ ["cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7"][spec.num as usize]
+ }
+ RegisterBank::DR => {
+ ["dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7"][spec.num as usize]
+ }
+ RegisterBank::X => {
+ ["xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"][spec.num as usize]
+ },
+ RegisterBank::Y => {
+ ["ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15"][spec.num as usize]
+ },
+ RegisterBank::Z => {
+ ["zmm0", "zmm1", "zmm2", "zmm3", "zmm4", "zmm5", "zmm6", "zmm7", "zmm8", "zmm9", "zmm10", "zmm11", "zmm12", "zmm13", "zmm14", "zmm15", "zmm16", "zmm17", "zmm18", "zmm19", "zmm20", "zmm21", "zmm22", "zmm23", "zmm24", "zmm25", "zmm26", "zmm27", "zmm28", "zmm29", "zmm30", "zmm31"][spec.num as usize]
+ },
+ RegisterBank::ST => {
+ ["st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"][spec.num as usize]
+ },
+ RegisterBank::MM => {
+ ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"][spec.num as usize]
+ }
+ RegisterBank::S => {
+ ["cs", "ds", "es", "fs", "gs", "ss"][spec.num as usize]
+ }
+ RegisterBank::K => {
+ ["k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7"][spec.num as usize]
+ }
+ }
+}
+
+impl fmt::Display for RegSpec {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{}", regspec_label(self))
+ }
+}
+
+impl fmt::Display for Operand {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ self.colorize(&NoColors, fmt)
+ }
+}
+
+impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color, Y> for Operand {
+ fn colorize(&self, colors: &Y, f: &mut T) -> fmt::Result {
+ match self {
+ &Operand::ImmediateU8(imm) => {
+ write!(f, "{}", colors.number(u8_hex(imm)))
+ }
+ &Operand::ImmediateI8(imm) => {
+ write!(f, "{}",
+ colors.number(signed_i8_hex(imm)))
+ },
+ &Operand::ImmediateU16(imm) => {
+ write!(f, "{}", colors.number(u16_hex(imm)))
+ }
+ &Operand::ImmediateI16(imm) => {
+ write!(f, "{}",
+ colors.number(signed_i16_hex(imm)))
+ },
+ &Operand::ImmediateU32(imm) => {
+ write!(f, "{}", colors.number(u32_hex(imm)))
+ }
+ &Operand::ImmediateI32(imm) => {
+ write!(f, "{}",
+ colors.number(signed_i32_hex(imm)))
+ },
+ &Operand::Register(ref spec) => {
+ write!(f, "{}", colors.register(spec))
+ }
+ &Operand::DisplacementU16(imm) => {
+ write!(f, "[{}]", colors.address(u32_hex(imm as u32)))
+ }
+ &Operand::DisplacementU32(imm) => {
+ write!(f, "[{}]", colors.address(u32_hex(imm)))
+ }
+ &Operand::RegDisp(ref spec, disp) => {
+ write!(f, "[{} ", colors.register(spec))?;
+ format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
+ write!(f, "]")
+ },
+ &Operand::RegDeref(ref spec) => {
+ write!(f, "[{}]", colors.register(spec))
+ },
+ &Operand::RegScale(ref spec, scale) => {
+ write!(f, "[{} * {}]",
+ colors.register(spec),
+ colors.number(scale)
+ )
+ },
+ &Operand::RegScaleDisp(ref spec, scale, disp) => {
+ write!(f, "[{} * {} ",
+ colors.register(spec),
+ colors.number(scale),
+ )?;
+ format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
+ write!(f, "]")
+ },
+ &Operand::RegIndexBase(ref base, ref index) => {
+ write!(f, "[{} + {}]",
+ colors.register(base),
+ colors.register(index)
+ )
+ }
+ &Operand::RegIndexBaseDisp(ref base, ref index, disp) => {
+ write!(f, "[{} + {} ",
+ colors.register(base),
+ colors.register(index),
+ )?;
+ format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
+ write!(f, "]")
+ },
+ &Operand::RegIndexBaseScale(ref base, ref index, scale) => {
+ write!(f, "[{} + {} * {}]",
+ colors.register(base),
+ colors.register(index),
+ colors.number(scale)
+ )
+ }
+ &Operand::RegIndexBaseScaleDisp(ref base, ref index, scale, disp) => {
+ write!(f, "[{} + {} * {} ",
+ colors.register(base),
+ colors.register(index),
+ colors.number(scale),
+ )?;
+ format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
+ write!(f, "]")
+ },
+ &Operand::Nothing => { Ok(()) },
+ }
+ }
+}
+
+impl fmt::Display for Opcode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &Opcode::POPCNT => write!(f, "popcnt"),
+ &Opcode::MOVDQU => write!(f, "movdqu"),
+ &Opcode::MOVDQA => write!(f, "movdqa"),
+ &Opcode::MOVQ => write!(f, "movq"),
+ &Opcode::CMPSS => write!(f, "cmpss"),
+ &Opcode::CMPSD => write!(f, "cmpsd"),
+ &Opcode::UNPCKLPS => write!(f, "unpcklps"),
+ &Opcode::UNPCKLPD => write!(f, "unpcklpd"),
+ &Opcode::UNPCKHPS => write!(f, "unpckhps"),
+ &Opcode::UNPCKHPD => write!(f, "unpckhpd"),
+ &Opcode::MOVUPS => write!(f, "movups"),
+ &Opcode::MOVQ2DQ => write!(f, "movq2dq"),
+ &Opcode::MOVDQ2Q => write!(f, "movdq2q"),
+ &Opcode::RSQRTSS => write!(f, "rsqrtss"),
+ &Opcode::MOVSHDUP => write!(f, "movshdup"),
+ &Opcode::CVTTPS2DQ => write!(f, "cvttps2dq"),
+ &Opcode::CVTPD2DQ => write!(f, "cvtpd2dq"),
+ &Opcode::RCPSS => write!(f, "rcpss"),
+ &Opcode::CVTDQ2PD => write!(f, "cvtdq2pd"),
+ &Opcode::PSHUFHW => write!(f, "pshufhw"),
+ &Opcode::PSHUFLW => write!(f, "pshuflw"),
+ &Opcode::XADD => write!(f, "xadd"),
+ &Opcode::BT => write!(f, "bt"),
+ &Opcode::BTS => write!(f, "bts"),
+ &Opcode::BTR => write!(f, "btr"),
+ &Opcode::BTC => write!(f, "btc"),
+ &Opcode::BSF => write!(f, "bsf"),
+ &Opcode::BSR => write!(f, "bsr"),
+ &Opcode::TZCNT => write!(f, "tzcnt"),
+ &Opcode::MOVSS => write!(f, "movss"),
+ &Opcode::SQRTSS => write!(f, "sqrtss"),
+ &Opcode::ADDSS => write!(f, "addss"),
+ &Opcode::SUBSS => write!(f, "subss"),
+ &Opcode::MULSS => write!(f, "mulss"),
+ &Opcode::DIVSS => write!(f, "divss"),
+ &Opcode::MINSS => write!(f, "minss"),
+ &Opcode::MAXSS => write!(f, "maxss"),
+ &Opcode::MOVSD => write!(f, "movsd"),
+ &Opcode::SQRTSD => write!(f, "sqrtsd"),
+ &Opcode::ADDSD => write!(f, "addsd"),
+ &Opcode::SUBSD => write!(f, "subsd"),
+ &Opcode::MULSD => write!(f, "mulsd"),
+ &Opcode::DIVSD => write!(f, "divsd"),
+ &Opcode::MINSD => write!(f, "minsd"),
+ &Opcode::MAXSD => write!(f, "maxsd"),
+ &Opcode::MOVDDUP => write!(f, "movddup"),
+ &Opcode::MOVSLDUP => write!(f, "movsldup"),
+ &Opcode::HADDPS => write!(f, "haddps"),
+ &Opcode::HSUBPS => write!(f, "hsubps"),
+ &Opcode::ADDSUBPS => write!(f, "addsubps"),
+ &Opcode::CVTSI2SS => write!(f, "cvtsi2ss"),
+ &Opcode::CVTSI2SD => write!(f, "cvtsi2sd"),
+ &Opcode::CVTTSD2SI => write!(f, "cvttsd2si"),
+ &Opcode::CVTSD2SI => write!(f, "cvtsd2si"),
+ &Opcode::CVTSD2SS => write!(f, "cvtsd2ss"),
+ &Opcode::CVTTSS2SI => write!(f, "cvttss2si"),
+ &Opcode::CVTSS2SI => write!(f, "cvtss2si"),
+ &Opcode::CVTSS2SD => write!(f, "cvtss2sd"),
+ &Opcode::LDDQU => write!(f, "lddqu"),
+ &Opcode::STI => write!(f, "sti"),
+ &Opcode::STD => write!(f, "std"),
+ &Opcode::STC => write!(f, "stc"),
+ &Opcode::CLI => write!(f, "cli"),
+ &Opcode::CLD => write!(f, "cld"),
+ &Opcode::CLC => write!(f, "clc"),
+ &Opcode::SLDT => write!(f, "sldt"),
+ &Opcode::STR => write!(f, "str"),
+ &Opcode::LLDT => write!(f, "lldt"),
+ &Opcode::LTR => write!(f, "ltr"),
+ &Opcode::VERR => write!(f, "verr"),
+ &Opcode::VERW => write!(f, "verw"),
+ &Opcode::JMPE => write!(f, "jmpe"),
+ &Opcode::WRMSR => write!(f, "wrmsr"),
+ &Opcode::RDMSR => write!(f, "rdmsr"),
+ &Opcode::RDTSC => write!(f, "rdtsc"),
+ &Opcode::RDPMC => write!(f, "rdpmc"),
+ &Opcode::FXSAVE => write!(f, "fxsave"),
+ &Opcode::FXRSTOR => write!(f, "fxrstor"),
+ &Opcode::LDMXCSR => write!(f, "ldmxcsr"),
+ &Opcode::STMXCSR => write!(f, "stmxcsr"),
+ &Opcode::XSAVE => write!(f, "xsave"),
+ &Opcode::XRSTOR => write!(f, "xrstor"),
+ &Opcode::XSAVEOPT => write!(f, "xsaveopt"),
+ &Opcode::LFENCE => write!(f, "lfence"),
+ &Opcode::MFENCE => write!(f, "mfence"),
+ &Opcode::SFENCE => write!(f, "sfence"),
+ &Opcode::CLFLUSH => write!(f, "clflush"),
+ &Opcode::LDS => write!(f, "lds"),
+ &Opcode::LES => write!(f, "les"),
+ &Opcode::SGDT => write!(f, "sgdt"),
+ &Opcode::SIDT => write!(f, "sidt"),
+ &Opcode::LGDT => write!(f, "lgdt"),
+ &Opcode::LIDT => write!(f, "lidt"),
+ &Opcode::SMSW => write!(f, "smsw"),
+ &Opcode::LMSW => write!(f, "lmsw"),
+ &Opcode::SWAPGS => write!(f, "swapgs"),
+ &Opcode::RDTSCP => write!(f, "rdtscp"),
+ &Opcode::INVLPG => write!(f, "invlpg"),
+ &Opcode::CPUID => write!(f, "cpuid"),
+ &Opcode::UD2 => write!(f, "ud2"),
+ &Opcode::WBINVD => write!(f, "wbinvd"),
+ &Opcode::INVD => write!(f, "invd"),
+ &Opcode::SYSRET => write!(f, "sysret"),
+ &Opcode::CLTS => write!(f, "clts"),
+ &Opcode::SYSCALL => write!(f, "syscall"),
+ &Opcode::LSL => write!(f, "lsl"),
+ &Opcode::LAR => write!(f, "lar"),
+ &Opcode::INC => write!(f, "inc"),
+ &Opcode::DEC => write!(f, "dec"),
+ &Opcode::HLT => write!(f, "hlt"),
+ &Opcode::SBB => write!(f, "sbb"),
+ &Opcode::AND => write!(f, "and"),
+ &Opcode::XOR => write!(f, "xor"),
+ &Opcode::OR => write!(f, "or"),
+ &Opcode::PUSH => write!(f, "push"),
+ &Opcode::POP => write!(f, "pop"),
+ &Opcode::LEA => write!(f, "lea"),
+ &Opcode::NOP => write!(f, "nop"),
+ &Opcode::PREFETCHNTA => write!(f, "prefetchnta"),
+ &Opcode::PREFETCH0 => write!(f, "prefetch0"),
+ &Opcode::PREFETCH1 => write!(f, "prefetch1"),
+ &Opcode::PREFETCH2 => write!(f, "prefetch2"),
+ &Opcode::XCHG => write!(f, "xchg"),
+ &Opcode::POPF => write!(f, "popf"),
+ &Opcode::ADD => write!(f, "add"),
+ &Opcode::ADC => write!(f, "adc"),
+ &Opcode::SUB => write!(f, "sub"),
+ &Opcode::INT => write!(f, "int"),
+ &Opcode::INTO => write!(f, "into"),
+ &Opcode::IRET => write!(f, "iret"),
+ &Opcode::RETF => write!(f, "retf"),
+ &Opcode::ENTER => write!(f, "enter"),
+ &Opcode::LEAVE => write!(f, "leave"),
+ &Opcode::MOV => write!(f, "mov"),
+ &Opcode::RETURN => write!(f, "ret"),
+ &Opcode::PUSHF => write!(f, "pushf"),
+ &Opcode::WAIT => write!(f, "wait"),
+ &Opcode::LODS => write!(f, "lods"),
+ &Opcode::STOS => write!(f, "stos"),
+ &Opcode::LAHF => write!(f, "lahf"),
+ &Opcode::SAHF => write!(f, "sahf"),
+ &Opcode::CMPS => write!(f, "cmps"),
+ &Opcode::SCAS => write!(f, "scas"),
+ &Opcode::MOVS => write!(f, "movs"),
+ &Opcode::TEST => write!(f, "test"),
+ &Opcode::CMP => write!(f, "cmp"),
+ &Opcode::INS => write!(f, "ins"),
+ &Opcode::IN => write!(f, "in"),
+ &Opcode::OUTS => write!(f, "outs"),
+ &Opcode::OUT => write!(f, "out"),
+ &Opcode::IMUL => write!(f, "imul"),
+ &Opcode::JO => write!(f, "jo"),
+ &Opcode::JNO => write!(f, "jno"),
+ &Opcode::JB => write!(f, "jb"),
+ &Opcode::JNB => write!(f, "jnb"),
+ &Opcode::JZ => write!(f, "jz"),
+ &Opcode::JNZ => write!(f, "jnz"),
+ &Opcode::JA => write!(f, "ja"),
+ &Opcode::JNA => write!(f, "jna"),
+ &Opcode::JS => write!(f, "js"),
+ &Opcode::JNS => write!(f, "jns"),
+ &Opcode::JP => write!(f, "jp"),
+ &Opcode::JNP => write!(f, "jnp"),
+ &Opcode::JL => write!(f, "jl"),
+ &Opcode::JGE => write!(f, "jge"),
+ &Opcode::JLE => write!(f, "jle"),
+ &Opcode::JG => write!(f, "jg"),
+ &Opcode::CALL => write!(f, "call"),
+ &Opcode::JMP => write!(f, "jmp"),
+ &Opcode::CALLF => write!(f, "callf"),
+ &Opcode::JMPF => write!(f, "jmpf"),
+ &Opcode::SAR => write!(f, "sar"),
+ &Opcode::SAL => write!(f, "sal"),
+ &Opcode::SHR => write!(f, "shr"),
+ &Opcode::SHRD => write!(f, "shrd"),
+ &Opcode::SHL => write!(f, "shl"),
+ &Opcode::RCR => write!(f, "rcr"),
+ &Opcode::RCL => write!(f, "rcl"),
+ &Opcode::ROR => write!(f, "ror"),
+ &Opcode::ROL => write!(f, "rol"),
+ &Opcode::CMOVA => write!(f, "cmova"),
+ &Opcode::CMOVB => write!(f, "cmovb"),
+ &Opcode::CMOVG => write!(f, "cmovg"),
+ &Opcode::CMOVGE => write!(f, "cmovge"),
+ &Opcode::CMOVL => write!(f, "cmovl"),
+ &Opcode::CMOVLE => write!(f, "cmovle"),
+ &Opcode::CMOVNA => write!(f, "cmovna"),
+ &Opcode::CMOVNB => write!(f, "cmovnb"),
+ &Opcode::CMOVNO => write!(f, "cmovno"),
+ &Opcode::CMOVNP => write!(f, "cmovnp"),
+ &Opcode::CMOVNS => write!(f, "cmovns"),
+ &Opcode::CMOVNZ => write!(f, "cmovnz"),
+ &Opcode::CMOVO => write!(f, "cmovo"),
+ &Opcode::CMOVP => write!(f, "cmovp"),
+ &Opcode::CMOVS => write!(f, "cmovs"),
+ &Opcode::CMOVZ => write!(f, "cmovz"),
+ &Opcode::NEG => write!(f, "neg"),
+ &Opcode::NOT => write!(f, "not"),
+ &Opcode::MUL => write!(f, "mul"),
+ &Opcode::DIV => write!(f, "div"),
+ &Opcode::IDIV => write!(f, "idiv"),
+ &Opcode::CMPXCHG => write!(f, "cmpxchg"),
+ &Opcode::MOVSX_b => write!(f, "movsx"),
+ &Opcode::MOVSX_w => write!(f, "movsx"),
+ &Opcode::MOVZX_b => write!(f, "movzx"),
+ &Opcode::MOVZX_w => write!(f, "movzx"),
+ &Opcode::MOVSX => write!(f, "movsx"),
+ &Opcode::SETO => write!(f, "seto"),
+ &Opcode::SETNO => write!(f, "setno"),
+ &Opcode::SETB => write!(f, "setb"),
+ &Opcode::SETAE => write!(f, "setae"),
+ &Opcode::SETZ => write!(f, "setz"),
+ &Opcode::SETNZ => write!(f, "setnz"),
+ &Opcode::SETBE => write!(f, "setbe"),
+ &Opcode::SETA => write!(f, "seta"),
+ &Opcode::SETS => write!(f, "sets"),
+ &Opcode::SETNS => write!(f, "setns"),
+ &Opcode::SETP => write!(f, "setp"),
+ &Opcode::SETNP => write!(f, "setnp"),
+ &Opcode::SETL => write!(f, "setl"),
+ &Opcode::SETGE => write!(f, "setge"),
+ &Opcode::SETLE => write!(f, "setle"),
+ &Opcode::SETG => write!(f, "setg"),
+ &Opcode::ADDPS => write!(f, "addps"),
+ &Opcode::ADDPD => write!(f, "addpd"),
+ &Opcode::ANDNPS => write!(f, "andnps"),
+ &Opcode::ANDNPD => write!(f, "andnpd"),
+ &Opcode::ANDPS => write!(f, "andps"),
+ &Opcode::ANDPD => write!(f, "andpd"),
+ &Opcode::BSWAP => write!(f, "bswap"),
+ &Opcode::CMPPS => write!(f, "cmpps"),
+ &Opcode::CMPPD => write!(f, "cmppd"),
+ &Opcode::COMISD => write!(f, "comisd"),
+ &Opcode::COMISS => write!(f, "comiss"),
+ &Opcode::CVTDQ2PS => write!(f, "cvtdq2ps"),
+ &Opcode::CVTPS2DQ => write!(f, "cvtps2dq"),
+ &Opcode::CVTPI2PS => write!(f, "cvtpi2ps"),
+ &Opcode::CVTPI2PD => write!(f, "cvtpi2pd"),
+ &Opcode::CVTPS2PD => write!(f, "cvtps2pd"),
+ &Opcode::CVTPD2PS => write!(f, "cvtpd2ps"),
+ &Opcode::CVTPS2PI => write!(f, "cvtps2pi"),
+ &Opcode::CVTPD2PI => write!(f, "cvtpd2pi"),
+ &Opcode::CVTTPS2PI => write!(f, "cvttps2pi"),
+ &Opcode::CVTTPD2PI => write!(f, "cvttpd2pi"),
+ &Opcode::CVTTPD2DQ => write!(f, "cvttpd2dq"),
+ &Opcode::DIVPS => write!(f, "divps"),
+ &Opcode::DIVPD => write!(f, "divpd"),
+ &Opcode::EMMS => write!(f, "emms"),
+ &Opcode::GETSEC => write!(f, "getsec"),
+ &Opcode::LFS => write!(f, "lfs"),
+ &Opcode::LGS => write!(f, "lgs"),
+ &Opcode::LSS => write!(f, "lss"),
+ &Opcode::ARPL => write!(f, "arpl"),
+ &Opcode::MASKMOVQ => write!(f, "maskmovq"),
+ &Opcode::MASKMOVDQU => write!(f, "maskmovdqu"),
+ &Opcode::MAXPS => write!(f, "maxps"),
+ &Opcode::MAXPD => write!(f, "maxpd"),
+ &Opcode::MINPS => write!(f, "minps"),
+ &Opcode::MINPD => write!(f, "minpd"),
+ &Opcode::MOVAPS => write!(f, "movaps"),
+ &Opcode::MOVAPD => write!(f, "movapd"),
+ &Opcode::MOVD => write!(f, "movd"),
+ &Opcode::MOVLPS => write!(f, "movlps"),
+ &Opcode::MOVLPD => write!(f, "movlpd"),
+ &Opcode::MOVLHPS => write!(f, "movlhps"),
+ &Opcode::MOVHPS => write!(f, "movhps"),
+ &Opcode::MOVHPD => write!(f, "movhpd"),
+ &Opcode::MOVHLPS => write!(f, "movhlps"),
+ &Opcode::MOVUPD => write!(f, "movupd"),
+ &Opcode::MOVMSKPS => write!(f, "movmskps"),
+ &Opcode::MOVMSKPD => write!(f, "movmskpd"),
+ &Opcode::MOVNTI => write!(f, "movnti"),
+ &Opcode::MOVNTPS => write!(f, "movntps"),
+ &Opcode::MOVNTPD => write!(f, "movntpd"),
+ &Opcode::MOVNTQ => write!(f, "movntq"),
+ &Opcode::MOVNTDQ => write!(f, "movntdq"),
+ &Opcode::MULPS => write!(f, "mulps"),
+ &Opcode::MULPD => write!(f, "mulpd"),
+ &Opcode::ORPS => write!(f, "orps"),
+ &Opcode::ORPD => write!(f, "orpd"),
+ &Opcode::PACKSSDW => write!(f, "packssdw"),
+ &Opcode::PACKSSWB => write!(f, "packsswb"),
+ &Opcode::PACKUSWB => write!(f, "packuswb"),
+ &Opcode::PADDB => write!(f, "paddb"),
+ &Opcode::PADDD => write!(f, "paddd"),
+ &Opcode::PADDQ => write!(f, "paddq"),
+ &Opcode::PADDSB => write!(f, "paddsb"),
+ &Opcode::PADDSW => write!(f, "paddsw"),
+ &Opcode::PADDUSB => write!(f, "paddusb"),
+ &Opcode::PADDUSW => write!(f, "paddusw"),
+ &Opcode::PADDW => write!(f, "paddw"),
+ &Opcode::PAND => write!(f, "pand"),
+ &Opcode::PANDN => write!(f, "pandn"),
+ &Opcode::PAVGB => write!(f, "pavgb"),
+ &Opcode::PAVGW => write!(f, "pavgw"),
+ &Opcode::PCMPEQB => write!(f, "pcmpeqb"),
+ &Opcode::PCMPEQD => write!(f, "pcmpeqd"),
+ &Opcode::PCMPEQW => write!(f, "pcmpeqw"),
+ &Opcode::PCMPGTB => write!(f, "pcmpgtb"),
+ &Opcode::PCMPGTD => write!(f, "pcmpgtd"),
+ &Opcode::PCMPGTW => write!(f, "pcmpgtw"),
+ &Opcode::PEXTRW => write!(f, "pextrw"),
+ &Opcode::PINSRW => write!(f, "pinsrw"),
+ &Opcode::PMADDWD => write!(f, "pmaddwd"),
+ &Opcode::PMAXSW => write!(f, "pmaxsw"),
+ &Opcode::PMAXUB => write!(f, "pmaxub"),
+ &Opcode::PMINSW => write!(f, "pminsw"),
+ &Opcode::PMINUB => write!(f, "pminub"),
+ &Opcode::PMOVMSKB => write!(f, "pmovmskb"),
+ &Opcode::PMULHUW => write!(f, "pmulhuw"),
+ &Opcode::PMULHW => write!(f, "pmulhw"),
+ &Opcode::PMULLW => write!(f, "pmullw"),
+ &Opcode::PMULUDQ => write!(f, "pmuludq"),
+ &Opcode::POR => write!(f, "por"),
+ &Opcode::PSADBW => write!(f, "psadbw"),
+ &Opcode::PSHUFW => write!(f, "pshufw"),
+ &Opcode::PSHUFD => write!(f, "pshufd"),
+ &Opcode::PSLLD => write!(f, "pslld"),
+ &Opcode::PSLLDQ => write!(f, "pslldq"),
+ &Opcode::PSLLQ => write!(f, "psllq"),
+ &Opcode::PSLLW => write!(f, "psllw"),
+ &Opcode::PSRAD => write!(f, "psrad"),
+ &Opcode::PSRAW => write!(f, "psraw"),
+ &Opcode::PSRLD => write!(f, "psrld"),
+ &Opcode::PSRLDQ => write!(f, "psrldq"),
+ &Opcode::PSRLQ => write!(f, "psrlq"),
+ &Opcode::PSRLW => write!(f, "psrlw"),
+ &Opcode::PSUBB => write!(f, "psubb"),
+ &Opcode::PSUBD => write!(f, "psubd"),
+ &Opcode::PSUBQ => write!(f, "psubq"),
+ &Opcode::PSUBSB => write!(f, "psubsb"),
+ &Opcode::PSUBSW => write!(f, "psubsw"),
+ &Opcode::PSUBUSB => write!(f, "psubusb"),
+ &Opcode::PSUBUSW => write!(f, "psubusw"),
+ &Opcode::PSUBW => write!(f, "psubw"),
+ &Opcode::PUNPCKHBW => write!(f, "punpckhbw"),
+ &Opcode::PUNPCKHDQ => write!(f, "punpckhdq"),
+ &Opcode::PUNPCKHWD => write!(f, "punpckhwd"),
+ &Opcode::PUNPCKLBW => write!(f, "punpcklbw"),
+ &Opcode::PUNPCKLDQ => write!(f, "punpckldq"),
+ &Opcode::PUNPCKLWD => write!(f, "punpcklwd"),
+ &Opcode::PUNPCKLQDQ => write!(f, "punpcklqdq"),
+ &Opcode::PUNPCKHQDQ => write!(f, "punpckhqdq"),
+ &Opcode::PXOR => write!(f, "pxor"),
+ &Opcode::RCPPS => write!(f, "rcpps"),
+ &Opcode::RSM => write!(f, "rsm"),
+ &Opcode::RSQRTPS => write!(f, "rsqrtps"),
+ &Opcode::SHLD => write!(f, "shld"),
+ &Opcode::SHUFPD => write!(f, "shufpd"),
+ &Opcode::SHUFPS => write!(f, "shufps"),
+ &Opcode::SLHD => write!(f, "slhd"),
+ &Opcode::SQRTPS => write!(f, "sqrtps"),
+ &Opcode::SQRTPD => write!(f, "sqrtpd"),
+ &Opcode::SUBPS => write!(f, "subps"),
+ &Opcode::SUBPD => write!(f, "subpd"),
+ &Opcode::SYSENTER => write!(f, "sysenter"),
+ &Opcode::SYSEXIT => write!(f, "sysexit"),
+ &Opcode::UCOMISD => write!(f, "ucomisd"),
+ &Opcode::UCOMISS => write!(f, "ucomiss"),
+ &Opcode::UD2E => write!(f, "ud2e"),
+ &Opcode::VMREAD => write!(f, "vmread"),
+ &Opcode::VMWRITE => write!(f, "vmwrite"),
+ &Opcode::XORPS => write!(f, "xorps"),
+ &Opcode::XORPD => write!(f, "xorpd"),
+ &Opcode::CBW => write!(f, "cbw"),
+ &Opcode::CWDE => write!(f, "cwde"),
+ &Opcode::CDQE => write!(f, "cdqe"),
+ &Opcode::CBD => write!(f, "cbd"),
+ &Opcode::CDQ => write!(f, "cdq"),
+ &Opcode::CQO => write!(f, "cqo"),
+ &Opcode::ANDN => write!(f, "andn"),
+ &Opcode::BEXTR => write!(f, "bextr"),
+ &Opcode::BLSI => write!(f, "blsi"),
+ &Opcode::BLSMSK => write!(f, "blsmsk"),
+ &Opcode::BLSR => write!(f, "blsr"),
+ &Opcode::VMCLEAR => write!(f, "vmclear"),
+ &Opcode::VMXON => write!(f, "vmxon"),
+ &Opcode::VMCALL => write!(f, "vmcall"),
+ &Opcode::VMLAUNCH => write!(f, "vmlaunch"),
+ &Opcode::VMRESUME => write!(f, "vmresume"),
+ &Opcode::VMXOFF => write!(f, "vmxoff"),
+ &Opcode::MONITOR => write!(f, "monitor"),
+ &Opcode::MWAIT => write!(f, "mwait"),
+ &Opcode::CLAC => write!(f, "clac"),
+ &Opcode::STAC => write!(f, "stac"),
+ &Opcode::ENCLS => write!(f, "encls"),
+ &Opcode::ENCLV => write!(f, "enclv"),
+ &Opcode::XGETBV => write!(f, "xgetbv"),
+ &Opcode::XSETBV => write!(f, "xsetbv"),
+ &Opcode::VMFUNC => write!(f, "vmfunc"),
+ &Opcode::XEND => write!(f, "xend"),
+ &Opcode::XTEST => write!(f, "xtest"),
+ &Opcode::ENCLU => write!(f, "enclu"),
+ &Opcode::RDPKRU => write!(f, "rdpkru"),
+ &Opcode::WRPKRU => write!(f, "wrpkru"),
+ &Opcode::VADDPD => write!(f, "vaddpd"),
+ &Opcode::VADDPS => write!(f, "vaddps"),
+ &Opcode::VADDSUBPD => write!(f, "vaddsubpd"),
+ &Opcode::VAESDEC => write!(f, "vaesdec"),
+ &Opcode::VAESDECLAST => write!(f, "vaesdeclast"),
+ &Opcode::VAESENC => write!(f, "vaesenc"),
+ &Opcode::VAESENCLAST => write!(f, "vaesenclast"),
+ &Opcode::VAESIMC => write!(f, "vaesimc"),
+ &Opcode::VAESKEYGENASSIST => write!(f, "vaeskeygenassist"),
+ &Opcode::VBLENDPD => write!(f, "vblendpd"),
+ &Opcode::VBLENDPS => write!(f, "vblendps"),
+ &Opcode::VBLENDVPD => write!(f, "vblendvpd"),
+ &Opcode::VBLENDVPS => write!(f, "vblendvps"),
+ &Opcode::VBROADCASTF128 => write!(f, "vbroadcastf128"),
+ &Opcode::VBROADCASTI128 => write!(f, "vbroadcasti128"),
+ &Opcode::VBROADCASTSD => write!(f, "vbroadcastsd"),
+ &Opcode::VBROADCASTSS => write!(f, "vbroadcastss"),
+ &Opcode::VCMPPD => write!(f, "vcmppd"),
+ &Opcode::VCMPPS => write!(f, "vcmpps"),
+ &Opcode::VCVTDQ2PD => write!(f, "vcvtdq2pd"),
+ &Opcode::VCVTDQ2PS => write!(f, "vcvtdq2ps"),
+ &Opcode::VCVTPD2PS => write!(f, "vcvtpd2ps"),
+ &Opcode::VCVTPH2PS => write!(f, "vcvtph2ps"),
+ &Opcode::VCVTPS2DQ => write!(f, "vcvtps2dq"),
+ &Opcode::VCVTPS2PD => write!(f, "vcvtps2pd"),
+ &Opcode::VCVTPS2PH => write!(f, "vcvtps2ph"),
+ &Opcode::VCVTTPD2DQ => write!(f, "vcvttpd2dq"),
+ &Opcode::VCVTTPS2DQ => write!(f, "vcvttps2dq"),
+ &Opcode::VDIVPD => write!(f, "vdivpd"),
+ &Opcode::VDIVPS => write!(f, "vdivps"),
+ &Opcode::VDPPD => write!(f, "vdppd"),
+ &Opcode::VDPPS => write!(f, "vdpps"),
+ &Opcode::VEXTRACTF128 => write!(f, "vextractf128"),
+ &Opcode::VEXTRACTI128 => write!(f, "vextracti128"),
+ &Opcode::VEXTRACTPS => write!(f, "vextractps"),
+ &Opcode::VFMADD132PD => write!(f, "vfmadd132pd"),
+ &Opcode::VFMADD132PS => write!(f, "vfmadd132ps"),
+ &Opcode::VFMADD213PD => write!(f, "vfmadd213pd"),
+ &Opcode::VFMADD213PS => write!(f, "vfmadd213ps"),
+ &Opcode::VFMADD231PD => write!(f, "vfmadd231pd"),
+ &Opcode::VFMADD231PS => write!(f, "vfmadd231ps"),
+ &Opcode::VFMADDSUB132PD => write!(f, "vfmaddsub132pd"),
+ &Opcode::VFMADDSUB132PS => write!(f, "vfmaddsub132ps"),
+ &Opcode::VFMADDSUB213PD => write!(f, "vfmaddsub213pd"),
+ &Opcode::VFMADDSUB213PS => write!(f, "vfmaddsub213ps"),
+ &Opcode::VFMADDSUB231PD => write!(f, "vfmaddsub231pd"),
+ &Opcode::VFMADDSUB231PS => write!(f, "vfmaddsub231ps"),
+ &Opcode::VFMSUB132PD => write!(f, "vfmsub132pd"),
+ &Opcode::VFMSUB132PS => write!(f, "vfmsub132ps"),
+ &Opcode::VFMSUB213PD => write!(f, "vfmsub213pd"),
+ &Opcode::VFMSUB213PS => write!(f, "vfmsub213ps"),
+ &Opcode::VFMSUB231PD => write!(f, "vfmsub231pd"),
+ &Opcode::VFMSUB231PS => write!(f, "vfmsub231ps"),
+ &Opcode::VFMSUBADD132PD => write!(f, "vfmsubadd132pd"),
+ &Opcode::VFMSUBADD132PS => write!(f, "vfmsubadd132ps"),
+ &Opcode::VFMSUBADD213PD => write!(f, "vfmsubadd213pd"),
+ &Opcode::VFMSUBADD213PS => write!(f, "vfmsubadd213ps"),
+ &Opcode::VFMSUBADD231PD => write!(f, "vfmsubadd231pd"),
+ &Opcode::VFMSUBADD231PS => write!(f, "vfmsubadd231ps"),
+ &Opcode::VFNMADD132PD => write!(f, "vfnmadd132pd"),
+ &Opcode::VFNMADD132PS => write!(f, "vfnmadd132ps"),
+ &Opcode::VFNMADD213PD => write!(f, "vfnmadd213pd"),
+ &Opcode::VFNMADD213PS => write!(f, "vfnmadd213ps"),
+ &Opcode::VFNMADD231PD => write!(f, "vfnmadd231pd"),
+ &Opcode::VFNMADD231PS => write!(f, "vfnmadd231ps"),
+ &Opcode::VFNMSUB132PD => write!(f, "vfnmsub132pd"),
+ &Opcode::VFNMSUB132PS => write!(f, "vfnmsub132ps"),
+ &Opcode::VFNMSUB213PD => write!(f, "vfnmsub213pd"),
+ &Opcode::VFNMSUB213PS => write!(f, "vfnmsub213ps"),
+ &Opcode::VFNMSUB231PD => write!(f, "vfnmsub231pd"),
+ &Opcode::VFNMSUB231PS => write!(f, "vfnmsub231ps"),
+ &Opcode::VGATHERDPD => write!(f, "vgatherdpd"),
+ &Opcode::VGATHERDPS => write!(f, "vgatherdps"),
+ &Opcode::VGATHERQPD => write!(f, "vgatherqpd"),
+ &Opcode::VGATHERQPS => write!(f, "vgatherqps"),
+ &Opcode::VHADDPD => write!(f, "vhaddpd"),
+ &Opcode::VHSUBPD => write!(f, "vhsubpd"),
+ &Opcode::VINSERTF128 => write!(f, "vinsertf128"),
+ &Opcode::VINSERTI128 => write!(f, "vinserti128"),
+ &Opcode::VINSERTPS => write!(f, "vinsertps"),
+ &Opcode::VMASKMOVDQU => write!(f, "vmaskmovdqu"),
+ &Opcode::VMASKMOVPD => write!(f, "vmaskmovpd"),
+ &Opcode::VMASKMOVPS => write!(f, "vmaskmovps"),
+ &Opcode::VMAXPD => write!(f, "vmaxpd"),
+ &Opcode::VMAXPS => write!(f, "vmaxps"),
+ &Opcode::VMINPD => write!(f, "vminpd"),
+ &Opcode::VMINPS => write!(f, "vminps"),
+ &Opcode::VMOVAPD => write!(f, "vmovapd"),
+ &Opcode::VMOVAPS => write!(f, "vmovaps"),
+ &Opcode::VMOVD => write!(f, "vmovd"),
+ &Opcode::VMOVDQA => write!(f, "vmovdqa"),
+ &Opcode::VMOVDQU => write!(f, "vmovdqu"),
+ &Opcode::VMOVHLPS => write!(f, "vmovhlps"),
+ &Opcode::VMOVHPD => write!(f, "vmovhpd"),
+ &Opcode::VMOVHPS => write!(f, "vmovhps"),
+ &Opcode::VMOVLHPS => write!(f, "vmovlhps"),
+ &Opcode::VMOVLPD => write!(f, "vmovlpd"),
+ &Opcode::VMOVLPS => write!(f, "vmovlps"),
+ &Opcode::VMOVMSKPD => write!(f, "vmovmskpd"),
+ &Opcode::VMOVMSKPS => write!(f, "vmovmskps"),
+ &Opcode::VMOVNTDQ => write!(f, "vmovntdq"),
+ &Opcode::VMOVNTDQA => write!(f, "vmovntdqa"),
+ &Opcode::VMOVNTPD => write!(f, "vmovntpd"),
+ &Opcode::VMOVNTPS => write!(f, "vmovntps"),
+ &Opcode::VMOVQ => write!(f, "vmovq"),
+ &Opcode::VMOVSHDUP => write!(f, "vmovshdup"),
+ &Opcode::VMOVSLDUP => write!(f, "vmovsldup"),
+ &Opcode::VMOVUPD => write!(f, "vmovupd"),
+ &Opcode::VMOVUPS => write!(f, "vmovups"),
+ &Opcode::VMPSADBW => write!(f, "vmpsadbw"),
+ &Opcode::VMULPD => write!(f, "vmulpd"),
+ &Opcode::VMULPS => write!(f, "vmulps"),
+ &Opcode::VPABSB => write!(f, "vpabsb"),
+ &Opcode::VPABSD => write!(f, "vpabsd"),
+ &Opcode::VPABSW => write!(f, "vpabsw"),
+ &Opcode::VPACKSSDW => write!(f, "vpackssdw"),
+ &Opcode::VPACKSSWB => write!(f, "vpacksswb"),
+ &Opcode::VPACKUSWB => write!(f, "vpackuswb"),
+ &Opcode::VPADDB => write!(f, "vpaddb"),
+ &Opcode::VPADDD => write!(f, "vpaddd"),
+ &Opcode::VPADDQ => write!(f, "vpaddq"),
+ &Opcode::VPADDSB => write!(f, "vpaddsb"),
+ &Opcode::VPADDSW => write!(f, "vpaddsw"),
+ &Opcode::VPADDUSB => write!(f, "vpaddusb"),
+ &Opcode::VPADDUSW => write!(f, "vpaddusw"),
+ &Opcode::VPADDW => write!(f, "vpaddw"),
+ &Opcode::VPALIGNR => write!(f, "vpalignr"),
+ &Opcode::VPAND => write!(f, "vpand"),
+ &Opcode::VPANDN => write!(f, "vpandn"),
+ &Opcode::VPAVGB => write!(f, "vpavgb"),
+ &Opcode::VPAVGW => write!(f, "vpavgw"),
+ &Opcode::VPBLENDD => write!(f, "vpblendd"),
+ &Opcode::VPBLENDVB => write!(f, "vpblendvb"),
+ &Opcode::VPBLENDW => write!(f, "vpblendw"),
+ &Opcode::VPBROADCASTB => write!(f, "vpbroadcastb"),
+ &Opcode::VPBROADCASTD => write!(f, "vpbroadcastd"),
+ &Opcode::VPBROADCASTQ => write!(f, "vpbroadcastq"),
+ &Opcode::VPBROADCASTW => write!(f, "vpbroadcastw"),
+ &Opcode::VPCLMULQDQ => write!(f, "vpclmulqdq"),
+ &Opcode::VPCMPEQB => write!(f, "vpcmpeqb"),
+ &Opcode::VPCMPEQD => write!(f, "vpcmpeqd"),
+ &Opcode::VPCMPEQQ => write!(f, "vpcmpeqq"),
+ &Opcode::VPCMPEQW => write!(f, "vpcmpeqw"),
+ &Opcode::VPCMPGTB => write!(f, "vpcmpgtb"),
+ &Opcode::VPCMPGTD => write!(f, "vpcmpgtd"),
+ &Opcode::VPCMPGTQ => write!(f, "vpcmpgtq"),
+ &Opcode::VPCMPGTW => write!(f, "vpcmpgtw"),
+ &Opcode::VPCMPISTRI => write!(f, "vpcmpistri"),
+ &Opcode::VPCMPISTRM => write!(f, "vpcmpistrm"),
+ &Opcode::VPERM2F128 => write!(f, "vperm2f128"),
+ &Opcode::VPERM2I128 => write!(f, "vperm2i128"),
+ &Opcode::VPERMD => write!(f, "vpermd"),
+ &Opcode::VPERMILPD => write!(f, "vpermilpd"),
+ &Opcode::VPERMILPS => write!(f, "vpermilps"),
+ &Opcode::VPERMPD => write!(f, "vpermpd"),
+ &Opcode::VPERMPS => write!(f, "vpermps"),
+ &Opcode::VPERMQ => write!(f, "vpermq"),
+ &Opcode::VPEXTRB => write!(f, "vpextrb"),
+ &Opcode::VPEXTRD => write!(f, "vpextrd"),
+ &Opcode::VPEXTRQ => write!(f, "vpextrq"),
+ &Opcode::VPEXTRW => write!(f, "vpextrw"),
+ &Opcode::VPGATHERDD => write!(f, "vpgatherdd"),
+ &Opcode::VPGATHERDQ => write!(f, "vpgatherdq"),
+ &Opcode::VPGATHERQD => write!(f, "vpgatherqd"),
+ &Opcode::VPGATHERQQ => write!(f, "vpgatherqq"),
+ &Opcode::VPHADDD => write!(f, "vphaddd"),
+ &Opcode::VPHADDSW => write!(f, "vphaddsw"),
+ &Opcode::VPHADDUBSW => write!(f, "vphaddubsw"),
+ &Opcode::VPHADDW => write!(f, "vphaddw"),
+ &Opcode::VPHMINPOSUW => write!(f, "vphminposuw"),
+ &Opcode::VPHSUBD => write!(f, "vphsubd"),
+ &Opcode::VPHSUBSW => write!(f, "vphsubsw"),
+ &Opcode::VPHSUBW => write!(f, "vphsubw"),
+ &Opcode::VPINSRB => write!(f, "vpinsrb"),
+ &Opcode::VPINSRD => write!(f, "vpinsrd"),
+ &Opcode::VPINSRQ => write!(f, "vpinsrq"),
+ &Opcode::VPINSRW => write!(f, "vpinsrw"),
+ &Opcode::VPMADDWD => write!(f, "vpmaddwd"),
+ &Opcode::VPMASKMOVD => write!(f, "vpmaskmovd"),
+ &Opcode::VPMASKMOVQ => write!(f, "vpmaskmovq"),
+ &Opcode::VPMAXSB => write!(f, "vpmaxsb"),
+ &Opcode::VPMAXSD => write!(f, "vpmaxsd"),
+ &Opcode::VPMAXSW => write!(f, "vpmaxsw"),
+ &Opcode::VPMAXUD => write!(f, "vpmaxud"),
+ &Opcode::VPMINSD => write!(f, "vpminsd"),
+ &Opcode::VPMINUD => write!(f, "vpminud"),
+ &Opcode::VPMOVMSKB => write!(f, "vpmovmskb"),
+ &Opcode::VPMOVSXBD => write!(f, "vpmovsxbd"),
+ &Opcode::VPMOVSXBQ => write!(f, "vpmovsxbq"),
+ &Opcode::VPMOVSXBW => write!(f, "vpmovsxbw"),
+ &Opcode::VPMOVSXDQ => write!(f, "vpmovsxdq"),
+ &Opcode::VPMOVSXWD => write!(f, "vpmovsxwd"),
+ &Opcode::VPMOVSXWQ => write!(f, "vpmovsxwq"),
+ &Opcode::VPMOVZXBD => write!(f, "vpmovzxbd"),
+ &Opcode::VPMOVZXBQ => write!(f, "vpmovzxbq"),
+ &Opcode::VPMOVZXBW => write!(f, "vpmovzxbw"),
+ &Opcode::VPMOVZXDQ => write!(f, "vpmovzxdq"),
+ &Opcode::VPMOVZXWD => write!(f, "vpmovzxwd"),
+ &Opcode::VPMOVZXWQ => write!(f, "vpmovzxwq"),
+ &Opcode::VPMULDQ => write!(f, "vpmuldq"),
+ &Opcode::VPMULHRSW => write!(f, "vpmulhrsw"),
+ &Opcode::VPMULHUW => write!(f, "vpmulhuw"),
+ &Opcode::VPMULHW => write!(f, "vpmulhw"),
+ &Opcode::VPMULLD => write!(f, "vpmulld"),
+ &Opcode::VPMULLW => write!(f, "vpmullw"),
+ &Opcode::VPMULUDQ => write!(f, "vpmuludq"),
+ &Opcode::VPOR => write!(f, "vpor"),
+ &Opcode::VPSADBW => write!(f, "vpsadbw"),
+ &Opcode::VPSHUFB => write!(f, "vpshufb"),
+ &Opcode::VPSHUFD => write!(f, "vpshufd"),
+ &Opcode::VPSIGNB => write!(f, "vpsignb"),
+ &Opcode::VPSIGND => write!(f, "vpsignd"),
+ &Opcode::VPSIGNW => write!(f, "vpsignw"),
+ &Opcode::VPSLLD => write!(f, "vpslld"),
+ &Opcode::VPSLLDQ => write!(f, "vpslldq"),
+ &Opcode::VPSLLQ => write!(f, "vpsllq"),
+ &Opcode::VPSLLVD => write!(f, "vpsllvd"),
+ &Opcode::VPSLLVQ => write!(f, "vpsllvq"),
+ &Opcode::VPSLLW => write!(f, "vpsllw"),
+ &Opcode::VPSRAD => write!(f, "vpsrad"),
+ &Opcode::VPSRAVD => write!(f, "vpsravd"),
+ &Opcode::VPSRAW => write!(f, "vpsraw"),
+ &Opcode::VPSRLD => write!(f, "vpsrld"),
+ &Opcode::VPSRLDQ => write!(f, "vpsrldq"),
+ &Opcode::VPSRLQ => write!(f, "vpsrlq"),
+ &Opcode::VPSRLVD => write!(f, "vpsrlvd"),
+ &Opcode::VPSRLVQ => write!(f, "vpsrlvq"),
+ &Opcode::VPSRLW => write!(f, "vpsrlw"),
+ &Opcode::VPSUBB => write!(f, "vpsubb"),
+ &Opcode::VPSUBD => write!(f, "vpsubd"),
+ &Opcode::VPSUBQ => write!(f, "vpsubq"),
+ &Opcode::VPSUBSB => write!(f, "vpsubsb"),
+ &Opcode::VPSUBSW => write!(f, "vpsubsw"),
+ &Opcode::VPSUBUSB => write!(f, "vpsubusb"),
+ &Opcode::VPSUBUSW => write!(f, "vpsubusw"),
+ &Opcode::VPSUBW => write!(f, "vpsubw"),
+ &Opcode::VPTEST => write!(f, "vptest"),
+ &Opcode::VPUNPCKHBW => write!(f, "vpunpckhbw"),
+ &Opcode::VPUNPCKHDQ => write!(f, "vpunpckhdq"),
+ &Opcode::VPUNPCKHQDQ => write!(f, "vpunpckhqdq"),
+ &Opcode::VPUNPCKHWD => write!(f, "vpunpckhwd"),
+ &Opcode::VPUNPCKLBW => write!(f, "vpunpcklbw"),
+ &Opcode::VPUNPCKLDQ => write!(f, "vpunpckldq"),
+ &Opcode::VPUNPCKLQDQ => write!(f, "vpunpcklqdq"),
+ &Opcode::VPUNPCKLWD => write!(f, "vpunpcklwd"),
+ &Opcode::VPXOR => write!(f, "vpxor"),
+ &Opcode::VRCPPS => write!(f, "vrcpps"),
+ &Opcode::VROUNDPD => write!(f, "vroundpd"),
+ &Opcode::VROUNDPS => write!(f, "vroundps"),
+ &Opcode::VRSQRTPS => write!(f, "vrsqrtps"),
+ &Opcode::VSHUFPD => write!(f, "vshufpd"),
+ &Opcode::VSHUFPS => write!(f, "vshufps"),
+ &Opcode::VSQRTPD => write!(f, "vsqrtpd"),
+ &Opcode::VSQRTPS => write!(f, "vsqrtps"),
+ &Opcode::VSUBPD => write!(f, "vsubpd"),
+ &Opcode::VSUBPS => write!(f, "vsubps"),
+ &Opcode::VTESTPD => write!(f, "vtestpd"),
+ &Opcode::VTESTPS => write!(f, "vtestps"),
+ &Opcode::VUNPCKHPD => write!(f, "vunpckhpd"),
+ &Opcode::VUNPCKHPS => write!(f, "vunpckhps"),
+ &Opcode::VUNPCKLPD => write!(f, "vunpcklpd"),
+ &Opcode::VUNPCKLPS => write!(f, "vunpcklps"),
+ &Opcode::VXORPD => write!(f, "vxorpd"),
+ &Opcode::VXORPS => write!(f, "vxorps"),
+ &Opcode::VZEROUPPER => write!(f, "vzeroupper"),
+ &Opcode::VMOVDDUP => write!(f, "vmovddup"),
+ &Opcode::VPSHUFLW => write!(f, "vpshuflw"),
+ &Opcode::VHADDPS => write!(f, "vhaddps"),
+ &Opcode::VHSUBPS => write!(f, "vhsubps"),
+ &Opcode::VADDSUBPS => write!(f, "vaddsubps"),
+ &Opcode::VCVTPD2DQ => write!(f, "vcvtpd2dq"),
+ &Opcode::VLDDQU => write!(f, "vlddqu"),
+ &Opcode::VADDSD => write!(f, "vaddsd"),
+ &Opcode::VADDSS => write!(f, "vaddss"),
+ &Opcode::VCMPSD => write!(f, "vcmpsd"),
+ &Opcode::VCMPSS => write!(f, "vcmpss"),
+ &Opcode::VCOMISD => write!(f, "vcomisd"),
+ &Opcode::VCOMISS => write!(f, "vcomiss"),
+ &Opcode::VCVTSD2SI => write!(f, "vcvtsd2si"),
+ &Opcode::VCVTSD2SS => write!(f, "vcvtsd2ss"),
+ &Opcode::VCVTSI2SD => write!(f, "vcvtsi2sd"),
+ &Opcode::VCVTSI2SS => write!(f, "vcvtsi2ss"),
+ &Opcode::VCVTSS2SD => write!(f, "vcvtss2sd"),
+ &Opcode::VCVTSS2SI => write!(f, "vcvtss2si"),
+ &Opcode::VCVTTSD2SI => write!(f, "vcvttsd2si"),
+ &Opcode::VCVTTSS2SI => write!(f, "vcvttss2si"),
+ &Opcode::VDIVSD => write!(f, "vdivsd"),
+ &Opcode::VDIVSS => write!(f, "vdivss"),
+ &Opcode::VFMADD132SD => write!(f, "vfmadd132sd"),
+ &Opcode::VFMADD132SS => write!(f, "vfmadd132ss"),
+ &Opcode::VFMADD213SD => write!(f, "vfmadd213sd"),
+ &Opcode::VFMADD213SS => write!(f, "vfmadd213ss"),
+ &Opcode::VFMADD231SD => write!(f, "vfmadd231sd"),
+ &Opcode::VFMADD231SS => write!(f, "vfmadd231ss"),
+ &Opcode::VFMSUB132SD => write!(f, "vfmsub132sd"),
+ &Opcode::VFMSUB132SS => write!(f, "vfmsub132ss"),
+ &Opcode::VFMSUB213SD => write!(f, "vfmsub213sd"),
+ &Opcode::VFMSUB213SS => write!(f, "vfmsub213ss"),
+ &Opcode::VFMSUB231SD => write!(f, "vfmsub231sd"),
+ &Opcode::VFMSUB231SS => write!(f, "vfmsub231ss"),
+ &Opcode::VFNMADD132SD => write!(f, "vfnmadd132sd"),
+ &Opcode::VFNMADD132SS => write!(f, "vfnmadd132ss"),
+ &Opcode::VFNMADD213SD => write!(f, "vfnmadd213sd"),
+ &Opcode::VFNMADD213SS => write!(f, "vfnmadd213ss"),
+ &Opcode::VFNMADD231SD => write!(f, "vfnmadd231sd"),
+ &Opcode::VFNMADD231SS => write!(f, "vfnmadd231ss"),
+ &Opcode::VFNMSUB132SD => write!(f, "vfnmsub132sd"),
+ &Opcode::VFNMSUB132SS => write!(f, "vfnmsub132ss"),
+ &Opcode::VFNMSUB213SD => write!(f, "vfnmsub213sd"),
+ &Opcode::VFNMSUB213SS => write!(f, "vfnmsub213ss"),
+ &Opcode::VFNMSUB231SD => write!(f, "vfnmsub231sd"),
+ &Opcode::VFNMSUB231SS => write!(f, "vfnmsub231ss"),
+ &Opcode::VMAXSD => write!(f, "vmaxsd"),
+ &Opcode::VMAXSS => write!(f, "vmaxss"),
+ &Opcode::VMINSD => write!(f, "vminsd"),
+ &Opcode::VMINSS => write!(f, "vminss"),
+ &Opcode::VMOVSD => write!(f, "vmovsd"),
+ &Opcode::VMOVSS => write!(f, "vmovss"),
+ &Opcode::VMULSD => write!(f, "vmulsd"),
+ &Opcode::VMULSS => write!(f, "vmulss"),
+ &Opcode::VRCPSS => write!(f, "vrcpss"),
+ &Opcode::VROUNDSD => write!(f, "vroundsd"),
+ &Opcode::VROUNDSS => write!(f, "vroundss"),
+ &Opcode::VRSQRTSS => write!(f, "vrsqrtss"),
+ &Opcode::VSQRTSD => write!(f, "vsqrtsd"),
+ &Opcode::VSQRTSS => write!(f, "vsqrtss"),
+ &Opcode::VSUBSD => write!(f, "vsubsd"),
+ &Opcode::VSUBSS => write!(f, "vsubss"),
+ &Opcode::VUCOMISD => write!(f, "vucomisd"),
+ &Opcode::VUCOMISS => write!(f, "vucomiss"),
+ &Opcode::PCLMULQDQ => write!(f, "pclmulqdq"),
+ &Opcode::AESKEYGENASSIST => write!(f, "aeskeygenassist"),
+ &Opcode::AESIMC => write!(f, "aesimc"),
+ &Opcode::AESENC => write!(f, "aesenc"),
+ &Opcode::AESENCLAST => write!(f, "aesenclast"),
+ &Opcode::AESDEC => write!(f, "aesdec"),
+ &Opcode::AESDECLAST => write!(f, "aesdeclast"),
+ &Opcode::PCMPGTQ => write!(f, "pcmpgtq"),
+ &Opcode::PCMPISTRM => write!(f, "pcmpistrm"),
+ &Opcode::PCMPISTRI => write!(f, "pcmpistri"),
+ &Opcode::PCMPESTRI => write!(f, "pcmpestri"),
+ &Opcode::PACKUSDW => write!(f, "packusdw"),
+ &Opcode::PCMPESTRM => write!(f, "pcmpestrm"),
+ &Opcode::PCMPEQQ => write!(f, "pcmpeqq"),
+ &Opcode::PTEST => write!(f, "ptest"),
+ &Opcode::PHMINPOSUW => write!(f, "phminposuw"),
+ &Opcode::MPSADBW => write!(f, "mpsadbw"),
+ &Opcode::PMOVZXDQ => write!(f, "pmovzxdq"),
+ &Opcode::PMOVSXDQ => write!(f, "pmovsxdq"),
+ &Opcode::PMOVZXBD => write!(f, "pmovzxbd"),
+ &Opcode::PMOVSXBD => write!(f, "pmovsxbd"),
+ &Opcode::PMOVZXWQ => write!(f, "pmovzxwq"),
+ &Opcode::PMOVSXWQ => write!(f, "pmovsxwq"),
+ &Opcode::PMOVZXBQ => write!(f, "pmovzxbq"),
+ &Opcode::PMOVSXBQ => write!(f, "pmovsxbq"),
+ &Opcode::PMOVSXWD => write!(f, "pmovsxwd"),
+ &Opcode::PMOVZXWD => write!(f, "pmovzxwd"),
+ &Opcode::PEXTRQ => write!(f, "pextrq"),
+ &Opcode::PEXTRB => write!(f, "pextrb"),
+ &Opcode::PMOVSXBW => write!(f, "pmovsxbw"),
+ &Opcode::PMOVZXBW => write!(f, "pmovzxbw"),
+ &Opcode::PINSRQ => write!(f, "pinsrq"),
+ &Opcode::PINSRD => write!(f, "pinsrd"),
+ &Opcode::PINSRB => write!(f, "pinsrb"),
+ &Opcode::EXTRACTPS => write!(f, "extractps"),
+ &Opcode::INSERTPS => write!(f, "insertps"),
+ &Opcode::ROUNDSS => write!(f, "roundss"),
+ &Opcode::ROUNDSD => write!(f, "roundsd"),
+ &Opcode::ROUNDPS => write!(f, "roundps"),
+ &Opcode::ROUNDPD => write!(f, "roundpd"),
+ &Opcode::PMAXSB => write!(f, "pmaxsb"),
+ &Opcode::PMAXUW => write!(f, "pmaxuw"),
+ &Opcode::PMAXUD => write!(f, "pmaxud"),
+ &Opcode::PMINSD => write!(f, "pminsd"),
+ &Opcode::PMINSB => write!(f, "pminsb"),
+ &Opcode::PMINUD => write!(f, "pminud"),
+ &Opcode::PMINUW => write!(f, "pminuw"),
+ &Opcode::BLENDW => write!(f, "blendw"),
+ &Opcode::BLENDDVB => write!(f, "blenddvb"),
+ &Opcode::BLENDVPS => write!(f, "blendvps"),
+ &Opcode::BLENDVPD => write!(f, "blendvpd"),
+ &Opcode::BLENDPS => write!(f, "blendps"),
+ &Opcode::BLENDPD => write!(f, "blendpd"),
+ &Opcode::PMULDQ => write!(f, "pmuldq"),
+ &Opcode::MOVNTDQA => write!(f, "movntdqa"),
+ &Opcode::PMULLD => write!(f, "pmulld"),
+ &Opcode::PALIGNR => write!(f, "palignr"),
+ &Opcode::PSIGNW => write!(f, "psignw"),
+ &Opcode::PSIGND => write!(f, "psignd"),
+ &Opcode::PSIGNB => write!(f, "psignb"),
+ &Opcode::PSHUFB => write!(f, "pshufb"),
+ &Opcode::PMULHRSU => write!(f, "pmulhrsu"),
+ &Opcode::PMADDUBSW => write!(f, "pmaddubsw"),
+ &Opcode::PABSD => write!(f, "pabsd"),
+ &Opcode::PABSW => write!(f, "pabsw"),
+ &Opcode::PABSB => write!(f, "pabsb"),
+ &Opcode::PHSUBSW => write!(f, "phsubsw"),
+ &Opcode::PHSUBW => write!(f, "phsubw"),
+ &Opcode::PHSUBD => write!(f, "phsubd"),
+ &Opcode::PHADDD => write!(f, "phaddd"),
+ &Opcode::PHADDSW => write!(f, "phaddsw"),
+ &Opcode::PHADDW => write!(f, "phaddw"),
+ &Opcode::HSUBPD => write!(f, "hsubpd"),
+ &Opcode::HADDPD => write!(f, "haddpd"),
+ &Opcode::ADDSUBPD => write!(f, "addsubpd"),
+ &Opcode::Invalid => write!(f, "invalid"),
+ }
+ }
+}
+
+impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color, Y> for Opcode {
+ fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result {
+ match self {
+ Opcode::VHADDPS |
+ Opcode::VHSUBPS |
+ Opcode::VADDSUBPS |
+ Opcode::VADDPD |
+ Opcode::VADDPS |
+ Opcode::VADDSD |
+ Opcode::VADDSS |
+ Opcode::VADDSUBPD |
+ Opcode::VFMADD132PD |
+ Opcode::VFMADD132PS |
+ Opcode::VFMADD132SD |
+ Opcode::VFMADD132SS |
+ Opcode::VFMADD213PD |
+ Opcode::VFMADD213PS |
+ Opcode::VFMADD213SD |
+ Opcode::VFMADD213SS |
+ Opcode::VFMADD231PD |
+ Opcode::VFMADD231PS |
+ Opcode::VFMADD231SD |
+ Opcode::VFMADD231SS |
+ Opcode::VFMADDSUB132PD |
+ Opcode::VFMADDSUB132PS |
+ Opcode::VFMADDSUB213PD |
+ Opcode::VFMADDSUB213PS |
+ Opcode::VFMADDSUB231PD |
+ Opcode::VFMADDSUB231PS |
+ Opcode::VFMSUB132PD |
+ Opcode::VFMSUB132PS |
+ Opcode::VFMSUB132SD |
+ Opcode::VFMSUB132SS |
+ Opcode::VFMSUB213PD |
+ Opcode::VFMSUB213PS |
+ Opcode::VFMSUB213SD |
+ Opcode::VFMSUB213SS |
+ Opcode::VFMSUB231PD |
+ Opcode::VFMSUB231PS |
+ Opcode::VFMSUB231SD |
+ Opcode::VFMSUB231SS |
+ Opcode::VFMSUBADD132PD |
+ Opcode::VFMSUBADD132PS |
+ Opcode::VFMSUBADD213PD |
+ Opcode::VFMSUBADD213PS |
+ Opcode::VFMSUBADD231PD |
+ Opcode::VFMSUBADD231PS |
+ Opcode::VFNMADD132PD |
+ Opcode::VFNMADD132PS |
+ Opcode::VFNMADD132SD |
+ Opcode::VFNMADD132SS |
+ Opcode::VFNMADD213PD |
+ Opcode::VFNMADD213PS |
+ Opcode::VFNMADD213SD |
+ Opcode::VFNMADD213SS |
+ Opcode::VFNMADD231PD |
+ Opcode::VFNMADD231PS |
+ Opcode::VFNMADD231SD |
+ Opcode::VFNMADD231SS |
+ Opcode::VFNMSUB132PD |
+ Opcode::VFNMSUB132PS |
+ Opcode::VFNMSUB132SD |
+ Opcode::VFNMSUB132SS |
+ Opcode::VFNMSUB213PD |
+ Opcode::VFNMSUB213PS |
+ Opcode::VFNMSUB213SD |
+ Opcode::VFNMSUB213SS |
+ Opcode::VFNMSUB231PD |
+ Opcode::VFNMSUB231PS |
+ Opcode::VFNMSUB231SD |
+ Opcode::VFNMSUB231SS |
+ Opcode::VDIVPD |
+ Opcode::VDIVPS |
+ Opcode::VDIVSD |
+ Opcode::VDIVSS |
+ Opcode::VHADDPD |
+ Opcode::VHSUBPD |
+ Opcode::HADDPD |
+ Opcode::HSUBPD |
+ Opcode::VMULPD |
+ Opcode::VMULPS |
+ Opcode::VMULSD |
+ Opcode::VMULSS |
+ Opcode::VPABSB |
+ Opcode::VPABSD |
+ Opcode::VPABSW |
+ Opcode::PABSB |
+ Opcode::PABSD |
+ Opcode::PABSW |
+ Opcode::VPSIGNB |
+ Opcode::VPSIGND |
+ Opcode::VPSIGNW |
+ Opcode::PSIGNB |
+ Opcode::PSIGND |
+ Opcode::PSIGNW |
+ Opcode::VPADDB |
+ Opcode::VPADDD |
+ Opcode::VPADDQ |
+ Opcode::VPADDSB |
+ Opcode::VPADDSW |
+ Opcode::VPADDUSB |
+ Opcode::VPADDUSW |
+ Opcode::VPADDW |
+ Opcode::VPAVGB |
+ Opcode::VPAVGW |
+ Opcode::VPMULDQ |
+ Opcode::VPMULHRSW |
+ Opcode::VPMULHUW |
+ Opcode::VPMULHW |
+ Opcode::VPMULLD |
+ Opcode::VPMULLW |
+ Opcode::VPMULUDQ |
+ Opcode::PCLMULQDQ |
+ Opcode::PMULDQ |
+ Opcode::PMULHRSU |
+ Opcode::PMULLD |
+ Opcode::VPSUBB |
+ Opcode::VPSUBD |
+ Opcode::VPSUBQ |
+ Opcode::VPSUBSB |
+ Opcode::VPSUBSW |
+ Opcode::VPSUBUSB |
+ Opcode::VPSUBUSW |
+ Opcode::VPSUBW |
+ Opcode::VROUNDPD |
+ Opcode::VROUNDPS |
+ Opcode::VRSQRTPS |
+ Opcode::VSQRTPD |
+ Opcode::VSQRTPS |
+ Opcode::VSUBPD |
+ Opcode::VSUBPS |
+ Opcode::VSUBSD |
+ Opcode::VSUBSS |
+ Opcode::VRCPSS |
+ Opcode::VROUNDSD |
+ Opcode::VROUNDSS |
+ Opcode::ROUNDPD |
+ Opcode::ROUNDPS |
+ Opcode::ROUNDSD |
+ Opcode::ROUNDSS |
+ Opcode::VRSQRTSS |
+ Opcode::VSQRTSD |
+ Opcode::VSQRTSS |
+ Opcode::VPSADBW |
+ Opcode::VMPSADBW |
+ Opcode::VPHADDD |
+ Opcode::VPHADDSW |
+ Opcode::VPHADDW |
+ Opcode::VPHSUBD |
+ Opcode::VPHSUBSW |
+ Opcode::VPHSUBW |
+ Opcode::VPHADDUBSW |
+ Opcode::VPMADDWD |
+ Opcode::VDPPD |
+ Opcode::VDPPS |
+ Opcode::VRCPPS |
+ Opcode::VPAND |
+ Opcode::VPANDN |
+ Opcode::VPOR |
+ Opcode::VPXOR |
+ Opcode::VXORPD |
+ Opcode::VXORPS |
+ Opcode::VPSLLD |
+ Opcode::VPSLLDQ |
+ Opcode::VPSLLQ |
+ Opcode::VPSLLVD |
+ Opcode::VPSLLVQ |
+ Opcode::VPSLLW |
+ Opcode::VPSRAD |
+ Opcode::VPSRAVD |
+ Opcode::VPSRAW |
+ Opcode::VPSRLD |
+ Opcode::VPSRLDQ |
+ Opcode::VPSRLQ |
+ Opcode::VPSRLVD |
+ Opcode::VPSRLVQ |
+ Opcode::VPSRLW |
+ Opcode::PHADDD |
+ Opcode::PHADDSW |
+ Opcode::PHADDW |
+ Opcode::PHSUBD |
+ Opcode::PHSUBSW |
+ Opcode::PHSUBW |
+ Opcode::PMADDUBSW |
+ Opcode::ADDSUBPD |
+ Opcode::MPSADBW |
+ Opcode::RCPSS |
+ Opcode::RSQRTSS |
+ Opcode::SQRTSD |
+ Opcode::ADDSD |
+ Opcode::SUBSD |
+ Opcode::MULSD |
+ Opcode::DIVSD |
+ Opcode::SQRTSS |
+ Opcode::ADDSS |
+ Opcode::SUBSS |
+ Opcode::MULSS |
+ Opcode::DIVSS |
+ Opcode::HADDPS |
+ Opcode::HSUBPS |
+ Opcode::ADDSUBPS |
+ Opcode::XADD|
+ Opcode::DIV |
+ Opcode::IDIV |
+ Opcode::MUL |
+ Opcode::NEG |
+ Opcode::NOT |
+ Opcode::SAR |
+ Opcode::SAL |
+ Opcode::SHR |
+ Opcode::SHRD |
+ Opcode::SHL |
+ Opcode::RCR |
+ Opcode::RCL |
+ Opcode::ROR |
+ Opcode::ROL |
+ Opcode::INC |
+ Opcode::DEC |
+ Opcode::SBB |
+ Opcode::AND |
+ Opcode::XOR |
+ Opcode::OR |
+ Opcode::LEA |
+ Opcode::ADD |
+ Opcode::ADC |
+ Opcode::SUB |
+ Opcode::POPCNT |
+ Opcode::BT |
+ Opcode::BTS |
+ Opcode::BTR |
+ Opcode::BTC |
+ Opcode::BSF |
+ Opcode::BSR |
+ Opcode::TZCNT |
+ Opcode::ANDN |
+ Opcode::BEXTR |
+ Opcode::BLSI |
+ Opcode::BLSMSK |
+ Opcode::BLSR |
+ Opcode::ADDPS |
+ Opcode::ADDPD |
+ Opcode::ANDNPS |
+ Opcode::ANDNPD |
+ Opcode::ANDPS |
+ Opcode::ANDPD |
+ Opcode::COMISD |
+ Opcode::COMISS |
+ Opcode::DIVPS |
+ Opcode::DIVPD |
+ Opcode::MULPS |
+ Opcode::MULPD |
+ Opcode::ORPS |
+ Opcode::ORPD |
+ Opcode::PADDB |
+ Opcode::PADDD |
+ Opcode::PADDQ |
+ Opcode::PADDSB |
+ Opcode::PADDSW |
+ Opcode::PADDUSB |
+ Opcode::PADDUSW |
+ Opcode::PADDW |
+ Opcode::PAND |
+ Opcode::PANDN |
+ Opcode::PAVGB |
+ Opcode::PAVGW |
+ Opcode::PMADDWD |
+ Opcode::PMULHUW |
+ Opcode::PMULHW |
+ Opcode::PMULLW |
+ Opcode::PMULUDQ |
+ Opcode::POR |
+ Opcode::PSADBW |
+ Opcode::PSHUFD |
+ Opcode::PSHUFW |
+ Opcode::PSHUFB |
+ Opcode::PSLLD |
+ Opcode::PSLLDQ |
+ Opcode::PSLLQ |
+ Opcode::PSLLW |
+ Opcode::PSRAD |
+ Opcode::PSRAW |
+ Opcode::PSRLD |
+ Opcode::PSRLDQ |
+ Opcode::PSRLQ |
+ Opcode::PSRLW |
+ Opcode::PSUBB |
+ Opcode::PSUBD |
+ Opcode::PSUBQ |
+ Opcode::PSUBSB |
+ Opcode::PSUBSW |
+ Opcode::PSUBUSB |
+ Opcode::PSUBUSW |
+ Opcode::PSUBW |
+ Opcode::PXOR |
+ Opcode::RSQRTPS |
+ Opcode::SQRTPS |
+ Opcode::SQRTPD |
+ Opcode::SUBPS |
+ Opcode::SUBPD |
+ Opcode::XORPS |
+ Opcode::XORPD |
+ Opcode::RCPPS |
+ Opcode::SHLD |
+ Opcode::SLHD |
+ Opcode::UCOMISD |
+ Opcode::UCOMISS |
+ Opcode::IMUL => { write!(out, "{}", colors.arithmetic_op(self)) }
+ Opcode::POPF |
+ Opcode::PUSHF |
+ Opcode::ENTER |
+ Opcode::LEAVE |
+ Opcode::PUSH |
+ Opcode::POP => { write!(out, "{}", colors.stack_op(self)) }
+ Opcode::WAIT |
+ Opcode::PREFETCHNTA |
+ Opcode::PREFETCH0 |
+ Opcode::PREFETCH1 |
+ Opcode::PREFETCH2 |
+ Opcode::NOP => { write!(out, "{}", colors.nop_op(self)) }
+
+ /* Control flow */
+ Opcode::HLT |
+ Opcode::INT |
+ Opcode::INTO |
+ Opcode::IRET |
+ Opcode::RETF |
+ Opcode::RETURN => { write!(out, "{}", colors.stop_op(self)) }
+ Opcode::CALL |
+ Opcode::CALLF |
+ Opcode::JMP |
+ Opcode::JMPF |
+ Opcode::JO |
+ Opcode::JNO |
+ Opcode::JB |
+ Opcode::JNB |
+ Opcode::JZ |
+ Opcode::JNZ |
+ Opcode::JA |
+ Opcode::JNA |
+ Opcode::JS |
+ Opcode::JNS |
+ Opcode::JP |
+ Opcode::JNP |
+ Opcode::JL |
+ Opcode::JGE |
+ Opcode::JLE |
+ Opcode::JG => { write!(out, "{}", colors.control_flow_op(self)) }
+
+ /* Data transfer */
+ Opcode::VCVTDQ2PD |
+ Opcode::VCVTDQ2PS |
+ Opcode::VCVTPD2DQ |
+ Opcode::VCVTPD2PS |
+ Opcode::VCVTPH2PS |
+ Opcode::VCVTPS2DQ |
+ Opcode::VCVTPS2PD |
+ Opcode::VCVTPS2PH |
+ Opcode::VCVTTPD2DQ |
+ Opcode::VCVTTPS2DQ |
+ Opcode::VCVTSD2SI |
+ Opcode::VCVTSD2SS |
+ Opcode::VCVTSI2SD |
+ Opcode::VCVTSI2SS |
+ Opcode::VCVTSS2SD |
+ Opcode::VCVTSS2SI |
+ Opcode::VCVTTSD2SI |
+ Opcode::VCVTTSS2SI |
+ Opcode::VMOVDDUP |
+ Opcode::VPSHUFLW |
+ Opcode::VBLENDPD |
+ Opcode::VBLENDPS |
+ Opcode::VBLENDVPD |
+ Opcode::VBLENDVPS |
+ Opcode::BLENDDVB |
+ Opcode::BLENDPD |
+ Opcode::BLENDPS |
+ Opcode::BLENDVPD |
+ Opcode::BLENDVPS |
+ Opcode::BLENDW |
+ Opcode::VBROADCASTF128 |
+ Opcode::VBROADCASTI128 |
+ Opcode::VBROADCASTSD |
+ Opcode::VBROADCASTSS |
+ Opcode::VEXTRACTF128 |
+ Opcode::VEXTRACTI128 |
+ Opcode::VEXTRACTPS |
+ Opcode::EXTRACTPS |
+ Opcode::VGATHERDPD |
+ Opcode::VGATHERDPS |
+ Opcode::VGATHERQPD |
+ Opcode::VGATHERQPS |
+ Opcode::VINSERTF128 |
+ Opcode::VINSERTI128 |
+ Opcode::VINSERTPS |
+ Opcode::INSERTPS |
+ Opcode::VMASKMOVDQU |
+ Opcode::VMASKMOVPD |
+ Opcode::VMASKMOVPS |
+ Opcode::VMOVAPD |
+ Opcode::VMOVAPS |
+ Opcode::VMOVD |
+ Opcode::VMOVDQA |
+ Opcode::VMOVDQU |
+ Opcode::VMOVHLPS |
+ Opcode::VMOVHPD |
+ Opcode::VMOVHPS |
+ Opcode::VMOVLHPS |
+ Opcode::VMOVLPD |
+ Opcode::VMOVLPS |
+ Opcode::VMOVMSKPD |
+ Opcode::VMOVMSKPS |
+ Opcode::VMOVNTDQ |
+ Opcode::VMOVNTDQA |
+ Opcode::VMOVNTPD |
+ Opcode::VMOVNTPS |
+ Opcode::MOVNTDQA |
+ Opcode::VMOVQ |
+ Opcode::VMOVSHDUP |
+ Opcode::VMOVSLDUP |
+ Opcode::VMOVUPD |
+ Opcode::VMOVUPS |
+ Opcode::VMOVSD |
+ Opcode::VMOVSS |
+
+ Opcode::VPBLENDD |
+ Opcode::VPBLENDVB |
+ Opcode::VPBLENDW |
+ Opcode::VPBROADCASTB |
+ Opcode::VPBROADCASTD |
+ Opcode::VPBROADCASTQ |
+ Opcode::VPBROADCASTW |
+ Opcode::VPGATHERDD |
+ Opcode::VPGATHERDQ |
+ Opcode::VPGATHERQD |
+ Opcode::VPGATHERQQ |
+ Opcode::VPCLMULQDQ |
+ Opcode::VPMOVMSKB |
+ Opcode::VPMOVSXBD |
+ Opcode::VPMOVSXBQ |
+ Opcode::VPMOVSXBW |
+ Opcode::VPMOVSXDQ |
+ Opcode::VPMOVSXWD |
+ Opcode::VPMOVSXWQ |
+ Opcode::VPMOVZXBD |
+ Opcode::VPMOVZXBQ |
+ Opcode::VPMOVZXBW |
+ Opcode::VPMOVZXDQ |
+ Opcode::VPMOVZXWD |
+ Opcode::VPMOVZXWQ |
+ Opcode::PMOVSXBD |
+ Opcode::PMOVSXBQ |
+ Opcode::PMOVSXBW |
+ Opcode::PMOVSXDQ |
+ Opcode::PMOVSXWD |
+ Opcode::PMOVSXWQ |
+ Opcode::PMOVZXBD |
+ Opcode::PMOVZXBQ |
+ Opcode::PMOVZXBW |
+ Opcode::PMOVZXDQ |
+ Opcode::PMOVZXWD |
+ Opcode::PMOVZXWQ |
+ Opcode::VUNPCKHPD |
+ Opcode::VUNPCKHPS |
+ Opcode::VUNPCKLPD |
+ Opcode::VUNPCKLPS |
+ Opcode::VPUNPCKHBW |
+ Opcode::VPUNPCKHDQ |
+ Opcode::VPUNPCKHQDQ |
+ Opcode::VPUNPCKHWD |
+ Opcode::VPUNPCKLBW |
+ Opcode::VPUNPCKLDQ |
+ Opcode::VPUNPCKLQDQ |
+ Opcode::VPUNPCKLWD |
+ Opcode::VSHUFPD |
+ Opcode::VSHUFPS |
+ Opcode::VPACKSSDW |
+ Opcode::PACKUSDW |
+ Opcode::VPACKSSWB |
+ Opcode::VPACKUSWB |
+ Opcode::VPALIGNR |
+ Opcode::PALIGNR |
+ Opcode::VPERM2F128 |
+ Opcode::VPERM2I128 |
+ Opcode::VPERMD |
+ Opcode::VPERMILPD |
+ Opcode::VPERMILPS |
+ Opcode::VPERMPD |
+ Opcode::VPERMPS |
+ Opcode::VPERMQ |
+ Opcode::VPEXTRB |
+ Opcode::VPEXTRD |
+ Opcode::VPEXTRQ |
+ Opcode::VPEXTRW |
+ Opcode::PEXTRB |
+ Opcode::PEXTRQ |
+ Opcode::PINSRB |
+ Opcode::PINSRD |
+ Opcode::PINSRQ |
+ Opcode::VPINSRB |
+ Opcode::VPINSRD |
+ Opcode::VPINSRQ |
+ Opcode::VPINSRW |
+ Opcode::VPMASKMOVD |
+ Opcode::VPMASKMOVQ |
+ Opcode::VPSHUFB |
+ Opcode::VPSHUFD |
+ Opcode::VPHMINPOSUW |
+ Opcode::PHMINPOSUW |
+ Opcode::VZEROUPPER |
+ Opcode::VLDDQU |
+ Opcode::BSWAP |
+ Opcode::CVTDQ2PD |
+ Opcode::CVTDQ2PS |
+ Opcode::CVTPS2DQ |
+ Opcode::CVTPD2DQ |
+ Opcode::CVTPI2PS |
+ Opcode::CVTPI2PD |
+ Opcode::CVTPS2PD |
+ Opcode::CVTPD2PS |
+ Opcode::CVTPS2PI |
+ Opcode::CVTPD2PI |
+ Opcode::CVTSD2SI |
+ Opcode::CVTSD2SS |
+ Opcode::CVTSI2SD |
+ Opcode::CVTSI2SS |
+ Opcode::CVTSS2SD |
+ Opcode::CVTSS2SI |
+ Opcode::CVTTPD2DQ |
+ Opcode::CVTTPS2DQ |
+ Opcode::CVTTPS2PI |
+ Opcode::CVTTPD2PI |
+ Opcode::CVTTSD2SI |
+ Opcode::CVTTSS2SI |
+ Opcode::MASKMOVQ |
+ Opcode::MASKMOVDQU |
+ Opcode::MOVAPS |
+ Opcode::MOVAPD |
+ Opcode::MOVD |
+ Opcode::MOVHPS |
+ Opcode::MOVHPD |
+ Opcode::MOVHLPS |
+ Opcode::MOVLPS |
+ Opcode::MOVLPD |
+ Opcode::MOVLHPS |
+ Opcode::MOVMSKPS |
+ Opcode::MOVMSKPD |
+ Opcode::MOVNTI |
+ Opcode::MOVNTPS |
+ Opcode::MOVNTPD |
+ Opcode::MOVNTQ |
+ Opcode::MOVNTDQ |
+ Opcode::MOVSD |
+ Opcode::MOVSS |
+ Opcode::MOVUPD |
+ Opcode::PSHUFHW |
+ Opcode::PSHUFLW |
+ Opcode::PUNPCKHBW |
+ Opcode::PUNPCKHDQ |
+ Opcode::PUNPCKHWD |
+ Opcode::PUNPCKLBW |
+ Opcode::PUNPCKLDQ |
+ Opcode::PUNPCKLWD |
+ Opcode::PUNPCKLQDQ |
+ Opcode::PUNPCKHQDQ |
+ Opcode::PACKSSDW |
+ Opcode::PACKSSWB |
+ Opcode::PACKUSWB |
+ Opcode::UNPCKHPS |
+ Opcode::UNPCKHPD |
+ Opcode::UNPCKLPS |
+ Opcode::UNPCKLPD |
+ Opcode::SHUFPD |
+ Opcode::SHUFPS |
+ Opcode::PMOVMSKB |
+ Opcode::LDDQU |
+ Opcode::CLC |
+ Opcode::CLI |
+ Opcode::CLD |
+ Opcode::STC |
+ Opcode::STI |
+ Opcode::STD |
+ Opcode::CBW |
+ Opcode::CWDE |
+ Opcode::CDQE |
+ Opcode::CBD |
+ Opcode::CDQ |
+ Opcode::CQO |
+ Opcode::MOVDDUP |
+ Opcode::MOVSLDUP |
+ Opcode::MOVDQ2Q |
+ Opcode::MOVDQU |
+ Opcode::MOVDQA |
+ Opcode::MOVQ |
+ Opcode::MOVQ2DQ |
+ Opcode::MOVSHDUP |
+ Opcode::MOVUPS |
+ Opcode::PEXTRW |
+ Opcode::PINSRW |
+ Opcode::MOV |
+ Opcode::LODS |
+ Opcode::STOS |
+ Opcode::LAHF |
+ Opcode::SAHF |
+ Opcode::MOVS |
+ Opcode::INS |
+ Opcode::IN |
+ Opcode::OUTS |
+ Opcode::OUT |
+ Opcode::MOVSX_b |
+ Opcode::MOVSX_w |
+ Opcode::MOVZX_b |
+ Opcode::MOVZX_w |
+ Opcode::MOVSX |
+ Opcode::XCHG |
+ Opcode::CMOVA |
+ Opcode::CMOVB |
+ Opcode::CMOVG |
+ Opcode::CMOVGE |
+ Opcode::CMOVL |
+ Opcode::CMOVLE |
+ Opcode::CMOVNA |
+ Opcode::CMOVNB |
+ Opcode::CMOVNO |
+ Opcode::CMOVNP |
+ Opcode::CMOVNS |
+ Opcode::CMOVNZ |
+ Opcode::CMOVO |
+ Opcode::CMOVP |
+ Opcode::CMOVS |
+ Opcode::CMOVZ |
+ Opcode::SETO |
+ Opcode::SETNO |
+ Opcode::SETB |
+ Opcode::SETAE |
+ Opcode::SETZ |
+ Opcode::SETNZ |
+ Opcode::SETBE |
+ Opcode::SETA |
+ Opcode::SETS |
+ Opcode::SETNS |
+ Opcode::SETP |
+ Opcode::SETNP |
+ Opcode::SETL |
+ Opcode::SETGE |
+ Opcode::SETLE |
+ Opcode::SETG => { write!(out, "{}", colors.data_op(self)) }
+
+ Opcode::VCOMISD |
+ Opcode::VCOMISS |
+ Opcode::VUCOMISD |
+ Opcode::VUCOMISS |
+ Opcode::VCMPPD |
+ Opcode::VCMPPS |
+ Opcode::VCMPSD |
+ Opcode::VCMPSS |
+ Opcode::VMAXPD |
+ Opcode::VMAXPS |
+ Opcode::VMAXSD |
+ Opcode::VMAXSS |
+ Opcode::VMINPD |
+ Opcode::VMINPS |
+ Opcode::VMINSD |
+ Opcode::VMINSS |
+ Opcode::VPCMPEQB |
+ Opcode::VPCMPEQD |
+ Opcode::VPCMPEQQ |
+ Opcode::VPCMPEQW |
+ Opcode::VPCMPGTB |
+ Opcode::VPCMPGTD |
+ Opcode::VPCMPGTQ |
+ Opcode::VPCMPGTW |
+ Opcode::VPCMPISTRI |
+ Opcode::VPCMPISTRM |
+ Opcode::VPMAXSB |
+ Opcode::VPMAXSD |
+ Opcode::VPMAXSW |
+ Opcode::VPMAXUD |
+ Opcode::VPMINSD |
+ Opcode::VPMINUD |
+ Opcode::VPTEST |
+ Opcode::VTESTPD |
+ Opcode::VTESTPS |
+ Opcode::PCMPEQB |
+ Opcode::PCMPEQD |
+ Opcode::PCMPEQQ |
+ Opcode::PCMPEQW |
+ Opcode::PCMPESTRI |
+ Opcode::PCMPESTRM |
+ Opcode::PCMPGTB |
+ Opcode::PCMPGTD |
+ Opcode::PCMPGTQ |
+ Opcode::PCMPGTW |
+ Opcode::PCMPISTRI |
+ Opcode::PCMPISTRM |
+ Opcode::PTEST |
+ Opcode::MAXPD |
+ Opcode::MAXPS |
+ Opcode::MAXSD |
+ Opcode::MAXSS |
+ Opcode::MINPD |
+ Opcode::MINPS |
+ Opcode::MINSD |
+ Opcode::MINSS |
+ Opcode::PMAXSB |
+ Opcode::PMAXSW |
+ Opcode::PMAXUB |
+ Opcode::PMAXUD |
+ Opcode::PMAXUW |
+ Opcode::PMINSB |
+ Opcode::PMINSD |
+ Opcode::PMINSW |
+ Opcode::PMINUB |
+ Opcode::PMINUD |
+ Opcode::PMINUW |
+ Opcode::CMPS |
+ Opcode::SCAS |
+ Opcode::TEST |
+ Opcode::CMPSD |
+ Opcode::CMPSS |
+ Opcode::CMP |
+ Opcode::CMPPS |
+ Opcode::CMPPD |
+ Opcode::CMPXCHG => { write!(out, "{}", colors.comparison_op(self)) }
+
+ Opcode::WRMSR |
+ Opcode::RDMSR |
+ Opcode::RDTSC |
+ Opcode::RDPMC |
+ Opcode::FXSAVE |
+ Opcode::FXRSTOR |
+ Opcode::LDMXCSR |
+ Opcode::STMXCSR |
+ Opcode::XSAVE |
+ Opcode::XRSTOR |
+ Opcode::XSAVEOPT |
+ Opcode::LFENCE |
+ Opcode::MFENCE |
+ Opcode::SFENCE |
+ Opcode::CLFLUSH |
+ Opcode::LDS |
+ Opcode::LES |
+ Opcode::SGDT |
+ Opcode::SIDT |
+ Opcode::LGDT |
+ Opcode::LIDT |
+ Opcode::SMSW |
+ Opcode::LMSW |
+ Opcode::SWAPGS |
+ Opcode::RDTSCP |
+ Opcode::INVLPG |
+ Opcode::CPUID |
+ Opcode::WBINVD |
+ Opcode::INVD |
+ Opcode::SYSRET |
+ Opcode::CLTS |
+ Opcode::SYSCALL |
+ Opcode::LSL |
+ Opcode::SLDT |
+ Opcode::STR |
+ Opcode::LLDT |
+ Opcode::LTR |
+ Opcode::VERR |
+ Opcode::VERW |
+ Opcode::JMPE |
+ Opcode::EMMS |
+ Opcode::GETSEC |
+ Opcode::LFS |
+ Opcode::LGS |
+ Opcode::LSS |
+ Opcode::ARPL |
+ Opcode::RSM |
+ Opcode::SYSENTER |
+ Opcode::SYSEXIT |
+ Opcode::UD2E |
+ Opcode::VMREAD |
+ Opcode::VMWRITE |
+ Opcode::VMCLEAR |
+ Opcode::VMXON |
+ Opcode::VMCALL |
+ Opcode::VMLAUNCH |
+ Opcode::VMRESUME |
+ Opcode::VMXOFF |
+ Opcode::MONITOR |
+ Opcode::MWAIT |
+ Opcode::CLAC |
+ Opcode::STAC |
+ Opcode::ENCLS |
+ Opcode::ENCLV |
+ Opcode::XGETBV |
+ Opcode::XSETBV |
+ Opcode::VMFUNC |
+ Opcode::XEND |
+ Opcode::XTEST |
+ Opcode::ENCLU |
+ Opcode::RDPKRU |
+ Opcode::WRPKRU |
+ Opcode::LAR => { write!(out, "{}", colors.platform_op(self)) }
+
+ Opcode::AESDEC |
+ Opcode::AESDECLAST |
+ Opcode::AESENC |
+ Opcode::AESENCLAST |
+ Opcode::AESIMC |
+ Opcode::AESKEYGENASSIST |
+ Opcode::VAESDEC |
+ Opcode::VAESDECLAST |
+ Opcode::VAESENC |
+ Opcode::VAESENCLAST |
+ Opcode::VAESIMC |
+ Opcode::VAESKEYGENASSIST => { write!(out, "{}", colors.misc_op(self)) }
+
+ Opcode::UD2 |
+ Opcode::Invalid => { write!(out, "{}", colors.invalid_op(self)) }
+ }
+ }
+}
+
+impl fmt::Display for Instruction {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ self.colorize(&NoColors, fmt)
+ }
+}
+
+/*
+ * Can't implement this as accepting a formatter because rust
+ * doesn't let me build one outside println! or write! or whatever.
+ *
+ * can't write this as an intermediate struct because i refuse to copy
+ * all data into the struct, and having a function producing a struct with
+ * some lifetimes gets really hairy if it's from a trait - same GAT kind
+ * of nonsense as i saw with ContextRead, because someone could hold onto
+ * the dang intermediate struct forever.
+ *
+ * so write to some Write thing i guess. bite me. i really just want to
+ * stop thinking about how to support printing instructions...
+ */
+impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color, Y> for Instruction {
+ fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result {
+ // TODO: I DONT LIKE THIS, there is no address i can give contextualize here,
+ // the address operand maybe should be optional..
+ self.contextualize(colors, 0, Some(&NoContext), out)
+ }
+}
+
+/// No per-operand context when contextualizing an instruction!
+struct NoContext;
+
+impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u64, NoContext, Color, T, Y> for Instruction {
+ fn contextualize(&self, colors: &Y, _address: u64, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+ if self.prefixes.lock() {
+ write!(out, "lock ")?;
+ }
+
+ if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&self.opcode) {
+ // only a few of you actually use the prefix...
+ if self.prefixes.rep() {
+ write!(out, "rep ")?;
+ } else if self.prefixes.repz() {
+ write!(out, "repz ")?;
+ } else if self.prefixes.repnz() {
+ write!(out, "repnz ")?;
+ }
+ }
+
+ self.opcode.colorize(colors, out)?;
+
+ match self.operands[0] {
+ OperandSpec::Nothing => {
+ return Ok(());
+ },
+ _ => {
+ write!(out, " ")?;
+ if let Some(prefix) = self.segment_override_for_op(0) {
+ write!(out, "{}:", prefix)?;
+ }
+ }
+ }
+ let x = Operand::from_spec(self, self.operands[0]);
+ x.colorize(colors, out)?;
+
+ for i in 1..4 {
+ match self.opcode {
+ Opcode::MOVSX_b |
+ Opcode::MOVZX_b => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ &OperandSpec::RegMMM => {
+ write!(out, ", ")?;
+ }
+ _ => {
+ write!(out, ", byte ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ }
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
+ },
+ Opcode::MOVSX_w |
+ Opcode::MOVZX_w => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ &OperandSpec::RegMMM => {
+ write!(out, ", ")?;
+ }
+ _ => {
+ write!(out, ", word ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ }
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
+ },
+ _ => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ _ => {
+ write!(out, ", ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
+ }
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+#[cfg(feature="std")]
+impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u64, [Option<alloc::string::String>], Color, T, Y> for Instruction {
+ fn contextualize(&self, colors: &Y, _address: u64, context: Option<&[Option<alloc::string::String>]>, out: &mut T) -> fmt::Result {
+ if self.prefixes.lock() {
+ write!(out, "lock ")?;
+ }
+
+ if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&self.opcode) {
+ // only a few of you actually use the prefix...
+ if self.prefixes.rep() {
+ write!(out, "rep ")?;
+ } else if self.prefixes.repz() {
+ write!(out, "repz ")?;
+ } else if self.prefixes.repnz() {
+ write!(out, "repnz ")?;
+ }
+ }
+
+ self.opcode.colorize(colors, out)?;
+
+ match context.and_then(|xs| xs[0].as_ref()) {
+ Some(s) => { write!(out, " {}", s)?; },
+ None => {
+ match self.operands[0] {
+ OperandSpec::Nothing => {
+ return Ok(());
+ },
+ _ => {
+ write!(out, " ")?;
+ if let Some(prefix) = self.segment_override_for_op(0) {
+ write!(out, "{}:", prefix)?;
+ }
+ }
+ }
+ let x = Operand::from_spec(self, self.operands[0]);
+ x.colorize(colors, out)?;
+ }
+ };
+ for i in 1..4 {
+ match self.opcode {
+ Opcode::MOVSX_b |
+ Opcode::MOVZX_b => {
+ match context.and_then(|xs| xs[i].as_ref()) {
+ Some(s) => { write!(out, ", {}", s)? }
+ None => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ &OperandSpec::RegMMM => {
+ write!(out, ", ")?;
+ }
+ _ => {
+ write!(out, ", byte ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ }
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
+ }
+ }
+ },
+ Opcode::MOVSX_w |
+ Opcode::MOVZX_w => {
+ match context.and_then(|xs| xs[i].as_ref()) {
+ Some(s) => { write!(out, ", {}", s)? }
+ None => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ &OperandSpec::RegMMM => {
+ write!(out, ", ")?;
+ }
+ _ => {
+ write!(out, ", word ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ }
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
+ }
+ }
+ },
+ _ => {
+ match context.and_then(|xs| xs[i].as_ref()) {
+ Some(s) => { write!(out, ", {}", s)? }
+ None => {
+ match &self.operands[i] {
+ &OperandSpec::Nothing => {
+ return Ok(());
+ },
+ _ => {
+ write!(out, ", ")?;
+ if let Some(prefix) = self.segment_override_for_op(1) {
+ write!(out, "{}:", prefix)?;
+ }
+ let x = Operand::from_spec(self, self.operands[i]);
+ x.colorize(colors, out)?
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+}
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index de7ec27..ac7968c 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -1 +1,6453 @@
-pub struct Arch {}
+mod vex;
+mod display;
+
+use core::hint::unreachable_unchecked;
+
+use yaxpeax_arch::{Decoder, LengthedInstruction};
+
+#[cfg(feature="use-serde")]
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq, Serialize, Deserialize)]
+pub struct RegSpec {
+ pub num: u8,
+ pub bank: RegisterBank
+}
+#[cfg(not(feature="use-serde"))]
+#[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)]
+pub struct RegSpec {
+ pub num: u8,
+ pub bank: RegisterBank
+}
+
+use core::hash::Hash;
+use core::hash::Hasher;
+impl Hash for RegSpec {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let code = ((self.bank as u16) << 8) | (self.num as u16);
+ code.hash(state);
+ }
+}
+
+// This is only to select alternate opcode maps for the 0f escape byte.
+// This often could be treated as a size prefix but in some cases selects
+// an entirely different operation.
+#[derive(Debug)]
+enum OpcodeMap {
+ Map66,
+ MapF2,
+ MapF3,
+}
+
+#[derive(Debug)]
+pub enum ConditionCode {
+ O,
+ NO,
+ B,
+ AE,
+ Z,
+ NZ,
+ A,
+ BE,
+ S,
+ NS,
+ P,
+ NP,
+ L,
+ GE,
+ G,
+ LE,
+}
+
+#[allow(non_snake_case)]
+impl RegSpec {
+ pub fn name(&self) -> &'static str {
+ display::regspec_label(self)
+ }
+
+ #[inline]
+ fn from_parts(num: u8, bank: RegisterBank) -> RegSpec {
+ RegSpec {
+ num: num,
+ bank: bank
+ }
+ }
+
+ #[inline]
+ fn gp_from_parts(num: u8, width: u8) -> RegSpec {
+ RegSpec {
+ num: num,
+ bank: width_to_gp_reg_bank(width)
+ }
+ }
+
+ #[inline]
+ pub fn eip() -> RegSpec {
+ RegSpec {
+ num: 0,
+ bank: RegisterBank::EIP
+ }
+ }
+
+ #[inline]
+ pub fn eflags() -> RegSpec {
+ RegSpec {
+ num: 0,
+ bank: RegisterBank::EFlags
+ }
+ }
+
+ #[inline]
+ pub fn bp() -> RegSpec {
+ RegSpec {
+ num: 5,
+ bank: RegisterBank::W
+ }
+ }
+
+ #[inline]
+ pub fn ebp() -> RegSpec {
+ RegSpec {
+ num: 5,
+ bank: RegisterBank::D
+ }
+ }
+
+ #[inline]
+ pub fn esp() -> RegSpec {
+ RegSpec {
+ num: 4,
+ bank: RegisterBank::D
+ }
+ }
+
+ #[inline]
+ pub fn fs() -> RegSpec {
+ RegSpec { bank: RegisterBank::S, num: 3 }
+ }
+
+ #[inline]
+ pub fn gs() -> RegSpec {
+ RegSpec { bank: RegisterBank::S, num: 4 }
+ }
+
+ #[inline]
+ pub fn eax() -> RegSpec {
+ RegSpec { bank: RegisterBank::D, num: 0 }
+ }
+
+ #[inline]
+ pub fn ecx() -> RegSpec {
+ RegSpec { bank: RegisterBank::D, num: 1 }
+ }
+
+ #[inline]
+ pub fn edx() -> RegSpec {
+ RegSpec { bank: RegisterBank::D, num: 2 }
+ }
+
+ #[inline]
+ pub fn bx() -> RegSpec {
+ RegSpec { bank: RegisterBank::W, num: 3 }
+ }
+
+ #[inline]
+ pub fn ebx() -> RegSpec {
+ RegSpec { bank: RegisterBank::D, num: 3 }
+ }
+
+ #[inline]
+ pub fn si() -> RegSpec {
+ RegSpec { bank: RegisterBank::W, num: 6 }
+ }
+
+ #[inline]
+ pub fn esi() -> RegSpec {
+ RegSpec { bank: RegisterBank::D, num: 6 }
+ }
+
+ #[inline]
+ pub fn di() -> RegSpec {
+ RegSpec { bank: RegisterBank::W, num: 7 }
+ }
+
+ #[inline]
+ pub fn edi() -> RegSpec {
+ RegSpec { bank: RegisterBank::D, num: 7 }
+ }
+
+ #[inline]
+ pub fn ax() -> RegSpec {
+ RegSpec { bank: RegisterBank::W, num: 0 }
+ }
+
+ #[inline]
+ pub fn dx() -> RegSpec {
+ RegSpec { bank: RegisterBank::W, num: 2 }
+ }
+
+ #[inline]
+ pub fn al() -> RegSpec {
+ RegSpec { bank: RegisterBank::B, num: 0 }
+ }
+
+ #[inline]
+ pub fn cl() -> RegSpec {
+ RegSpec { bank: RegisterBank::B, num: 1 }
+ }
+}
+
+#[allow(non_camel_case_types)]
+#[allow(dead_code)]
+enum SizeCode {
+ b,
+ vd,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum Operand {
+ ImmediateI8(i8),
+ ImmediateU8(u8),
+ ImmediateI16(i16),
+ ImmediateU16(u16),
+ ImmediateU32(u32),
+ ImmediateI32(i32),
+ Register(RegSpec),
+ DisplacementU32(u32),
+ DisplacementU16(u16),
+ RegDeref(RegSpec),
+ RegDisp(RegSpec, i32),
+ RegScale(RegSpec, u8),
+ RegIndexBase(RegSpec, RegSpec),
+ RegIndexBaseDisp(RegSpec, RegSpec, i32),
+ RegScaleDisp(RegSpec, u8, i32),
+ RegIndexBaseScale(RegSpec, RegSpec, u8),
+ RegIndexBaseScaleDisp(RegSpec, RegSpec, u8, i32),
+ Nothing,
+}
+
+impl OperandSpec {
+ pub fn is_memory(&self) -> bool {
+ match self {
+ OperandSpec::DispU32 |
+ OperandSpec::DispU16 |
+ OperandSpec::Deref |
+ OperandSpec::Deref_esi |
+ OperandSpec::Deref_edi |
+ OperandSpec::RegDisp |
+ OperandSpec::RegScale |
+ OperandSpec::RegIndexBase |
+ OperandSpec::RegIndexBaseDisp |
+ OperandSpec::RegScaleDisp |
+ OperandSpec::RegIndexBaseScale |
+ OperandSpec::RegIndexBaseScaleDisp => {
+ true
+ },
+ OperandSpec::ImmI8 |
+ OperandSpec::ImmI16 |
+ OperandSpec::ImmI32 |
+ OperandSpec::ImmU8 |
+ OperandSpec::ImmU16 |
+ OperandSpec::ImmU32 |
+ OperandSpec::RegRRR |
+ OperandSpec::RegMMM |
+ OperandSpec::RegVex |
+ OperandSpec::AL |
+ OperandSpec::CL |
+ OperandSpec::Nothing => {
+ false
+ }
+ }
+ }
+}
+impl Operand {
+ fn from_spec(inst: &Instruction, spec: OperandSpec) -> Operand {
+ match spec {
+ OperandSpec::Nothing => {
+ Operand::Nothing
+ }
+ // the register in modrm_rrr
+ OperandSpec::RegRRR => {
+ Operand::Register(inst.modrm_rrr)
+ }
+ // the register in modrm_mmm (eg modrm mod bits were 11)
+ OperandSpec::RegMMM => {
+ Operand::Register(inst.modrm_mmm)
+ }
+ OperandSpec::RegVex => {
+ Operand::Register(inst.vex_reg)
+ }
+ OperandSpec::AL => {
+ Operand::Register(RegSpec::al())
+ }
+ OperandSpec::CL => {
+ Operand::Register(RegSpec::cl())
+ }
+ OperandSpec::ImmI8 => Operand::ImmediateI8(inst.imm as i8),
+ OperandSpec::ImmU8 => Operand::ImmediateU8(inst.imm as u8),
+ OperandSpec::ImmI16 => Operand::ImmediateI16(inst.imm as i16),
+ OperandSpec::ImmU16 => Operand::ImmediateU16(inst.imm as u16),
+ OperandSpec::ImmI32 => Operand::ImmediateI32(inst.imm as i32),
+ OperandSpec::ImmU32 => Operand::ImmediateU32(inst.imm as u32),
+ OperandSpec::DispU32 => Operand::DisplacementU32(inst.disp),
+ OperandSpec::DispU16 => Operand::DisplacementU16(inst.disp as u16),
+ OperandSpec::Deref => {
+ Operand::RegDeref(inst.modrm_mmm)
+ }
+ OperandSpec::Deref_esi => {
+ Operand::RegDeref(RegSpec::esi())
+ }
+ OperandSpec::Deref_edi => {
+ Operand::RegDeref(RegSpec::edi())
+ }
+ OperandSpec::RegDisp => {
+ Operand::RegDisp(inst.modrm_mmm, inst.disp as i32)
+ }
+ OperandSpec::RegScale => {
+ Operand::RegScale(inst.sib_index, inst.scale)
+ }
+ OperandSpec::RegIndexBase => {
+ Operand::RegIndexBase(inst.modrm_mmm, inst.sib_index)
+ }
+ OperandSpec::RegIndexBaseDisp => {
+ Operand::RegIndexBaseDisp(inst.modrm_mmm, inst.sib_index, inst.disp as i32)
+ }
+ OperandSpec::RegScaleDisp => {
+ Operand::RegScaleDisp(inst.sib_index, inst.scale, inst.disp as i32)
+ }
+ OperandSpec::RegIndexBaseScale => {
+ Operand::RegIndexBaseScale(inst.modrm_mmm, inst.sib_index, inst.scale)
+ }
+ OperandSpec::RegIndexBaseScaleDisp => {
+ Operand::RegIndexBaseScaleDisp(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32)
+ }
+ }
+ }
+ pub fn is_memory(&self) -> bool {
+ match self {
+ Operand::DisplacementU16(_) |
+ Operand::DisplacementU32(_) |
+ Operand::RegDeref(_) |
+ Operand::RegDisp(_, _) |
+ Operand::RegScale(_, _) |
+ Operand::RegIndexBase(_, _) |
+ Operand::RegIndexBaseDisp(_, _, _) |
+ Operand::RegScaleDisp(_, _, _) |
+ Operand::RegIndexBaseScale(_, _, _) |
+ Operand::RegIndexBaseScaleDisp(_, _, _, _) => {
+ true
+ },
+ Operand::ImmediateI8(_) |
+ Operand::ImmediateU8(_) |
+ Operand::ImmediateI16(_) |
+ Operand::ImmediateU16(_) |
+ Operand::ImmediateU32(_) |
+ Operand::ImmediateI32(_) |
+ Operand::Register(_) |
+ Operand::Nothing => {
+ false
+ }
+ }
+ }
+}
+
+#[test]
+fn operand_size() {
+ assert_eq!(core::mem::size_of::<OperandSpec>(), 1);
+ assert_eq!(core::mem::size_of::<RegSpec>(), 2);
+ // assert_eq!(core::mem::size_of::<Prefixes>(), 4);
+ // assert_eq!(core::mem::size_of::<Instruction>(), 40);
+}
+
+#[allow(non_camel_case_types)]
+#[cfg(feature="use-serde")]
+#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize)]
+pub enum RegisterBank {
+ D, W, B, // Dword, Word, Byte
+ CR, DR, S, EIP, EFlags, // Control reg, Debug reg, Selector, ...
+ X, Y, Z, // XMM, YMM, ZMM
+ ST, MM, // ST, MM regs (x87, mmx)
+ K, // AVX512 mask registers
+}
+#[allow(non_camel_case_types)]
+#[cfg(not(feature="use-serde"))]
+#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)]
+pub enum RegisterBank {
+ D, W, B, // Dword, Word, Byte
+ CR, DR, S, EIP, EFlags, // Control reg, Debug reg, Selector, ...
+ X, Y, Z, // XMM, YMM, ZMM
+ ST, MM, // ST, MM regs (x87, mmx)
+ K, // AVX512 mask registers
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
+pub enum Segment {
+ DS = 0, CS, ES, FS, GS, SS
+}
+
+const BMI1: [Opcode; 6] = [
+ Opcode::ANDN,
+ Opcode::BEXTR,
+ Opcode::BLSI,
+ Opcode::BLSMSK,
+ Opcode::BLSR,
+ Opcode::TZCNT,
+];
+
+// TODO:
+// PTWRITE
+// RDFSBASE
+// RDGSBASE
+// WRFSBASE
+// WRGSBASE
+// TPAUSE
+// UMONITOR
+// UMWAIT
+// CLFLUSHOPT
+// CLWB
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Opcode {
+ ADD = 1,
+ OR = 2,
+ ADC = 3,
+ SBB = 4,
+ AND = 5,
+ XOR = 6,
+ SUB = 7,
+ CMP = 8,
+ Invalid,
+ XADD,
+ BT,
+ BTS,
+ BTC,
+ BTR,
+ BSF,
+ BSR,
+ TZCNT,
+ MOVSS,
+ ADDSS,
+ SUBSS,
+ MULSS,
+ DIVSS,
+ MINSS,
+ MAXSS,
+ SQRTSS,
+ MOVSD,
+ SQRTSD,
+ ADDSD,
+ SUBSD,
+ MULSD,
+ DIVSD,
+ MINSD,
+ MAXSD,
+ MOVSLDUP,
+ MOVSHDUP,
+ MOVDDUP,
+ HADDPS,
+ HSUBPS,
+ ADDSUBPD,
+ ADDSUBPS,
+ CVTSI2SS,
+ CVTSI2SD,
+ CVTTSD2SI,
+ CVTTPS2DQ,
+ CVTPD2DQ,
+ CVTPD2PS,
+ CVTPS2DQ,
+ CVTSD2SI,
+ CVTSD2SS,
+ CVTTSS2SI,
+ CVTSS2SI,
+ CVTSS2SD,
+ CVTDQ2PD,
+ LDDQU,
+ MOVSX_b,
+ MOVSX_w,
+ MOVZX_b,
+ MOVZX_w,
+ MOVSX,
+ ARPL,
+ SAR,
+ SAL,
+ SHR,
+ SHRD,
+ SHL,
+ RCR,
+ RCL,
+ ROR,
+ ROL,
+ INC,
+ DEC,
+ HLT,
+ CALL,
+ CALLF,
+ JMP,
+ JMPF,
+ PUSH,
+ POP,
+ LEA,
+ NOP,
+ PREFETCHNTA,
+ PREFETCH0,
+ PREFETCH1,
+ PREFETCH2,
+ XCHG,
+ POPF,
+ INT,
+ INTO,
+ IRET,
+ RETF,
+ ENTER,
+ LEAVE,
+ MOV,
+ RETURN,
+ PUSHF,
+ WAIT,
+ CBW,
+ CWDE,
+ CDQE,
+ CBD,
+ CDQ,
+ CQO,
+ LODS,
+ STOS,
+ LAHF,
+ SAHF,
+ CMPS,
+ SCAS,
+ MOVS,
+ TEST,
+ INS,
+ IN,
+ OUTS,
+ OUT,
+ IMUL,
+ JO,
+ JNO,
+ JB,
+ JNB,
+ JZ,
+ JNZ,
+ JA,
+ JNA,
+ JS,
+ JNS,
+ JP,
+ JNP,
+ JL,
+ JGE,
+ JLE,
+ JG,
+ CMOVA,
+ CMOVB,
+ CMOVG,
+ CMOVGE,
+ CMOVL,
+ CMOVLE,
+ CMOVNA,
+ CMOVNB,
+ CMOVNO,
+ CMOVNP,
+ CMOVNS,
+ CMOVNZ,
+ CMOVO,
+ CMOVP,
+ CMOVS,
+ CMOVZ,
+ DIV,
+ IDIV,
+ MUL,
+ NEG,
+ NOT,
+ CMPXCHG,
+ SETO,
+ SETNO,
+ SETB,
+ SETAE,
+ SETZ,
+ SETNZ,
+ SETBE,
+ SETA,
+ SETS,
+ SETNS,
+ SETP,
+ SETNP,
+ SETL,
+ SETGE,
+ SETLE,
+ SETG,
+ CPUID,
+ UD2,
+ WBINVD,
+ INVD,
+ SYSRET,
+ CLTS,
+ SYSCALL,
+ LSL,
+ LAR,
+ LES,
+ LDS,
+ SGDT,
+ SIDT,
+ LGDT,
+ LIDT,
+ SMSW,
+ LMSW,
+ SWAPGS,
+ RDTSCP,
+ INVLPG,
+ FXSAVE,
+ FXRSTOR,
+ LDMXCSR,
+ STMXCSR,
+ XSAVE,
+ XRSTOR,
+ XSAVEOPT,
+ LFENCE,
+ MFENCE,
+ SFENCE,
+ CLFLUSH,
+ WRMSR,
+ RDTSC,
+ RDMSR,
+ RDPMC,
+ SLDT,
+ STR,
+ LLDT,
+ LTR,
+ VERR,
+ VERW,
+ CLC,
+ STC,
+ CLI,
+ STI,
+ CLD,
+ STD,
+ JMPE,
+ POPCNT,
+ MOVDQU,
+ MOVDQA,
+ MOVQ,
+ CMPSS,
+ CMPSD,
+ UNPCKLPS,
+ UNPCKLPD,
+ UNPCKHPS,
+ UNPCKHPD,
+ PSHUFHW,
+ PSHUFLW,
+ MOVUPS,
+ MOVQ2DQ,
+ MOVDQ2Q,
+ RSQRTSS,
+ RCPSS,
+
+ ANDN,
+ BEXTR,
+ BLSI,
+ BLSMSK,
+ BLSR,
+ VMCLEAR,
+ VMXON,
+ VMCALL,
+ VMLAUNCH,
+ VMRESUME,
+ VMXOFF,
+ MONITOR,
+ MWAIT,
+ CLAC,
+ STAC,
+ ENCLS,
+ ENCLV,
+ XGETBV,
+ XSETBV,
+ VMFUNC,
+ XEND,
+ XTEST,
+ ENCLU,
+ RDPKRU,
+ WRPKRU,
+
+ ADDPS,
+ ADDPD,
+ ANDNPS,
+ ANDNPD,
+ ANDPS,
+ ANDPD,
+ BSWAP,
+ CMPPD,
+ CMPPS,
+ COMISD,
+ COMISS,
+ CVTDQ2PS,
+ CVTPI2PS,
+ CVTPI2PD,
+ CVTPS2PD,
+ CVTPS2PI,
+ CVTPD2PI,
+ CVTTPS2PI,
+ CVTTPD2PI,
+ CVTTPD2DQ,
+ DIVPS,
+ DIVPD,
+ EMMS,
+ GETSEC,
+ LFS,
+ LGS,
+ LSS,
+ MASKMOVQ,
+ MASKMOVDQU,
+ MAXPS,
+ MAXPD,
+ MINPS,
+ MINPD,
+ MOVAPS,
+ MOVAPD,
+ MOVD,
+ MOVLPS,
+ MOVLPD,
+ MOVHPS,
+ MOVHPD,
+ MOVLHPS,
+ MOVHLPS,
+ MOVUPD,
+ MOVMSKPS,
+ MOVMSKPD,
+ MOVNTI,
+ MOVNTPS,
+ MOVNTPD,
+ MOVNTQ,
+ MOVNTDQ,
+ MULPS,
+ MULPD,
+ ORPS,
+ ORPD,
+ PACKSSDW,
+ PACKSSWB,
+ PACKUSWB,
+ PADDB,
+ PADDD,
+ PADDQ,
+ PADDSB,
+ PADDSW,
+ PADDUSB,
+ PADDUSW,
+ PADDW,
+ PAND,
+ PANDN,
+ PAVGB,
+ PAVGW,
+ PCMPEQB,
+ PCMPEQD,
+ PCMPEQW,
+ PCMPGTB,
+ PCMPGTD,
+ PCMPGTW,
+ PEXTRW,
+ PINSRW,
+ PMADDWD,
+ PMAXSW,
+ PMAXUB,
+ PMINSW,
+ PMINUB,
+ PMOVMSKB,
+ PMULHUW,
+ PMULHW,
+ PMULLW,
+ PMULUDQ,
+ POR,
+ PSADBW,
+ PSHUFW,
+ PSHUFD,
+ PSLLD,
+ PSLLDQ,
+ PSLLQ,
+ PSLLW,
+ PSRAD,
+ PSRAW,
+ PSRLD,
+ PSRLDQ,
+ PSRLQ,
+ PSRLW,
+ PSUBB,
+ PSUBD,
+ PSUBQ,
+ PSUBSB,
+ PSUBSW,
+ PSUBUSB,
+ PSUBUSW,
+ PSUBW,
+ PUNPCKHBW,
+ PUNPCKHDQ,
+ PUNPCKHWD,
+ PUNPCKLBW,
+ PUNPCKLDQ,
+ PUNPCKLWD,
+ PUNPCKLQDQ,
+ PUNPCKHQDQ,
+ PXOR,
+ RCPPS,
+ RSM,
+ RSQRTPS,
+ SHLD,
+ SHUFPD,
+ SHUFPS,
+ SLHD,
+ SQRTPS,
+ SQRTPD,
+ SUBPS,
+ SUBPD,
+ SYSENTER,
+ SYSEXIT,
+ UCOMISD,
+ UCOMISS,
+ UD2E,
+ VMREAD,
+ VMWRITE,
+ XORPS,
+ XORPD,
+
+ VMOVDDUP,
+ VPSHUFLW,
+ VHADDPS,
+ VHSUBPS,
+ VADDSUBPS,
+ VCVTPD2DQ,
+ VLDDQU,
+
+ VCOMISD,
+ VCOMISS,
+ VUCOMISD,
+ VUCOMISS,
+ VADDPD,
+ VADDPS,
+ VADDSD,
+ VADDSS,
+ VADDSUBPD,
+ VAESDEC,
+ VAESDECLAST,
+ VAESENC,
+ VAESENCLAST,
+ VAESIMC,
+ VAESKEYGENASSIST,
+ VBLENDPD,
+ VBLENDPS,
+ VBLENDVPD,
+ VBLENDVPS,
+ VBROADCASTF128,
+ VBROADCASTI128,
+ VBROADCASTSD,
+ VBROADCASTSS,
+ VCMPSD,
+ VCMPSS,
+ VCMPPD,
+ VCMPPS,
+ VCVTDQ2PD,
+ VCVTDQ2PS,
+ VCVTPD2PS,
+ VCVTPH2PS,
+ VCVTPS2DQ,
+ VCVTPS2PD,
+ VCVTSS2SD,
+ VCVTSI2SS,
+ VCVTSI2SD,
+ VCVTSD2SI,
+ VCVTSD2SS,
+ VCVTPS2PH,
+ VCVTSS2SI,
+ VCVTTPD2DQ,
+ VCVTTPS2DQ,
+ VCVTTSS2SI,
+ VCVTTSD2SI,
+ VDIVPD,
+ VDIVPS,
+ VDIVSD,
+ VDIVSS,
+ VDPPD,
+ VDPPS,
+ VEXTRACTF128,
+ VEXTRACTI128,
+ VEXTRACTPS,
+ VFMADD132PD,
+ VFMADD132PS,
+ VFMADD132SD,
+ VFMADD132SS,
+ VFMADD213PD,
+ VFMADD213PS,
+ VFMADD213SD,
+ VFMADD213SS,
+ VFMADD231PD,
+ VFMADD231PS,
+ VFMADD231SD,
+ VFMADD231SS,
+ VFMADDSUB132PD,
+ VFMADDSUB132PS,
+ VFMADDSUB213PD,
+ VFMADDSUB213PS,
+ VFMADDSUB231PD,
+ VFMADDSUB231PS,
+ VFMSUB132PD,
+ VFMSUB132PS,
+ VFMSUB132SD,
+ VFMSUB132SS,
+ VFMSUB213PD,
+ VFMSUB213PS,
+ VFMSUB213SD,
+ VFMSUB213SS,
+ VFMSUB231PD,
+ VFMSUB231PS,
+ VFMSUB231SD,
+ VFMSUB231SS,
+ VFMSUBADD132PD,
+ VFMSUBADD132PS,
+ VFMSUBADD213PD,
+ VFMSUBADD213PS,
+ VFMSUBADD231PD,
+ VFMSUBADD231PS,
+ VFNMADD132PD,
+ VFNMADD132PS,
+ VFNMADD132SD,
+ VFNMADD132SS,
+ VFNMADD213PD,
+ VFNMADD213PS,
+ VFNMADD213SD,
+ VFNMADD213SS,
+ VFNMADD231PD,
+ VFNMADD231PS,
+ VFNMADD231SD,
+ VFNMADD231SS,
+ VFNMSUB132PD,
+ VFNMSUB132PS,
+ VFNMSUB132SD,
+ VFNMSUB132SS,
+ VFNMSUB213PD,
+ VFNMSUB213PS,
+ VFNMSUB213SD,
+ VFNMSUB213SS,
+ VFNMSUB231PD,
+ VFNMSUB231PS,
+ VFNMSUB231SD,
+ VFNMSUB231SS,
+ VGATHERDPD,
+ VGATHERDPS,
+ VGATHERQPD,
+ VGATHERQPS,
+ VHADDPD,
+ VHSUBPD,
+ VINSERTF128,
+ VINSERTI128,
+ VINSERTPS,
+ VMASKMOVDQU,
+ VMASKMOVPD,
+ VMASKMOVPS,
+ VMAXPD,
+ VMAXPS,
+ VMAXSD,
+ VMAXSS,
+ VMINPD,
+ VMINPS,
+ VMINSD,
+ VMINSS,
+ VMOVAPD,
+ VMOVAPS,
+ VMOVD,
+ VMOVDQA,
+ VMOVDQU,
+ VMOVHLPS,
+ VMOVHPD,
+ VMOVHPS,
+ VMOVLHPS,
+ VMOVLPD,
+ VMOVLPS,
+ VMOVMSKPD,
+ VMOVMSKPS,
+ VMOVNTDQ,
+ VMOVNTDQA,
+ VMOVNTPD,
+ VMOVNTPS,
+ VMOVQ,
+ VMOVSS,
+ VMOVSD,
+ VMOVSHDUP,
+ VMOVSLDUP,
+ VMOVUPD,
+ VMOVUPS,
+ VMPSADBW,
+ VMULPD,
+ VMULPS,
+ VMULSD,
+ VMULSS,
+ VPABSB,
+ VPABSD,
+ VPABSW,
+ VPACKSSDW,
+ VPACKSSWB,
+ VPACKUSWB,
+ VPADDB,
+ VPADDD,
+ VPADDQ,
+ VPADDSB,
+ VPADDSW,
+ VPADDUSB,
+ VPADDUSW,
+ VPADDW,
+ VPALIGNR,
+ VPAND,
+ VPANDN,
+ VPAVGB,
+ VPAVGW,
+ VPBLENDD,
+ VPBLENDVB,
+ VPBLENDW,
+ VPBROADCASTB,
+ VPBROADCASTD,
+ VPBROADCASTQ,
+ VPBROADCASTW,
+ VPCLMULQDQ,
+ VPCMPEQB,
+ VPCMPEQD,
+ VPCMPEQQ,
+ VPCMPEQW,
+ VPCMPGTB,
+ VPCMPGTD,
+ VPCMPGTQ,
+ VPCMPGTW,
+ VPCMPISTRI,
+ VPCMPISTRM,
+ VPERM2F128,
+ VPERM2I128,
+ VPERMD,
+ VPERMILPD,
+ VPERMILPS,
+ VPERMPD,
+ VPERMPS,
+ VPERMQ,
+ VPEXTRB,
+ VPEXTRD,
+ VPEXTRQ,
+ VPEXTRW,
+ VPGATHERDD,
+ VPGATHERDQ,
+ VPGATHERQD,
+ VPGATHERQQ,
+ VPHADDD,
+ VPHADDSW,
+ VPHADDW,
+ VPHADDUBSW,
+ VPHMINPOSUW,
+ VPHSUBD,
+ VPHSUBSW,
+ VPHSUBW,
+ VPINSRB,
+ VPINSRD,
+ VPINSRQ,
+ VPINSRW,
+ VPMADDWD,
+ VPMASKMOVD,
+ VPMASKMOVQ,
+ VPMAXSB,
+ VPMAXSD,
+ VPMAXSW,
+ VPMAXUD,
+ VPMINSD,
+ VPMINUD,
+ VPMOVMSKB,
+ VPMOVSXBD,
+ VPMOVSXBQ,
+ VPMOVSXBW,
+ VPMOVSXDQ,
+ VPMOVSXWD,
+ VPMOVSXWQ,
+ VPMOVZXBD,
+ VPMOVZXBQ,
+ VPMOVZXBW,
+ VPMOVZXDQ,
+ VPMOVZXWD,
+ VPMOVZXWQ,
+ VPMULDQ,
+ VPMULHRSW,
+ VPMULHUW,
+ VPMULHW,
+ VPMULLD,
+ VPMULLW,
+ VPMULUDQ,
+ VPOR,
+ VPSADBW,
+ VPSHUFB,
+ VPSHUFD,
+ VPSIGNB,
+ VPSIGND,
+ VPSIGNW,
+ VPSLLD,
+ VPSLLDQ,
+ VPSLLQ,
+ VPSLLVD,
+ VPSLLVQ,
+ VPSLLW,
+ VPSRAD,
+ VPSRAVD,
+ VPSRAW,
+ VPSRLD,
+ VPSRLDQ,
+ VPSRLQ,
+ VPSRLVD,
+ VPSRLVQ,
+ VPSRLW,
+ VPSUBB,
+ VPSUBD,
+ VPSUBQ,
+ VPSUBSB,
+ VPSUBSW,
+ VPSUBUSB,
+ VPSUBUSW,
+ VPSUBW,
+ VPTEST,
+ VPUNPCKHBW,
+ VPUNPCKHDQ,
+ VPUNPCKHQDQ,
+ VPUNPCKHWD,
+ VPUNPCKLBW,
+ VPUNPCKLDQ,
+ VPUNPCKLQDQ,
+ VPUNPCKLWD,
+ VPXOR,
+ VRCPPS,
+ VROUNDPD,
+ VROUNDPS,
+ VROUNDSD,
+ VROUNDSS,
+ VRSQRTPS,
+ VRSQRTSS,
+ VRCPSS,
+ VSHUFPD,
+ VSHUFPS,
+ VSQRTPD,
+ VSQRTPS,
+ VSQRTSS,
+ VSQRTSD,
+ VSUBPD,
+ VSUBPS,
+ VSUBSD,
+ VSUBSS,
+ VTESTPD,
+ VTESTPS,
+ VUNPCKHPD,
+ VUNPCKHPS,
+ VUNPCKLPD,
+ VUNPCKLPS,
+ VXORPD,
+ VXORPS,
+ VZEROUPPER,
+
+ PCLMULQDQ,
+ AESKEYGENASSIST,
+ AESIMC,
+ AESENC,
+ AESENCLAST,
+ AESDEC,
+ AESDECLAST,
+ PCMPGTQ,
+ PCMPISTRM,
+ PCMPISTRI,
+ PCMPESTRI,
+ PACKUSDW,
+ PCMPESTRM,
+ PCMPEQQ,
+ PTEST,
+ PHMINPOSUW,
+ MPSADBW,
+ PMOVZXDQ,
+ PMOVSXDQ,
+ PMOVZXBD,
+ PMOVSXBD,
+ PMOVZXWQ,
+ PMOVSXWQ,
+ PMOVZXBQ,
+ PMOVSXBQ,
+ PMOVSXWD,
+ PMOVZXWD,
+ PEXTRQ,
+ PEXTRB,
+ PMOVSXBW,
+ PMOVZXBW,
+ PINSRQ,
+ PINSRD,
+ PINSRB,
+ EXTRACTPS,
+ INSERTPS,
+ ROUNDSS,
+ ROUNDSD,
+ ROUNDPS,
+ ROUNDPD,
+ PMAXSB,
+ PMAXUW,
+ PMAXUD,
+ PMINSD,
+ PMINSB,
+ PMINUD,
+ PMINUW,
+ BLENDW,
+ BLENDDVB,
+ BLENDVPS,
+ BLENDVPD,
+ BLENDPS,
+ BLENDPD,
+ PMULDQ,
+ MOVNTDQA,
+ PMULLD,
+ PALIGNR,
+ PSIGNW,
+ PSIGND,
+ PSIGNB,
+ PSHUFB,
+ PMULHRSU,
+ PMADDUBSW,
+ PABSD,
+ PABSW,
+ PABSB,
+ PHSUBSW,
+ PHSUBW,
+ PHSUBD,
+ PHADDD,
+ PHADDSW,
+ PHADDW,
+ HSUBPD,
+ HADDPD,
+}
+
+#[derive(Debug)]
+pub struct Instruction {
+ pub prefixes: Prefixes,
+ modrm_rrr: RegSpec,
+ modrm_mmm: RegSpec, // doubles as sib_base
+ sib_index: RegSpec,
+ vex_reg: RegSpec,
+ scale: u8,
+ length: u8,
+ operand_count: u8,
+ operands: [OperandSpec; 4],
+ imm: u32,
+ disp: u32,
+ pub opcode: Opcode,
+}
+
+impl yaxpeax_arch::Instruction for Instruction {
+ fn well_defined(&self) -> bool {
+ // TODO: this is incorrect!
+ true
+ }
+}
+
+#[derive(Debug, PartialEq)]
+pub enum DecodeError {
+ ExhaustedInput,
+ InvalidOpcode,
+ InvalidOperand,
+ InvalidPrefixes,
+ TooLong,
+ IncompleteDecoder,
+}
+
+impl yaxpeax_arch::DecodeError for DecodeError {
+ fn data_exhausted(&self) -> bool { self == &DecodeError::ExhaustedInput }
+ fn bad_opcode(&self) -> bool { self == &DecodeError::InvalidOpcode }
+ fn bad_operand(&self) -> bool { self == &DecodeError::InvalidOperand }
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Debug, Copy, Clone, PartialEq)]
+enum OperandSpec {
+ Nothing,
+ // the register in modrm_rrr
+ RegRRR,
+ // the register in modrm_mmm (eg modrm mod bits were 11)
+ RegMMM,
+ // the register selected by vex-vvvv bits
+ RegVex,
+ // the register `al`. Used for MOVS.
+ AL,
+ // the register `cl`. Used for SHLD and SHRD.
+ CL,
+ ImmI8,
+ ImmI16,
+ ImmI32,
+ ImmU8,
+ ImmU16,
+ ImmU32,
+ DispU16,
+ DispU32,
+ Deref,
+ Deref_esi,
+ Deref_edi,
+ RegDisp,
+ RegScale,
+ RegIndexBase,
+ RegIndexBaseDisp,
+ RegScaleDisp,
+ RegIndexBaseScale,
+ RegIndexBaseScaleDisp
+}
+
+// the Hash, Eq, and PartialEq impls here are possibly misleading.
+// They exist because downstream some structs are spelled like
+// Foo<T> for T == x86_64. This is only to access associated types
+// which themselves are bounded, but their #[derive] require T to
+// implement these traits.
+#[cfg(feature="use-serde")]
+#[derive(Hash, Eq, PartialEq, Debug, Serialize, Deserialize)]
+#[allow(non_camel_case_types)]
+pub struct Arch;
+
+#[cfg(not(feature="use-serde"))]
+#[derive(Hash, Eq, PartialEq, Debug)]
+#[allow(non_camel_case_types)]
+pub struct Arch;
+
+impl yaxpeax_arch::Arch for Arch {
+ type Address = u32;
+ type Instruction = Instruction;
+ type DecodeError = DecodeError;
+ type Decoder = InstDecoder;
+ type Operand = Operand;
+}
+
+impl LengthedInstruction for Instruction {
+ type Unit = u32;
+ fn len(&self) -> u32 {
+ self.length.into()
+ }
+ fn min_size() -> u32 {
+ 1
+ }
+}
+
+#[derive(PartialEq)]
+pub struct InstDecoder {
+ // extensions tracked here:
+ // 0. SSE3
+ // 1. SSSE3
+ // 2. monitor (intel-only?)
+ // 3. vmx (some atom chips still lack it)
+ // 4. fma3 (intel haswell/broadwell+, amd piledriver+)
+ // 5. cmpxchg16b (some amd are missingt this one)
+ // 6. sse4.1
+ // 7. sse4.2
+ // 8. movbe
+ // 9. popcnt (independent of BMI)
+ // 10. aesni
+ // 11. xsave (xsave, xrestor, xsetbv, xgetbv)
+ // 12. rdrand (intel ivybridge+, amd ..??)
+ // 13. sgx (eadd, eblock, ecreate, edbgrd, edbgwr, einit, eldb, eldu, epa, eremove, etrace,
+ // ewb, eenter, eexit, egetkey, ereport, eresume)
+ // 14. bmi1 (intel haswell+, amd jaguar+)
+ // 15. avx2 (intel haswell+, amd excavator+)
+ // 16. bmi2 (intel ?, amd ?)
+ // 17. invpcid
+ // 18. mpx
+ // 19. avx512_f
+ // 20. avx512_dq
+ // 21. rdseed
+ // 22. adx
+ // 23. avx512_fma
+ // 24. pcommit
+ // 25. clflushopt
+ // 26. clwb
+ // 27. avx512_pf
+ // 28. avx512_er
+ // 29. avx512_cd
+ // 30. sha
+ // 31. avx512_bw
+ // 32. avx512_vl
+ // 33. prefetchwt1
+ // 34. avx512_vbmi
+ // 35. avx512_vbmi2
+ // 36. gfni (galois field instructions)
+ // 37. vaes
+ // 38. pclmulqdq
+ // 39. avx_vnni
+ // 40. avx512_bitalg
+ // 41. avx512_vpopcntdq
+ // 42. avx512_4vnniw
+ // 43. avx512_4fmaps
+ // 44. cx8 // cmpxchg8 - is this actually optional in x86_64?
+ // 45. syscall // syscall/sysret - actually optional in x86_64?
+ // 46. rdtscp // actually optional in x86_64?
+ // 47. abm (lzcnt, popcnt)
+ // 48. sse4a
+ // 49. 3dnowprefetch // actually optional?
+ // 50. xop
+ // 51. skinit
+ // 52. tbm
+ // 53. intel quirks
+ // 54. amd quirks
+ // 55. avx (intel ?, amd ?)
+ flags: u64,
+}
+
+impl InstDecoder {
+ /// Instantiates an x86_64 decoder that decodes the bare minimum of x86_64.
+ ///
+ /// Pedantic and only decodes what the spec says is well-defined, rejecting undefined sequences
+ /// and any instructions defined by extensions.
+ pub fn minimal() -> Self {
+ InstDecoder {
+ flags: 0,
+ }
+ }
+
+ pub fn sse3(&self) -> bool {
+ self.flags & (1 << 0) != 0
+ }
+
+ pub fn with_sse3(mut self) -> Self {
+ self.flags |= 1 << 0;
+ self
+ }
+
+ pub fn ssse3(&self) -> bool {
+ self.flags & (1 << 1) != 0
+ }
+
+ pub fn with_ssse3(mut self) -> Self {
+ self.flags |= 1 << 1;
+ self
+ }
+
+ pub fn monitor(&self) -> bool {
+ self.flags & (1 << 2) != 0
+ }
+
+ pub fn with_monitor(mut self) -> Self {
+ self.flags |= 1 << 2;
+ self
+ }
+
+ pub fn vmx(&self) -> bool {
+ self.flags & (1 << 3) != 0
+ }
+
+ pub fn with_vmx(mut self) -> Self {
+ self.flags |= 1 << 3;
+ self
+ }
+
+ pub fn fma3(&self) -> bool {
+ self.flags & (1 << 4) != 0
+ }
+
+ pub fn with_fma3(mut self) -> Self {
+ self.flags |= 1 << 4;
+ self
+ }
+
+ pub fn cmpxchg16b(&self) -> bool {
+ self.flags & (1 << 5) != 0
+ }
+
+ pub fn with_cmpxchg16b(mut self) -> Self {
+ self.flags |= 1 << 5;
+ self
+ }
+
+ pub fn sse4_1(&self) -> bool {
+ self.flags & (1 << 6) != 0
+ }
+
+ pub fn with_sse4_1(mut self) -> Self {
+ self.flags |= 1 << 6;
+ self
+ }
+
+ pub fn sse4_2(&self) -> bool {
+ self.flags & (1 << 7) != 0
+ }
+
+ pub fn with_sse4_2(mut self) -> Self {
+ self.flags |= 1 << 7;
+ self
+ }
+
+ pub fn movbe(&self) -> bool {
+ self.flags & (1 << 8) != 0
+ }
+
+ pub fn with_movbe(mut self) -> Self {
+ self.flags |= 1 << 8;
+ self
+ }
+
+ pub fn popcnt(&self) -> bool {
+ self.flags & (1 << 9) != 0
+ }
+
+ pub fn with_popcnt(mut self) -> Self {
+ self.flags |= 1 << 9;
+ self
+ }
+
+ pub fn aesni(&self) -> bool {
+ self.flags & (1 << 10) != 0
+ }
+
+ pub fn with_aesni(mut self) -> Self {
+ self.flags |= 1 << 10;
+ self
+ }
+
+ pub fn xsave(&self) -> bool {
+ self.flags & (1 << 11) != 0
+ }
+
+ pub fn with_xsave(mut self) -> Self {
+ self.flags |= 1 << 11;
+ self
+ }
+
+ pub fn rdrand(&self) -> bool {
+ self.flags & (1 << 12) != 0
+ }
+
+ pub fn with_rdrand(mut self) -> Self {
+ self.flags |= 1 << 12;
+ self
+ }
+
+ pub fn sgx(&self) -> bool {
+ self.flags & (1 << 13) != 0
+ }
+
+ pub fn with_sgx(mut self) -> Self {
+ self.flags |= 1 << 13;
+ self
+ }
+
+ pub fn bmi1(&self) -> bool {
+ self.flags & (1 << 14) != 0
+ }
+
+ pub fn with_bmi1(mut self) -> Self {
+ self.flags |= 1 << 14;
+ self
+ }
+
+ pub fn avx2(&self) -> bool {
+ self.flags & (1 << 15) != 0
+ }
+
+ pub fn with_avx2(mut self) -> Self {
+ self.flags |= 1 << 15;
+ self
+ }
+
+ pub fn bmi2(&self) -> bool {
+ self.flags & (1 << 16) != 0
+ }
+
+ pub fn with_bmi2(mut self) -> Self {
+ self.flags |= 1 << 16;
+ self
+ }
+
+ pub fn invpcid(&self) -> bool {
+ self.flags & (1 << 17) != 0
+ }
+
+ pub fn with_invpcid(mut self) -> Self {
+ self.flags |= 1 << 17;
+ self
+ }
+
+ pub fn mpx(&self) -> bool {
+ self.flags & (1 << 18) != 0
+ }
+
+ pub fn with_mpx(mut self) -> Self {
+ self.flags |= 1 << 18;
+ self
+ }
+
+ pub fn avx512_f(&self) -> bool {
+ self.flags & (1 << 19) != 0
+ }
+
+ pub fn with_avx512_f(mut self) -> Self {
+ self.flags |= 1 << 19;
+ self
+ }
+
+ pub fn avx512_dq(&self) -> bool {
+ self.flags & (1 << 20) != 0
+ }
+
+ pub fn with_avx512_dq(mut self) -> Self {
+ self.flags |= 1 << 20;
+ self
+ }
+
+ pub fn rdseed(&self) -> bool {
+ self.flags & (1 << 21) != 0
+ }
+
+ pub fn with_rdseed(mut self) -> Self {
+ self.flags |= 1 << 21;
+ self
+ }
+
+ pub fn adx(&self) -> bool {
+ self.flags & (1 << 22) != 0
+ }
+
+ pub fn with_adx(mut self) -> Self {
+ self.flags |= 1 << 22;
+ self
+ }
+
+ pub fn avx512_fma(&self) -> bool {
+ self.flags & (1 << 23) != 0
+ }
+
+ pub fn with_avx512_fma(mut self) -> Self {
+ self.flags |= 1 << 23;
+ self
+ }
+
+ pub fn pcommit(&self) -> bool {
+ self.flags & (1 << 24) != 0
+ }
+
+ pub fn with_pcommit(mut self) -> Self {
+ self.flags |= 1 << 24;
+ self
+ }
+
+ pub fn clflushopt(&self) -> bool {
+ self.flags & (1 << 25) != 0
+ }
+
+ pub fn with_clflushopt(mut self) -> Self {
+ self.flags |= 1 << 25;
+ self
+ }
+
+ pub fn clwb(&self) -> bool {
+ self.flags & (1 << 26) != 0
+ }
+
+ pub fn with_clwb(mut self) -> Self {
+ self.flags |= 1 << 26;
+ self
+ }
+
+ pub fn avx512_pf(&self) -> bool {
+ self.flags & (1 << 27) != 0
+ }
+
+ pub fn with_avx512_pf(mut self) -> Self {
+ self.flags |= 1 << 27;
+ self
+ }
+
+ pub fn avx512_er(&self) -> bool {
+ self.flags & (1 << 28) != 0
+ }
+
+ pub fn with_avx512_er(mut self) -> Self {
+ self.flags |= 1 << 28;
+ self
+ }
+
+ pub fn avx512_cd(&self) -> bool {
+ self.flags & (1 << 29) != 0
+ }
+
+ pub fn with_avx512_cd(mut self) -> Self {
+ self.flags |= 1 << 29;
+ self
+ }
+
+ pub fn sha(&self) -> bool {
+ self.flags & (1 << 30) != 0
+ }
+
+ pub fn with_sha(mut self) -> Self {
+ self.flags |= 1 << 30;
+ self
+ }
+
+ pub fn avx512_bw(&self) -> bool {
+ self.flags & (1 << 31) != 0
+ }
+
+ pub fn with_avx512_bw(mut self) -> Self {
+ self.flags |= 1 << 31;
+ self
+ }
+
+ pub fn avx512_vl(&self) -> bool {
+ self.flags & (1 << 32) != 0
+ }
+
+ pub fn with_avx512_vl(mut self) -> Self {
+ self.flags |= 1 << 32;
+ self
+ }
+
+ pub fn prefetchwt1(&self) -> bool {
+ self.flags & (1 << 33) != 0
+ }
+
+ pub fn with_prefetchwt1(mut self) -> Self {
+ self.flags |= 1 << 33;
+ self
+ }
+
+ pub fn avx512_vbmi(&self) -> bool {
+ self.flags & (1 << 34) != 0
+ }
+
+ pub fn with_avx512_vbmi(mut self) -> Self {
+ self.flags |= 1 << 34;
+ self
+ }
+
+ pub fn avx512_vbmi2(&self) -> bool {
+ self.flags & (1 << 35) != 0
+ }
+
+ pub fn with_avx512_vbmi2(mut self) -> Self {
+ self.flags |= 1 << 35;
+ self
+ }
+
+ pub fn gfni(&self) -> bool {
+ self.flags & (1 << 36) != 0
+ }
+
+ pub fn with_gfni(mut self) -> Self {
+ self.flags |= 1 << 36;
+ self
+ }
+
+ pub fn vaes(&self) -> bool {
+ self.flags & (1 << 37) != 0
+ }
+
+ pub fn with_vaes(mut self) -> Self {
+ self.flags |= 1 << 37;
+ self
+ }
+
+ pub fn pclmulqdq(&self) -> bool {
+ self.flags & (1 << 38) != 0
+ }
+
+ pub fn with_pclmulqdq(mut self) -> Self {
+ self.flags |= 1 << 38;
+ self
+ }
+
+ pub fn avx_vnni(&self) -> bool {
+ self.flags & (1 << 39) != 0
+ }
+
+ pub fn with_avx_vnni(mut self) -> Self {
+ self.flags |= 1 << 39;
+ self
+ }
+
+ pub fn avx512_bitalg(&self) -> bool {
+ self.flags & (1 << 40) != 0
+ }
+
+ pub fn with_avx512_bitalg(mut self) -> Self {
+ self.flags |= 1 << 40;
+ self
+ }
+
+ pub fn avx512_vpopcntdq(&self) -> bool {
+ self.flags & (1 << 41) != 0
+ }
+
+ pub fn with_avx512_vpopcntdq(mut self) -> Self {
+ self.flags |= 1 << 41;
+ self
+ }
+
+ pub fn avx512_4vnniw(&self) -> bool {
+ self.flags & (1 << 42) != 0
+ }
+
+ pub fn with_avx512_4vnniw(mut self) -> Self {
+ self.flags |= 1 << 42;
+ self
+ }
+
+ pub fn avx512_4fmaps(&self) -> bool {
+ self.flags & (1 << 43) != 0
+ }
+
+ pub fn with_avx512_4fmaps(mut self) -> Self {
+ self.flags |= 1 << 43;
+ self
+ }
+
+ pub fn cx8(&self) -> bool {
+ self.flags & (1 << 44) != 0
+ }
+
+ pub fn with_cx8(mut self) -> Self {
+ self.flags |= 1 << 44;
+ self
+ }
+
+ pub fn syscall(&self) -> bool {
+ self.flags & (1 << 45) != 0
+ }
+
+ pub fn with_syscall(mut self) -> Self {
+ self.flags |= 1 << 45;
+ self
+ }
+
+ pub fn rdtscp(&self) -> bool {
+ self.flags & (1 << 46) != 0
+ }
+
+ pub fn with_rdtscp(mut self) -> Self {
+ self.flags |= 1 << 46;
+ self
+ }
+
+ pub fn abm(&self) -> bool {
+ self.flags & (1 << 47) != 0
+ }
+
+ pub fn with_abm(mut self) -> Self {
+ self.flags |= 1 << 47;
+ self
+ }
+
+ pub fn sse4a(&self) -> bool {
+ self.flags & (1 << 48) != 0
+ }
+
+ pub fn with_sse4a(mut self) -> Self {
+ self.flags |= 1 << 48;
+ self
+ }
+
+ pub fn _3dnowprefetch(&self) -> bool {
+ self.flags & (1 << 49) != 0
+ }
+
+ pub fn with_3dnowprefetch(mut self) -> Self {
+ self.flags |= 1 << 49;
+ self
+ }
+
+ pub fn xop(&self) -> bool {
+ self.flags & (1 << 50) != 0
+ }
+
+ pub fn with_xop(mut self) -> Self {
+ self.flags |= 1 << 50;
+ self
+ }
+
+ pub fn skinit(&self) -> bool {
+ self.flags & (1 << 51) != 0
+ }
+
+ pub fn with_skinit(mut self) -> Self {
+ self.flags |= 1 << 51;
+ self
+ }
+
+ pub fn tbm(&self) -> bool {
+ self.flags & (1 << 52) != 0
+ }
+
+ pub fn with_tbm(mut self) -> Self {
+ self.flags |= 1 << 52;
+ self
+ }
+
+ pub fn intel_quirks(&self) -> bool {
+ self.flags & (1 << 53) != 0
+ }
+
+ pub fn with_intel_quirks(mut self) -> Self {
+ self.flags |= 1 << 53;
+ self
+ }
+
+ pub fn amd_quirks(&self) -> bool {
+ self.flags & (1 << 54) != 0
+ }
+
+ pub fn with_amd_quirks(mut self) -> Self {
+ self.flags |= 1 << 54;
+ self
+ }
+
+ pub fn avx(&self) -> bool {
+ self.flags & (1 << 55) != 0
+ }
+
+ pub fn with_avx(mut self) -> Self {
+ self.flags |= 1 << 55;
+ self
+ }
+
+ /// Optionally reject or reinterpret instruction according to the decoder's
+ /// declared extensions.
+ fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), DecodeError> {
+ match inst.opcode {
+ Opcode::TZCNT => {
+ if !self.bmi1() {
+ // tzcnt is only supported if bmi1 is enabled. without bmi1, this decodes as
+ // bsf.
+ inst.opcode = Opcode::BSF;
+ }
+ }
+ Opcode::LDDQU |
+ Opcode::ADDSUBPS |
+ Opcode::ADDSUBPD |
+ Opcode::HADDPS |
+ Opcode::HSUBPS |
+ Opcode::HADDPD |
+ Opcode::HSUBPD |
+ Opcode::MOVSHDUP |
+ Opcode::MOVSLDUP |
+ Opcode::MOVDDUP |
+ Opcode::MONITOR |
+ Opcode::MWAIT => {
+ // via Intel section 5.7, SSE3 Instructions
+ if !self.sse3() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PHADDW |
+ Opcode::PHADDSW |
+ Opcode::PHADDD |
+ Opcode::PHSUBW |
+ Opcode::PHSUBSW |
+ Opcode::PHSUBD |
+ Opcode::PABSB |
+ Opcode::PABSW |
+ Opcode::PABSD |
+ Opcode::PMADDUBSW |
+ Opcode::PMULHRSU |
+ Opcode::PSHUFB |
+ Opcode::PSIGNB |
+ Opcode::PSIGNW |
+ Opcode::PSIGND |
+ Opcode::PALIGNR => {
+ // via Intel section 5.8, SSSE3 Instructions
+ if !self.ssse3() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PMULLD |
+ Opcode::PMULDQ |
+ Opcode::MOVNTDQA |
+ Opcode::BLENDPD |
+ Opcode::BLENDPS |
+ Opcode::BLENDVPD |
+ Opcode::BLENDVPS |
+ Opcode::BLENDDVB |
+ Opcode::BLENDW |
+ Opcode::PMINUW |
+ Opcode::PMINUD |
+ Opcode::PMINSB |
+ Opcode::PMINSD |
+ Opcode::PMAXUW |
+ Opcode::PMAXUD |
+ Opcode::PMAXSB |
+ Opcode::ROUNDPS |
+ Opcode::ROUNDPD |
+ Opcode::ROUNDSS |
+ Opcode::ROUNDSD |
+ Opcode::EXTRACTPS |
+ Opcode::INSERTPS |
+ Opcode::PINSRB |
+ Opcode::PINSRD |
+ Opcode::PINSRQ |
+ Opcode::PEXTRB |
+ Opcode::PEXTRW |
+ Opcode::PEXTRQ |
+ Opcode::PMOVSXBW |
+ Opcode::PMOVZXBW |
+ Opcode::PMOVSXBD |
+ Opcode::PMOVZXBD |
+ Opcode::PMOVSXWD |
+ Opcode::PMOVZXWD |
+ Opcode::PMOVSXBQ |
+ Opcode::PMOVZXBQ |
+ Opcode::PMOVSXWQ |
+ Opcode::PMOVZXWQ |
+ Opcode::PMOVSXDQ |
+ Opcode::PMOVZXDQ |
+ Opcode::MPSADBW |
+ Opcode::PHMINPOSUW |
+ Opcode::PTEST |
+ Opcode::PCMPEQQ |
+ Opcode::PACKUSDW => {
+ // via Intel section 5.10, SSE4.1 Instructions
+ if !self.sse4_1() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PCMPESTRI |
+ Opcode::PCMPESTRM |
+ Opcode::PCMPISTRI |
+ Opcode::PCMPISTRM |
+ Opcode::PCMPGTQ => {
+ // via Intel section 5.11, SSE4.2 Instructions
+ if !self.sse4_2() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::AESDEC |
+ Opcode::AESDECLAST |
+ Opcode::AESENC |
+ Opcode::AESENCLAST |
+ Opcode::AESIMC |
+ Opcode::AESKEYGENASSIST => {
+ // via Intel section 5.12. AESNI AND PCLMULQDQ
+ if !self.aesni() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PCLMULQDQ => {
+ // via Intel section 5.12. AESNI AND PCLMULQDQ
+ if !self.pclmulqdq() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ // AVX...
+ /* // TODO
+ Opcode::XABORT |
+ Opcode::XACQUIRE |
+ Opcode::XRELEASE |
+ Opcode::XBEGIN |
+ Opcode::XEND |
+ Opcode::XTEST => {
+ if !self.tsx() {
+ inst.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }
+ */
+ /* // TODO
+ Opcode::SHA1MSG1 |
+ Opcode::SHA1MSG2 |
+ Opcode::SHA1NEXTE |
+ Opcode::SHA1RNDS4 |
+ Opcode::SHA256MSG1 |
+ Opcode::SHA256MSG2 |
+ Opcode::SHA256RNDS2 => {
+ if !self.sha() {
+ inst.opcode = Opcode::Invalid;
+ return Err(());
+ }
+ }*/
+ Opcode::ENCLV |
+ Opcode::ENCLS |
+ Opcode::ENCLU => {
+ if !self.sgx() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VMOVDDUP |
+ Opcode::VPSHUFLW |
+ Opcode::VHADDPS |
+ Opcode::VHSUBPS |
+ Opcode::VADDSUBPS |
+ Opcode::VCVTPD2DQ |
+ Opcode::VLDDQU |
+ Opcode::VCOMISD |
+ Opcode::VCOMISS |
+ Opcode::VUCOMISD |
+ Opcode::VUCOMISS |
+ Opcode::VADDPD |
+ Opcode::VADDPS |
+ Opcode::VADDSD |
+ Opcode::VADDSS |
+ Opcode::VADDSUBPD |
+ Opcode::VBLENDPD |
+ Opcode::VBLENDPS |
+ Opcode::VBLENDVPD |
+ Opcode::VBLENDVPS |
+ Opcode::VBROADCASTF128 |
+ Opcode::VBROADCASTI128 |
+ Opcode::VBROADCASTSD |
+ Opcode::VBROADCASTSS |
+ Opcode::VCMPSD |
+ Opcode::VCMPSS |
+ Opcode::VCMPPD |
+ Opcode::VCMPPS |
+ Opcode::VCVTDQ2PD |
+ Opcode::VCVTDQ2PS |
+ Opcode::VCVTPD2PS |
+ Opcode::VCVTPH2PS |
+ Opcode::VCVTPS2DQ |
+ Opcode::VCVTPS2PD |
+ Opcode::VCVTSS2SD |
+ Opcode::VCVTSI2SS |
+ Opcode::VCVTSI2SD |
+ Opcode::VCVTSD2SI |
+ Opcode::VCVTSD2SS |
+ Opcode::VCVTPS2PH |
+ Opcode::VCVTSS2SI |
+ Opcode::VCVTTPD2DQ |
+ Opcode::VCVTTPS2DQ |
+ Opcode::VCVTTSS2SI |
+ Opcode::VCVTTSD2SI |
+ Opcode::VDIVPD |
+ Opcode::VDIVPS |
+ Opcode::VDIVSD |
+ Opcode::VDIVSS |
+ Opcode::VDPPD |
+ Opcode::VDPPS |
+ Opcode::VEXTRACTF128 |
+ Opcode::VEXTRACTI128 |
+ Opcode::VEXTRACTPS |
+ Opcode::VFMADD132PD |
+ Opcode::VFMADD132PS |
+ Opcode::VFMADD132SD |
+ Opcode::VFMADD132SS |
+ Opcode::VFMADD213PD |
+ Opcode::VFMADD213PS |
+ Opcode::VFMADD213SD |
+ Opcode::VFMADD213SS |
+ Opcode::VFMADD231PD |
+ Opcode::VFMADD231PS |
+ Opcode::VFMADD231SD |
+ Opcode::VFMADD231SS |
+ Opcode::VFMADDSUB132PD |
+ Opcode::VFMADDSUB132PS |
+ Opcode::VFMADDSUB213PD |
+ Opcode::VFMADDSUB213PS |
+ Opcode::VFMADDSUB231PD |
+ Opcode::VFMADDSUB231PS |
+ Opcode::VFMSUB132PD |
+ Opcode::VFMSUB132PS |
+ Opcode::VFMSUB132SD |
+ Opcode::VFMSUB132SS |
+ Opcode::VFMSUB213PD |
+ Opcode::VFMSUB213PS |
+ Opcode::VFMSUB213SD |
+ Opcode::VFMSUB213SS |
+ Opcode::VFMSUB231PD |
+ Opcode::VFMSUB231PS |
+ Opcode::VFMSUB231SD |
+ Opcode::VFMSUB231SS |
+ Opcode::VFMSUBADD132PD |
+ Opcode::VFMSUBADD132PS |
+ Opcode::VFMSUBADD213PD |
+ Opcode::VFMSUBADD213PS |
+ Opcode::VFMSUBADD231PD |
+ Opcode::VFMSUBADD231PS |
+ Opcode::VFNMADD132PD |
+ Opcode::VFNMADD132PS |
+ Opcode::VFNMADD132SD |
+ Opcode::VFNMADD132SS |
+ Opcode::VFNMADD213PD |
+ Opcode::VFNMADD213PS |
+ Opcode::VFNMADD213SD |
+ Opcode::VFNMADD213SS |
+ Opcode::VFNMADD231PD |
+ Opcode::VFNMADD231PS |
+ Opcode::VFNMADD231SD |
+ Opcode::VFNMADD231SS |
+ Opcode::VFNMSUB132PD |
+ Opcode::VFNMSUB132PS |
+ Opcode::VFNMSUB132SD |
+ Opcode::VFNMSUB132SS |
+ Opcode::VFNMSUB213PD |
+ Opcode::VFNMSUB213PS |
+ Opcode::VFNMSUB213SD |
+ Opcode::VFNMSUB213SS |
+ Opcode::VFNMSUB231PD |
+ Opcode::VFNMSUB231PS |
+ Opcode::VFNMSUB231SD |
+ Opcode::VFNMSUB231SS |
+ Opcode::VGATHERDPD |
+ Opcode::VGATHERDPS |
+ Opcode::VGATHERQPD |
+ Opcode::VGATHERQPS |
+ Opcode::VHADDPD |
+ Opcode::VHSUBPD |
+ Opcode::VINSERTF128 |
+ Opcode::VINSERTI128 |
+ Opcode::VINSERTPS |
+ Opcode::VMASKMOVDQU |
+ Opcode::VMASKMOVPD |
+ Opcode::VMASKMOVPS |
+ Opcode::VMAXPD |
+ Opcode::VMAXPS |
+ Opcode::VMAXSD |
+ Opcode::VMAXSS |
+ Opcode::VMINPD |
+ Opcode::VMINPS |
+ Opcode::VMINSD |
+ Opcode::VMINSS |
+ Opcode::VMOVAPD |
+ Opcode::VMOVAPS |
+ Opcode::VMOVD |
+ Opcode::VMOVDQA |
+ Opcode::VMOVDQU |
+ Opcode::VMOVHLPS |
+ Opcode::VMOVHPD |
+ Opcode::VMOVHPS |
+ Opcode::VMOVLHPS |
+ Opcode::VMOVLPD |
+ Opcode::VMOVLPS |
+ Opcode::VMOVMSKPD |
+ Opcode::VMOVMSKPS |
+ Opcode::VMOVNTDQ |
+ Opcode::VMOVNTDQA |
+ Opcode::VMOVNTPD |
+ Opcode::VMOVNTPS |
+ Opcode::VMOVQ |
+ Opcode::VMOVSS |
+ Opcode::VMOVSD |
+ Opcode::VMOVSHDUP |
+ Opcode::VMOVSLDUP |
+ Opcode::VMOVUPD |
+ Opcode::VMOVUPS |
+ Opcode::VMPSADBW |
+ Opcode::VMULPD |
+ Opcode::VMULPS |
+ Opcode::VMULSD |
+ Opcode::VMULSS |
+ Opcode::VPABSB |
+ Opcode::VPABSD |
+ Opcode::VPABSW |
+ Opcode::VPACKSSDW |
+ Opcode::VPACKSSWB |
+ Opcode::VPACKUSWB |
+ Opcode::VPADDB |
+ Opcode::VPADDD |
+ Opcode::VPADDQ |
+ Opcode::VPADDSB |
+ Opcode::VPADDSW |
+ Opcode::VPADDUSB |
+ Opcode::VPADDUSW |
+ Opcode::VPADDW |
+ Opcode::VPALIGNR |
+ Opcode::VPAND |
+ Opcode::VPANDN |
+ Opcode::VPAVGB |
+ Opcode::VPAVGW |
+ Opcode::VPBLENDD |
+ Opcode::VPBLENDVB |
+ Opcode::VPBLENDW |
+ Opcode::VPBROADCASTB |
+ Opcode::VPBROADCASTD |
+ Opcode::VPBROADCASTQ |
+ Opcode::VPBROADCASTW |
+ Opcode::VPCLMULQDQ |
+ Opcode::VPCMPEQB |
+ Opcode::VPCMPEQD |
+ Opcode::VPCMPEQQ |
+ Opcode::VPCMPEQW |
+ Opcode::VPCMPGTB |
+ Opcode::VPCMPGTD |
+ Opcode::VPCMPGTQ |
+ Opcode::VPCMPGTW |
+ Opcode::VPCMPISTRI |
+ Opcode::VPCMPISTRM |
+ Opcode::VPERM2F128 |
+ Opcode::VPERM2I128 |
+ Opcode::VPERMD |
+ Opcode::VPERMILPD |
+ Opcode::VPERMILPS |
+ Opcode::VPERMPD |
+ Opcode::VPERMPS |
+ Opcode::VPERMQ |
+ Opcode::VPEXTRB |
+ Opcode::VPEXTRD |
+ Opcode::VPEXTRQ |
+ Opcode::VPEXTRW |
+ Opcode::VPGATHERDD |
+ Opcode::VPGATHERDQ |
+ Opcode::VPGATHERQD |
+ Opcode::VPGATHERQQ |
+ Opcode::VPHADDD |
+ Opcode::VPHADDSW |
+ Opcode::VPHADDW |
+ Opcode::VPHADDUBSW |
+ Opcode::VPHMINPOSUW |
+ Opcode::VPHSUBD |
+ Opcode::VPHSUBSW |
+ Opcode::VPHSUBW |
+ Opcode::VPINSRB |
+ Opcode::VPINSRD |
+ Opcode::VPINSRQ |
+ Opcode::VPINSRW |
+ Opcode::VPMADDWD |
+ Opcode::VPMASKMOVD |
+ Opcode::VPMASKMOVQ |
+ Opcode::VPMAXSB |
+ Opcode::VPMAXSD |
+ Opcode::VPMAXSW |
+ Opcode::VPMAXUD |
+ Opcode::VPMINSD |
+ Opcode::VPMINUD |
+ Opcode::VPMOVMSKB |
+ Opcode::VPMOVSXBD |
+ Opcode::VPMOVSXBQ |
+ Opcode::VPMOVSXBW |
+ Opcode::VPMOVSXDQ |
+ Opcode::VPMOVSXWD |
+ Opcode::VPMOVSXWQ |
+ Opcode::VPMOVZXBD |
+ Opcode::VPMOVZXBQ |
+ Opcode::VPMOVZXBW |
+ Opcode::VPMOVZXDQ |
+ Opcode::VPMOVZXWD |
+ Opcode::VPMOVZXWQ |
+ Opcode::VPMULDQ |
+ Opcode::VPMULHRSW |
+ Opcode::VPMULHUW |
+ Opcode::VPMULHW |
+ Opcode::VPMULLD |
+ Opcode::VPMULLW |
+ Opcode::VPMULUDQ |
+ Opcode::VPOR |
+ Opcode::VPSADBW |
+ Opcode::VPSHUFB |
+ Opcode::VPSHUFD |
+ Opcode::VPSIGNB |
+ Opcode::VPSIGND |
+ Opcode::VPSIGNW |
+ Opcode::VPSLLD |
+ Opcode::VPSLLDQ |
+ Opcode::VPSLLQ |
+ Opcode::VPSLLVD |
+ Opcode::VPSLLVQ |
+ Opcode::VPSLLW |
+ Opcode::VPSRAD |
+ Opcode::VPSRAVD |
+ Opcode::VPSRAW |
+ Opcode::VPSRLD |
+ Opcode::VPSRLDQ |
+ Opcode::VPSRLQ |
+ Opcode::VPSRLVD |
+ Opcode::VPSRLVQ |
+ Opcode::VPSRLW |
+ Opcode::VPSUBB |
+ Opcode::VPSUBD |
+ Opcode::VPSUBQ |
+ Opcode::VPSUBSB |
+ Opcode::VPSUBSW |
+ Opcode::VPSUBUSB |
+ Opcode::VPSUBUSW |
+ Opcode::VPSUBW |
+ Opcode::VPTEST |
+ Opcode::VPUNPCKHBW |
+ Opcode::VPUNPCKHDQ |
+ Opcode::VPUNPCKHQDQ |
+ Opcode::VPUNPCKHWD |
+ Opcode::VPUNPCKLBW |
+ Opcode::VPUNPCKLDQ |
+ Opcode::VPUNPCKLQDQ |
+ Opcode::VPUNPCKLWD |
+ Opcode::VPXOR |
+ Opcode::VRCPPS |
+ Opcode::VROUNDPD |
+ Opcode::VROUNDPS |
+ Opcode::VROUNDSD |
+ Opcode::VROUNDSS |
+ Opcode::VRSQRTPS |
+ Opcode::VRSQRTSS |
+ Opcode::VRCPSS |
+ Opcode::VSHUFPD |
+ Opcode::VSHUFPS |
+ Opcode::VSQRTPD |
+ Opcode::VSQRTPS |
+ Opcode::VSQRTSS |
+ Opcode::VSQRTSD |
+ Opcode::VSUBPD |
+ Opcode::VSUBPS |
+ Opcode::VSUBSD |
+ Opcode::VSUBSS |
+ Opcode::VTESTPD |
+ Opcode::VTESTPS |
+ Opcode::VUNPCKHPD |
+ Opcode::VUNPCKHPS |
+ Opcode::VUNPCKLPD |
+ Opcode::VUNPCKLPS |
+ Opcode::VXORPD |
+ Opcode::VXORPS |
+ Opcode::VZEROUPPER => {
+ // TODO: check a table for these
+ if !self.avx() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VAESDEC |
+ Opcode::VAESDECLAST |
+ Opcode::VAESENC |
+ Opcode::VAESENCLAST |
+ Opcode::VAESIMC |
+ Opcode::VAESKEYGENASSIST => {
+ // TODO: check a table for these
+ if !self.avx() || !self.aesni() {
+ inst.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ other => {
+ if !self.bmi1() {
+ if BMI1.contains(&other) {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ }
+ Ok(())
+ }
+}
+
+impl Default for InstDecoder {
+ /// Instantiates an x86_64 decoder that probably decodes what you want.
+ ///
+ /// Attempts to match real processors in interpretation of undefined sequences, and decodes any
+ /// instruction defined in any extension.
+ fn default() -> Self {
+ Self {
+ flags: 0xffffffff_ffffffff,
+ }
+ }
+}
+
+impl Decoder<Instruction> for InstDecoder {
+ type Error = DecodeError;
+
+ fn decode<T: IntoIterator<Item=u8>>(&self, bytes: T) -> Result<Instruction, Self::Error> {
+ let mut instr = Instruction::invalid();
+ decode_one(self, bytes, &mut instr)
+ .map(|_: ()| instr)
+ }
+ fn decode_into<T: IntoIterator<Item=u8>>(&self, instr: &mut Instruction, bytes: T) -> Result<(), Self::Error> {
+ decode_one(self, bytes, instr)
+ }
+}
+
+impl Opcode {
+ pub fn condition(&self) -> Option<ConditionCode> {
+ match self {
+ Opcode::JO |
+ Opcode::CMOVO |
+ Opcode::SETO => { Some(ConditionCode::O) },
+ Opcode::JNO |
+ Opcode::CMOVNO |
+ Opcode::SETNO => { Some(ConditionCode::NO) },
+ Opcode::JB |
+ Opcode::CMOVB |
+ Opcode::SETB => { Some(ConditionCode::B) },
+ Opcode::JNB |
+ Opcode::CMOVNB |
+ Opcode::SETAE => { Some(ConditionCode::AE) },
+ Opcode::JZ |
+ Opcode::CMOVZ |
+ Opcode::SETZ => { Some(ConditionCode::Z) },
+ Opcode::JNZ |
+ Opcode::CMOVNZ |
+ Opcode::SETNZ => { Some(ConditionCode::NZ) },
+ Opcode::JA |
+ Opcode::CMOVA |
+ Opcode::SETA => { Some(ConditionCode::A) },
+ Opcode::JNA |
+ Opcode::CMOVNA |
+ Opcode::SETBE => { Some(ConditionCode::BE) },
+ Opcode::JS |
+ Opcode::CMOVS |
+ Opcode::SETS => { Some(ConditionCode::S) },
+ Opcode::JNS |
+ Opcode::CMOVNS |
+ Opcode::SETNS => { Some(ConditionCode::NS) },
+ Opcode::JP |
+ Opcode::CMOVP |
+ Opcode::SETP => { Some(ConditionCode::P) },
+ Opcode::JNP |
+ Opcode::CMOVNP |
+ Opcode::SETNP => { Some(ConditionCode::NP) },
+ Opcode::JL |
+ Opcode::CMOVL |
+ Opcode::SETL => { Some(ConditionCode::L) },
+ Opcode::JGE |
+ Opcode::CMOVGE |
+ Opcode::SETGE => { Some(ConditionCode::GE) },
+ Opcode::JG |
+ Opcode::CMOVG |
+ Opcode::SETG => { Some(ConditionCode::G) },
+ Opcode::JLE |
+ Opcode::CMOVLE |
+ Opcode::SETLE => { Some(ConditionCode::LE) },
+ _ => None,
+ }
+ }
+}
+
+impl Default for Instruction {
+ fn default() -> Self {
+ Instruction::invalid()
+ }
+}
+
+impl Instruction {
+ pub fn operand(&self, i: u8) -> Operand {
+ assert!(i < 4);
+ Operand::from_spec(self, self.operands[i as usize])
+ }
+
+ pub fn operand_count(&self) -> u8 {
+ let mut i = 0;
+ for op in self.operands.iter() {
+ if let OperandSpec::Nothing = op {
+ return i;
+ } else {
+ i += 1;
+ }
+ }
+ return i;
+ }
+
+ pub fn operand_present(&self, i: u8) -> bool {
+ assert!(i < 4);
+ if let OperandSpec::Nothing = self.operands[i as usize] {
+ false
+ } else {
+ true
+ }
+ }
+
+ pub fn invalid() -> Instruction {
+ Instruction {
+ prefixes: Prefixes::new(0),
+ opcode: Opcode::Invalid,
+ modrm_rrr: RegSpec::eax(),
+ modrm_mmm: RegSpec::eax(), // doubles as sib_base
+ sib_index: RegSpec::eax(),
+ vex_reg: RegSpec::eax(),
+ scale: 0,
+ length: 0,
+ disp: 0,
+ imm: 0,
+ operand_count: 0,
+ operands: [OperandSpec::Nothing; 4],
+ }
+ }
+
+ pub fn is_invalid(&self) -> bool {
+ match self.opcode {
+ Opcode::Invalid => true,
+ _ => false
+ }
+ }
+
+ pub fn segment_override_for_op(&self, op: u8) -> Option<Segment> {
+ match self.opcode {
+ Opcode::STOS => {
+ if op == 0 {
+ Some(Segment::ES)
+ } else {
+ None
+ }
+ }
+ Opcode::LODS => {
+ if op == 1 {
+ Some(self.prefixes.segment)
+ } else {
+ None
+ }
+ }
+ Opcode::MOVS => {
+ if op == 0 {
+ Some(Segment::ES)
+ } else if op == 1 {
+ Some(self.prefixes.segment)
+ } else {
+ None
+ }
+ }
+ Opcode::CMPS => {
+ if op == 0 {
+ Some(self.prefixes.segment)
+ } else if op == 1 {
+ Some(Segment::ES)
+ } else {
+ None
+ }
+ },
+ _ => {
+ // most operands are pretty simple:
+ if self.operands[op as usize].is_memory() &&
+ self.prefixes.segment != Segment::DS {
+ Some(self.prefixes.segment)
+ } else {
+ None
+ }
+ }
+ }
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct Prefixes {
+ bits: u8,
+ vex: PrefixVex,
+ segment: Segment,
+}
+
+#[derive(Debug, Copy, Clone)]
+pub struct PrefixVex {
+ bits: u8,
+}
+
+#[allow(dead_code)]
+impl PrefixVex {
+ #[inline]
+ fn b(&self) -> bool { (self.bits & 0x01) == 0x01 }
+ #[inline]
+ fn x(&self) -> bool { (self.bits & 0x02) == 0x02 }
+ #[inline]
+ fn r(&self) -> bool { (self.bits & 0x04) == 0x04 }
+ #[inline]
+ fn w(&self) -> bool { (self.bits & 0x08) == 0x08 }
+ #[inline]
+ fn l(&self) -> bool { (self.bits & 0x10) == 0x10 }
+ #[inline]
+ fn present(&self) -> bool { (self.bits & 0x80) == 0x80 }
+}
+
+#[allow(dead_code)]
+impl Prefixes {
+ fn new(bits: u8) -> Prefixes {
+ Prefixes {
+ bits: bits,
+ vex: PrefixVex {
+ bits: 0,
+ },
+ segment: Segment::DS,
+ }
+ }
+ fn vex_from(&mut self, bits: u8) {
+ self.vex = PrefixVex {
+ bits
+ };
+ }
+ #[inline]
+ fn rep(&self) -> bool { self.bits & 0x30 == 0x10 }
+ #[inline]
+ fn set_rep(&mut self) { self.bits = (self.bits & 0xcf) | 0x10 }
+ #[inline]
+ pub fn repz(&self) -> bool { self.bits & 0x30 == 0x20 }
+ #[inline]
+ fn set_repz(&mut self) { self.bits = (self.bits & 0xcf) | 0x20 }
+ #[inline]
+ pub fn repnz(&self) -> bool { self.bits & 0x30 == 0x30 }
+ #[inline]
+ fn set_repnz(&mut self) { self.bits = (self.bits & 0xcf) | 0x30 }
+ #[inline]
+ fn operand_size(&self) -> bool { self.bits & 0x1 == 1 }
+ #[inline]
+ fn set_operand_size(&mut self) { self.bits = self.bits | 0x1 }
+ #[inline]
+ fn address_size(&self) -> bool { self.bits & 0x2 == 2 }
+ #[inline]
+ fn set_address_size(&mut self) { self.bits = self.bits | 0x2 }
+ #[inline]
+ fn set_lock(&mut self) { self.bits |= 0x4 }
+ #[inline]
+ pub fn lock(&self) -> bool { self.bits & 0x4 == 4 }
+ #[inline]
+ fn cs(&mut self) { self.segment = Segment::CS }
+ #[inline]
+ fn set_cs(&mut self) { self.segment = Segment::CS }
+ #[inline]
+ pub fn ds(&self) -> bool { self.segment == Segment::DS }
+ #[inline]
+ fn set_ds(&mut self) { self.segment = Segment::DS }
+ #[inline]
+ pub fn es(&self) -> bool { self.segment == Segment::ES }
+ #[inline]
+ fn set_es(&mut self) { self.segment = Segment::ES }
+ #[inline]
+ pub fn fs(&self) -> bool { self.segment == Segment::FS }
+ #[inline]
+ fn set_fs(&mut self) { self.segment = Segment::FS }
+ #[inline]
+ pub fn gs(&self) -> bool { self.segment == Segment::GS }
+ #[inline]
+ fn set_gs(&mut self) { self.segment = Segment::GS }
+ #[inline]
+ pub fn ss(&self) -> bool { self.segment == Segment::SS }
+ #[inline]
+ fn set_ss(&mut self) { self.segment = Segment::SS }
+ #[inline]
+ fn vex(&self) -> PrefixVex { PrefixVex { bits: self.vex.bits } }
+
+ #[inline]
+ fn vex_from_c5(&mut self, bits: u8) {
+ // collect rex bits
+ let r = bits & 0x80;
+ let wrxb = (r >> 5) ^ 0x04;
+ let l = (bits & 0x04) << 2;
+ let synthetic_rex = wrxb | l | 0x80;
+ self.vex = PrefixVex { bits: synthetic_rex };
+ }
+
+ #[inline]
+ fn vex_from_c4(&mut self, high: u8, low: u8) {
+ let w = low & 0x80;
+ let rxb = (high >> 5) ^ 0x07;
+ let wrxb = rxb | w >> 4;
+ let l = (low & 0x04) << 2;
+ let synthetic_rex = wrxb | l | 0x80;
+ self.vex = PrefixVex { bits: synthetic_rex };
+ }
+}
+
+#[allow(non_camel_case_types)]
+// might be able to pack these into a u8, but with `Operand` being u16 as well now there's little
+// point. table entries will have a padding byte per record already.
+//
+// many of the one-off per-opcode variants could be written as 'decide based on opcode' but trying
+// to pack this more tightly only makes sense if opcode were smaller, to get some space savings.
+#[repr(u16)]
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum OperandCode {
+ ModRM_0x0f00,
+ ModRM_0x0f01,
+ ModRM_0x0fae,
+ ModRM_0x0fba,
+ ModRM_0xf238,
+ ModRM_0xf30fc7,
+ ModRM_0x660f38,
+ ModRM_0x660f3a,
+ CVT_AA,
+ CVT_DA,
+ Rq_Cq_0,
+ Rq_Dq_0,
+ Cq_Rq_0,
+ Dq_Rq_0,
+ FS,
+ GS,
+ Yb_DX,
+ Yv_DX,
+ DX_Xb,
+ DX_Xv,
+ AH,
+ AX_Xv,
+ // DX_AX,
+ E_G_xmm,
+ // Ev_Ivs,
+ Ew_Sw,
+ Fw,
+ I_3,
+ Ib,
+ Ibs,
+ Ivs,
+ Iw,
+ Iw_Ib,
+ Jvds,
+ Ob_AL,
+ Ov_AX,
+ Sw_Ew,
+ Yb_AL,
+ Yb_Xb,
+ Yv_AX,
+ Yv_Xv,
+ G_E_q,
+ E_G_q,
+ Rv_Gmm_Ib,
+ G_mm_Ew_Ib,
+ Mq_Dq,
+ ModRM_0x0f38,
+ ModRM_0x0f3a,
+ ModRM_0x0f71,
+ ModRM_0x0f72,
+ ModRM_0x0f73,
+ ModRM_0x660f12,
+ ModRM_0x660f16,
+ ModRM_0x660f71,
+ ModRM_0x660f72,
+ ModRM_0x660f73,
+ ModRM_0x660fc7,
+ ModRM_0x0fc7,
+ ModRM_0xc4,
+ ModRM_0xc5,
+ Nothing,
+ // Implied,
+ Unsupported,
+ AL_Ib = 0x100,
+ AX_Ib = 0x101,
+ Ib_AL = 0x102,
+ Ib_AX = 0x103,
+ AX_DX = 0x104,
+ AL_DX = 0x105,
+ DX_AX = 0x106,
+ DX_AL = 0x107,
+ MOVQ_f30f = 0x108,
+ G_xmm_Ed_Ib = 0x1ef, // mirror G_xmm_Edq, but also read an immediate
+ Zv_R0 = 0x40,
+ Zv_R1 = 0x41,
+ Zv_R2 = 0x42,
+ Zv_R3 = 0x43,
+ Zv_R4 = 0x44,
+ Zv_R5 = 0x45,
+ Zv_R6 = 0x46,
+ Zv_R7 = 0x47,
+ // Zv_AX_R0 = 0x48,
+ Zv_AX_R1 = 0x49,
+ Zv_AX_R2 = 0x4a,
+ Zv_AX_R3 = 0x4b,
+ Zv_AX_R4 = 0x4c,
+ Zv_AX_R5 = 0x4d,
+ Zv_AX_R6 = 0x4e,
+ Zv_AX_R7 = 0x4f,
+ Zb_Ib_R0 = 0x50,
+ Zb_Ib_R1 = 0x51,
+ Zb_Ib_R2 = 0x52,
+ Zb_Ib_R3 = 0x53,
+ Zb_Ib_R4 = 0x54,
+ Zb_Ib_R5 = 0x55,
+ Zb_Ib_R6 = 0x56,
+ Zb_Ib_R7 = 0x57,
+ Zv_Iv_R0 = 0x58,
+ Zv_Iv_R1 = 0x59,
+ Zv_Iv_R2 = 0x5a,
+ Zv_Iv_R3 = 0x5b,
+ Zv_Iv_R4 = 0x5c,
+ Zv_Iv_R5 = 0x5d,
+ Zv_Iv_R6 = 0x5e,
+ Zv_Iv_R7 = 0x5f,
+ Gv_Eb = 0x60,
+ Gv_Ew = 0x61,
+ Ew_Gw = 0x62,
+ G_E_mm_Ib = 0x64,
+ G_E_xmm_Ib = 0x65,
+ AL_Ibs = 0x66,
+ AX_Ivd = 0x67,
+ AL_Ob = 0x68,
+ AL_Xb = 0x69,
+ AX_AL = 0x6a,
+ AX_Ov = 0x6b,
+
+ Eb_Gb = 0x80,
+ Ev_Gv = 0x81,
+ Gb_Eb = 0xc2,
+ Gv_Ev = 0xc3,
+ Gb_Eb_Ib = 0xc4,
+ Gv_Ev_Iv = 0xc5,
+ // gap: 0xc6
+ Gd_U_xmm = 0xc7,
+ Gv_E_xmm = 0x1c7,
+ M_G_xmm = 0xc9,
+ ModRM_0x0f12 = 0xcb,
+ ModRM_0x0f16 = 0xce,
+ ModRM_0xc0_Eb_Ib = 0x86,
+ ModRM_0xc1_Ev_Ib = 0x87,
+ ModRM_0xd0_Eb_1 = 0x88,
+ ModRM_0xd1_Ev_1 = 0x89,
+ ModRM_0xd2_Eb_CL = 0x8a,
+ ModRM_0xd3_Ev_CL = 0x8b,
+ ModRM_0x80_Eb_Ib = 0x8c,
+ ModRM_0x83_Ev_Ibs = 0x8d,
+ // this would be Eb_Ivs, 0x8e
+ ModRM_0x81_Ev_Ivs = 0x8f,
+ ModRM_0xc6_Eb_Ib = 0x90,
+ ModRM_0xc7_Ev_Iv = 0x91,
+ ModRM_0xfe_Eb = 0x92,
+ ModRM_0x8f_Ev = 0x93,
+ // gap, 0x94
+ ModRM_0xff_Ev = 0x95,
+ ModRM_0xf6 = 0x96,
+ ModRM_0xf7 = 0x97,
+ Eb_R0 = 0x98,
+ Ev = 0x99,
+ ModRM_0x0f18 = 0x9b,
+ // gap, 0x9a
+ Gv_M = 0xdb,
+ G_mm_Edq = 0xdd,
+ G_mm_E = 0xdf,
+ G_U_xmm = 0xe1,
+ G_xmm_Ed = 0xe3,
+ G_mm_E_xmm = 0xe5,
+ G_E_mm = 0xe7,
+ Edq_G_mm = 0xe9,
+ Edq_G_xmm = 0x1e9,
+ E_G_mm = 0xeb,
+ G_xmm_E_mm = 0xed,
+ G_xmm_U_mm = 0x1ed,
+ U_mm_G_xmm = 0x2ed,
+ G_xmm_Edq = 0xef,
+ 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 {
+ match v {
+ 0 => Opcode::ADD,
+ 1 => Opcode::OR,
+ 2 => Opcode::ADC,
+ 3 => Opcode::SBB,
+ 4 => Opcode::AND,
+ 5 => Opcode::SUB,
+ 6 => Opcode::XOR,
+ 7 => Opcode::CMP,
+ _ => { unsafe { unreachable_unchecked() } }
+ }
+}
+
+const BITWISE_OPCODE_MAP: [Opcode; 8] = [
+ Opcode::ROL,
+ Opcode::ROR,
+ Opcode::RCL,
+ Opcode::RCR,
+ Opcode::SHL,
+ Opcode::SHR,
+ Opcode::SAL,
+ Opcode::SAR
+];
+
+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::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::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::Invalid), OperandCode::Nothing),
+// 0x10
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPD), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f12),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPD), OperandCode::M_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKLPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKHPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPD), OperandCode::ModRM_0x660f16),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPD), OperandCode::M_G_xmm),
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x20
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPD), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPI2PD), OperandCode::G_xmm_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTPD), OperandCode::M_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPD2PI), OperandCode::G_mm_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2PI), OperandCode::G_mm_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UCOMISD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::COMISD), OperandCode::G_E_xmm),
+// 0x30
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f38),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f3a),
+ 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),
+// 0x40
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x50
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVMSKPD), OperandCode::Gd_U_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SQRTPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ANDPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ANDNPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ORPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XORPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADDPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MULPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2PS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2DQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUBPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MINPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DIVPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MAXPD), OperandCode::G_E_xmm),
+// 0x60
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLBW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLWD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLDQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSWB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSWB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHBW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHWD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHDQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSDW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLQDQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHQDQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::G_xmm_Ed),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQA), OperandCode::G_E_xmm),
+// 0x70
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFD), OperandCode::G_E_xmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f71),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f72),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f73),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), 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),
+ 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::MOVD), OperandCode::Edq_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQA), OperandCode::E_G_xmm),
+// 0x80
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x90
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xa0
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xb0
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xc0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPPD), OperandCode::G_E_xmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_xmm_Ed_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::G_E_xmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPD), OperandCode::G_E_xmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660fc7),
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0xd0
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRLW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRLD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRLQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULLW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMOVMSKB), OperandCode::Gd_U_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::G_E_xmm),
+// 0xe0
+ OpcodeRecord(Interpretation::Instruction(Opcode::PAVGB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPD2DQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTDQ), OperandCode::M_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PXOR), OperandCode::G_E_xmm),
+// 0xf0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSLLW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVDQU), OperandCode::G_U_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_xmm),
+];
+
+fn read_opcode_660f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u8) -> Result<(OpcodeRecord, u8), DecodeError> {
+ bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| {
+ *length += 1;
+ (OPCODE_660F_MAP[b as usize], b)
+ })
+}
+
+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::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::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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x10
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSD), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVDDUP), 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),
+ 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::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),
+// 0x20
+ 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::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::CVTSI2SD), OperandCode::G_xmm_Edq),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTTSD2SI), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTSD2SI), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x30
+ 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::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::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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x40
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x50
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SQRTSD), 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),
+ 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::ADDSD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MULSD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTSD2SS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUBSD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MINSD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DIVSD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MAXSD), OperandCode::G_E_xmm),
+// 0x60
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x70
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFLW), OperandCode::G_E_xmm_Ib),
+ 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::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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::HADDPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x80
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x90
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xa0
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xb0
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xc0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPSD), OperandCode::G_E_xmm_Ib),
+ 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::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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0xd0
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPS), 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),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQ2Q), OperandCode::U_mm_G_xmm),
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0xe0
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2DQ), 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),
+ 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::Invalid), OperandCode::Nothing),
+// 0xf0
+ 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),
+ 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::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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+];
+
+fn read_opcode_f20f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u8) -> Result<(OpcodeRecord, u8), DecodeError> {
+ bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| {
+ *length += 1;
+ (OPCODE_F20F_MAP[b as usize], b)
+ })
+}
+
+const OPCODE_F30F_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::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::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::Invalid), OperandCode::Nothing),
+// 0x10
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSS), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSLDUP), 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),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSHDUP), 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),
+ 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::Invalid), OperandCode::Nothing),
+// 0x20
+ 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::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::CVTSI2SS), OperandCode::G_xmm_Edq),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTTSS2SI), OperandCode::Gv_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTSS2SI), OperandCode::Gv_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x30
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x40
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x50
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SQRTSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RSQRTSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RCPSS), 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),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADDSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MULSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTSS2SD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPS2DQ), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUBSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MINSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DIVSS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MAXSS), OperandCode::G_E_xmm),
+// 0x60
+ 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::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::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::MOVDQU), OperandCode::G_E_xmm),
+// 0x70
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFHW), OperandCode::G_E_xmm_Ib),
+ 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::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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::MOVQ_f30f),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQU), OperandCode::E_G_xmm),
+// 0x80
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0x90
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xa0
+ 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::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::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::Invalid), OperandCode::Nothing),
+// 0xb0
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POPCNT), OperandCode::Gv_Ev),
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0xc0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPSS), OperandCode::G_E_xmm_Ib),
+ 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::ModRM_0xf30fc7),
+ 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::Invalid), OperandCode::Nothing),
+ 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::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::MOVQ2DQ), OperandCode::G_xmm_U_mm),
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0xe0
+ 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::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTDQ2PD), 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),
+ 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::Invalid), OperandCode::Nothing),
+// 0xf0
+ 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::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::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::Invalid), OperandCode::Nothing),
+];
+
+fn read_opcode_f30f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u8) -> Result<(OpcodeRecord, u8), DecodeError> {
+ bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| {
+ *length += 1;
+ (OPCODE_F30F_MAP[b as usize], b)
+ })
+ /*
+ match bytes_iter.next() {
+ Some(b) => {
+ *length += 1;
+ match b {
+ 0x10 => { instruction.opcode = Opcode::MOVSS; Some(OperandCode::G_E_xmm) },
+ 0x11 => { instruction.opcode = Opcode::MOVSS; Some(OperandCode::E_G_xmm) },
+ 0x12 => { instruction.opcode = Opcode::MOVSLDUP; Some(OperandCode::G_E_xmm) },
+ 0x2a => { instruction.opcode = Opcode::CVTSI2SS; Some(OperandCode::G_E_xmm) },
+ 0x2c => { instruction.opcode = Opcode::CVTTSS2SI; Some(OperandCode::G_E_xmm) },
+ 0x2d => { instruction.opcode = Opcode::CVTSS2SI; Some(OperandCode::G_E_xmm) },
+ 0x51 => { instruction.opcode = Opcode::SQRTSS; Some(OperandCode::G_E_xmm) },
+ 0x58 => { instruction.opcode = Opcode::ADDSS; Some(OperandCode::G_E_xmm) },
+ 0x59 => { instruction.opcode = Opcode::MULSS; Some(OperandCode::G_E_xmm) },
+ 0x5a => { instruction.opcode = Opcode::CVTSS2SD; Some(OperandCode::G_E_xmm) },
+ 0x5c => { instruction.opcode = Opcode::SUBSS; Some(OperandCode::G_E_xmm) },
+ 0x5d => { instruction.opcode = Opcode::MINSS; Some(OperandCode::G_E_xmm) },
+ 0x5e => { instruction.opcode = Opcode::DIVSS; Some(OperandCode::G_E_xmm) },
+ 0x5f => { instruction.opcode = Opcode::MAXSS; Some(OperandCode::G_E_xmm) },
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ Some(OperandCode::Nothing)
+ }
+ }
+ }
+ None => {
+ None
+ }
+ }
+ */
+}
+const OPCODE_0F_MAP: [OpcodeRecord; 256] = [
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_M),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x10
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f12),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPS), OperandCode::M_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKLPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKHPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f16),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPS), OperandCode::M_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev),
+// 0x20
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0),
+ 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::MOVAPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPS), OperandCode::E_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPI2PS), OperandCode::G_xmm_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTPS), OperandCode::M_G_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPS2PI), OperandCode::G_mm_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2PI), OperandCode::G_mm_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::UCOMISS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::COMISS), OperandCode::G_E_xmm),
+
+// 0x30
+ OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::GETSEC), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f38),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f3a),
+ 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),
+
+// 0x40
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev),
+
+// 0x50
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVMSKPS), OperandCode::Gd_U_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SQRTPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RSQRTPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RCPPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ANDPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ANDNPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ORPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XORPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADDPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MULPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2PD), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CVTDQ2PS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUBPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MINPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DIVPS), OperandCode::G_E_xmm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MAXPS), OperandCode::G_E_xmm),
+
+// 0x60
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLBW), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLWD), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLDQ), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSWB), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTB), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTW), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTD), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSWB), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHBW), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHWD), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHDQ), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSDW), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::G_mm_Edq),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::G_mm_E),
+
+// 0x70
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFW), OperandCode::G_E_mm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f71),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f72),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f73),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::EMMS), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_q),
+ OpcodeRecord(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_q),
+ 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::MOVD), OperandCode::Edq_G_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::E_G_mm),
+
+// 0x80
+ OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds),
+
+// 0x90
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0),
+
+// 0xa0
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev),
+
+// 0xb0
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::Gv_M),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::E_G_q),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::Gv_M),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::Gv_M),
+ 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::Invalid), OperandCode::ModRM_0x0fba),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::TZCNT), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX_b), OperandCode::Gv_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX_w), OperandCode::Gv_Ew),
+
+// 0xc0
+ OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPPS), OperandCode::G_E_xmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTI), OperandCode::Mq_Dq),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_mm_Ew_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::Rv_Gmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPS), OperandCode::G_E_xmm_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7),
+
+// 0xd0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRLW), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRLD), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRLQ), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULLW), OperandCode::G_E_mm),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMOVMSKB), OperandCode::G_U_mm),
+
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::Unsupported),
+
+// 0xe0
+ OpcodeRecord(Interpretation::Instruction(Opcode::PAVGB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PXOR), OperandCode::G_E_mm),
+// 0xf0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSLLW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::Unsupported),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+];
+fn read_opcode_0f_map<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u8) -> Result<OpcodeRecord, DecodeError> {
+ bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| {
+ *length += 1;
+ OPCODE_0F_MAP[b as usize]
+ })
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Interpretation {
+ Instruction(Opcode),
+ Prefix,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+// this should be a 32-byte struct..
+struct OpcodeRecord(Interpretation, OperandCode);
+
+#[test]
+fn opcode_record_size() {
+ // there are more than 256 opcodes...
+ assert_eq!(core::mem::size_of::<OpcodeRecord>(), 4);
+}
+
+const OPCODES: [OpcodeRecord; 256] = [
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+// 0x40:
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R7),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R7),
+// 0x50:
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R7),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R7),
+// 0x60
+ 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::ARPL), OperandCode::Ew_Gw),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ivs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Iv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gb_Eb_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INS), OperandCode::Yb_DX),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INS), OperandCode::Yv_DX),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OUTS), OperandCode::DX_Xb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OUTS), OperandCode::DX_Xv),
+// 0x70
+ OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Ibs),
+// 0x80
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x80_Eb_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x81_Ev_Ivs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ 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::MOV), OperandCode::Eb_Gb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ev_Gv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gb_Eb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gv_Ev),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ew_Sw),
+ 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_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R7),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_AA),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_DA),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::PUSHF), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::POPF), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SAHF), OperandCode::AH),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LAHF), OperandCode::AH),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::AL_Ob),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::AX_Ov),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ob_AL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ov_AX),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVS), OperandCode::Yb_Xb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOVS), OperandCode::Yv_Xv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPS), OperandCode::Yb_Xb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CMPS), OperandCode::Yv_Xv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::AL_Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::AX_Ivd),
+ OpcodeRecord(Interpretation::Instruction(Opcode::STOS), OperandCode::Yb_AL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::STOS), OperandCode::Yv_AX),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LODS), OperandCode::AL_Xb),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LODS), OperandCode::AX_Xv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SCAS), OperandCode::Yb_AL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::SCAS), OperandCode::Yv_AX),
+// 0xb0
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R7),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R0),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R2),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R7),
+// 0xc0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xc0_Eb_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xc1_Ev_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RETURN), OperandCode::Iw),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RETURN), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LES), OperandCode::ModRM_0xc4),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LDS), OperandCode::ModRM_0xc5),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::ModRM_0xc6_Eb_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::ModRM_0xc7_Ev_Iv),
+ OpcodeRecord(Interpretation::Instruction(Opcode::ENTER), OperandCode::Iw_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::LEAVE), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Iw),
+ OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::I_3),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::INTO), OperandCode::Fw),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IRET), OperandCode::Fw),
+// 0xd0
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd0_Eb_1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd1_Ev_1),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd2_Eb_CL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd3_Ev_CL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ // XLAT
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ // x86 d8
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 d9
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 da
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 db
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 dc
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 dd
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 de
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+ // x86 df
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported),
+// 0xe0
+ // LOOPNZ
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ // LOOPZ
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ // LOOP
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ // JECXZ
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AL_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AX_Ib),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AX),
+// 0xe8
+ OpcodeRecord(Interpretation::Instruction(Opcode::CALL), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JMP), OperandCode::Jvds),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::JMP), OperandCode::Ibs),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AL_DX),
+ OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AX_DX),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::DX_AL),
+ OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::DX_AX),
+// 0xf0
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ // ICEBP?
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing),
+// 0xf4
+ OpcodeRecord(Interpretation::Instruction(Opcode::HLT), OperandCode::Nothing),
+ // CMC
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf6),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf7),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CLC), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::STC), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CLI), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::STI), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::CLD), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::STD), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xfe_Eb),
+ // TODO: test 0xff /3
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xff_Ev),
+];
+
+#[allow(non_snake_case)]
+pub(self) fn read_E<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, width: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ let bank = width_to_gp_reg_bank(width);
+ if modrm >= 0b11000000 {
+ read_modrm_reg(instr, modrm, bank)
+ } else {
+ read_M(bytes_iter, instr, modrm, length)
+ }
+}
+#[allow(non_snake_case)]
+pub(self) fn read_E_xmm<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ if modrm >= 0b11000000 {
+ read_modrm_reg(instr, modrm, RegisterBank::X)
+ } else {
+ read_M(bytes_iter, instr, modrm, length)
+ }
+}
+#[allow(non_snake_case)]
+pub(self) fn read_E_ymm<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ if modrm >= 0b11000000 {
+ read_modrm_reg(instr, modrm, RegisterBank::Y)
+ } else {
+ read_M(bytes_iter, instr, modrm, length)
+ }
+}
+
+#[allow(non_snake_case)]
+fn read_modrm_reg(instr: &mut Instruction, modrm: u8, reg_bank: RegisterBank) -> Result<OperandSpec, DecodeError> {
+ instr.modrm_mmm = RegSpec::from_parts(modrm & 7, reg_bank);
+ Ok(OperandSpec::RegMMM)
+}
+
+#[allow(non_snake_case)]
+fn read_sib<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ let modbits = modrm >> 6;
+ let addr_width = if instr.prefixes.address_size() { RegisterBank::W } else { RegisterBank::D };
+ let sibbyte = bytes_iter.next().ok_or(DecodeError::ExhaustedInput)?;
+ *length += 1;
+
+ let op_spec = if (sibbyte & 7) == 0b101 {
+ let disp = if modbits == 0b00 {
+ *length += 4;
+ read_num(bytes_iter, 4)? as i32
+ } else if modbits == 0b01 {
+ *length += 1;
+ read_num(bytes_iter, 1)? as i8 as i32
+ } else {
+ *length += 4;
+ read_num(bytes_iter, 4)? as i32
+ };
+
+ if ((sibbyte >> 3) & 7) == 0b100 {
+ if modbits == 0b00 {
+ instr.disp = disp as u32;
+
+ OperandSpec::DispU32
+ } else {
+ let reg = RegSpec::from_parts(0b100, addr_width);
+ instr.modrm_mmm = reg;
+
+ if disp == 0 {
+ OperandSpec::Deref
+ } else {
+ instr.disp = disp as i32 as u32;
+ OperandSpec::RegDisp
+ }
+ }
+ } else {
+ instr.modrm_mmm = RegSpec::from_parts(5, addr_width);
+
+ instr.sib_index = RegSpec::from_parts((sibbyte >> 3) & 7, addr_width);
+ let scale = 1u8 << (sibbyte >> 6);
+ instr.scale = scale;
+
+ if disp == 0 {
+ if modbits == 0 {
+ OperandSpec::RegScale
+ } else {
+ OperandSpec::RegIndexBaseScale
+ }
+ } else {
+ instr.disp = disp as i32 as u32;
+ if modbits == 0 {
+ OperandSpec::RegScaleDisp
+ } else {
+ OperandSpec::RegIndexBaseScaleDisp
+ }
+ }
+ }
+ } else {
+ instr.modrm_mmm = RegSpec::from_parts(sibbyte & 7, addr_width);
+
+ let disp = if modbits == 0b00 {
+ 0
+ } else if modbits == 0b01 {
+ *length += 1;
+ read_num(bytes_iter, 1)? as i8 as i32
+ } else {
+ *length += 4;
+ read_num(bytes_iter, 4)? as i32
+ };
+
+ if ((sibbyte >> 3) & 7) == 0b100 {
+ if disp == 0 {
+ OperandSpec::Deref
+ } else {
+ instr.disp = disp as i32 as u32;
+ OperandSpec::RegDisp
+ }
+ } else {
+ instr.sib_index = RegSpec::from_parts((sibbyte >> 3) & 7, addr_width);
+ let scale = 1u8 << (sibbyte >> 6);
+ instr.scale = scale;
+ if disp == 0 {
+ OperandSpec::RegIndexBaseScale
+ } else {
+ instr.disp = disp as i32 as u32;
+ OperandSpec::RegIndexBaseScaleDisp
+ }
+ }
+ };
+ Ok(op_spec)
+}
+
+#[allow(non_snake_case)]
+fn read_M_16bit<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ let modbits = modrm >> 6;
+ let mmm = modrm & 7;
+ if modbits == 0b00 && mmm == 0b110 {
+ return Ok(OperandSpec::DispU16);
+ }
+ match mmm {
+ 0b000 => {
+ instr.modrm_mmm = RegSpec::bx();
+ instr.sib_index = RegSpec::si();
+ },
+ 0b001 => {
+ instr.modrm_mmm = RegSpec::bx();
+ instr.sib_index = RegSpec::di();
+ },
+ 0b010 => {
+ instr.modrm_mmm = RegSpec::bp();
+ instr.sib_index = RegSpec::si();
+ },
+ 0b011 => {
+ instr.modrm_mmm = RegSpec::bp();
+ instr.sib_index = RegSpec::di();
+ },
+ 0b100 => {
+ instr.modrm_mmm = RegSpec::si();
+ },
+ 0b101 => {
+ instr.modrm_mmm = RegSpec::di();
+ },
+ 0b110 => {
+ instr.modrm_mmm = RegSpec::bp();
+ },
+ 0b111 => {
+ instr.modrm_mmm = RegSpec::bx();
+ },
+ _ => { unreachable!("impossible bit pattern"); }
+ }
+ match modbits {
+ 0b00 => {
+ if mmm > 3 {
+ Ok(OperandSpec::Deref)
+ } else {
+ Ok(OperandSpec::RegIndexBase)
+ }
+ },
+ 0b01 => {
+ instr.disp = read_num(bytes_iter, 1)?;
+ *length += 1;
+ if mmm > 3 {
+ Ok(OperandSpec::RegDisp)
+ } else {
+ Ok(OperandSpec::RegIndexBaseDisp)
+ }
+ },
+ 0b10 => {
+ instr.disp = read_num(bytes_iter, 2)?;
+ *length += 2;
+ if mmm > 3 {
+ Ok(OperandSpec::RegDisp)
+ } else {
+ Ok(OperandSpec::RegIndexBaseDisp)
+ }
+ },
+ _ => {
+ unreachable!("read_M_16but but mod bits were not a memory operand");
+ }
+ }
+}
+
+#[allow(non_snake_case)]
+fn read_M<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ if instr.prefixes.address_size() {
+ return read_M_16bit(bytes_iter, instr, modrm, length);
+ }
+ let addr_width = RegisterBank::D;
+ let modbits = modrm >> 6;
+ let mmm = modrm & 7;
+ let op_spec = if mmm == 4 {
+ return read_sib(bytes_iter, instr, modrm, length);
+ } else if mmm == 5 && modbits == 0b00 {
+ *length += 4;
+ instr.disp = read_num(bytes_iter, 4)? as u32;
+ OperandSpec::DispU32
+ } else {
+ instr.modrm_mmm = RegSpec::from_parts(mmm, addr_width);
+
+ if modbits == 0b00 {
+ OperandSpec::Deref
+ } else {
+ let disp = if modbits == 0b01 {
+ *length += 1;
+ read_num(bytes_iter, 1)? as i8 as i32
+ } else {
+ *length += 4;
+ read_num(bytes_iter, 4)? as i32
+ };
+ if disp == 0 {
+ OperandSpec::Deref
+ } else {
+ instr.disp = disp as i32 as u32;
+ OperandSpec::RegDisp
+ }
+ }
+ };
+ Ok(op_spec)
+}
+
+#[inline]
+fn width_to_gp_reg_bank(width: u8) -> RegisterBank {
+ match width {
+ 1 => return RegisterBank::B,
+ 2 => return RegisterBank::W,
+ 4 => return RegisterBank::D,
+ o => { unreachable!("impossible width: {}", o); }
+// _ => unsafe { unreachable_unchecked() }
+ }
+}
+
+fn read_instr<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction) -> Result<(), DecodeError> {
+ let mut length = 0u8;
+ let mut alternate_opcode_map: Option<OpcodeMap> = None;
+// use core::intrinsics::unlikely;
+ let mut prefixes = Prefixes::new(0);
+
+ fn escapes_are_prefixes_actually(prefixes: &mut Prefixes, opc_map: &mut Option<OpcodeMap>) {
+ match opc_map {
+ Some(OpcodeMap::Map66) => {
+ prefixes.set_operand_size();
+ },
+ Some(OpcodeMap::MapF2) => {
+ prefixes.set_repnz();
+ },
+ Some(OpcodeMap::MapF3) => {
+ prefixes.set_rep();
+ },
+ None => {}
+ }
+ *opc_map = None;
+ }
+
+ let record: OpcodeRecord = loop {
+// let operand_code = loop {
+ match bytes_iter.next() {
+ Some(b) => {
+ length += 1;
+ let record = OPCODES[b as usize];
+ if b == 0x0f {
+ let record = match alternate_opcode_map {
+ Some(opcode_map) => {
+ let (rec, opcode_byte) = match opcode_map {
+ OpcodeMap::Map66 => {
+ read_opcode_660f_map(&mut bytes_iter, &mut length)?
+ },
+ OpcodeMap::MapF2 => {
+ read_opcode_f20f_map(&mut bytes_iter, &mut length)?
+ },
+ OpcodeMap::MapF3 => {
+ read_opcode_f30f_map(&mut bytes_iter, &mut length)?
+ },
+ };
+ if rec == OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing) {
+ escapes_are_prefixes_actually(&mut prefixes, &mut Some(opcode_map));
+ OPCODE_0F_MAP[opcode_byte as usize]
+ } else {
+ rec
+ }
+ },
+ None => {
+ read_opcode_0f_map(&mut bytes_iter, &mut length)?
+ }
+ };
+
+ break record;
+ } else if let Interpretation::Instruction(_) = record.0 {
+ escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map);
+ break record;
+ } else {
+ escapes_are_prefixes_actually(&mut prefixes, &mut alternate_opcode_map);
+ match b {
+ 0x26 => {
+ prefixes.set_es();
+ },
+ 0x2e => {
+ prefixes.set_cs();
+ },
+ 0x36 => {
+ prefixes.set_ss();
+ },
+ 0x3e => {
+ prefixes.set_ds();
+ },
+ 0x64 => {
+ prefixes.set_fs();
+ },
+ 0x65 => {
+ prefixes.set_gs();
+ },
+ 0x66 => {
+ alternate_opcode_map = Some(OpcodeMap::Map66);
+ },
+ 0x67 => {
+ prefixes.set_address_size();
+ },
+ 0x9b => {
+ // TODO: WAIT prefix
+ return Err(DecodeError::IncompleteDecoder);
+ },
+ 0xf0 => {
+ prefixes.set_lock();
+ },
+ 0xf2 => {
+ alternate_opcode_map = Some(OpcodeMap::MapF2);
+ },
+ 0xf3 => {
+ alternate_opcode_map = Some(OpcodeMap::MapF3);
+ },
+// _ => { unsafe { unreachable_unchecked(); } }
+ o => {
+ unreachable!("invalid prefix {:#02x}", o);
+ }
+ }
+ }
+ },
+ None => {
+ return Err(DecodeError::ExhaustedInput);
+ }
+ }
+ };
+ if let Interpretation::Instruction(opcode) = record.0 {
+ instruction.opcode = opcode;
+ } else {
+// unsafe { unreachable_unchecked(); }
+ unreachable!("bad record, needs to be an Instruction but was {:?}", record);
+ }
+ instruction.prefixes = prefixes;
+ read_operands(decoder, bytes_iter, instruction, record.1, &mut length)?;
+ instruction.length = length;
+
+ if decoder != &InstDecoder::default() {
+ // we might have to fix up or reject this instruction under whatever cpu features we need to
+ // pretend to have.
+ decoder.revise_instruction(instruction)?;
+ }
+ Ok(())
+}
+fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, length: &mut u8) -> Result<(), DecodeError> {
+ if (operand_code as u8) & 0x40 == 0x40 {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ }
+ if (operand_code as u8) >= 0x40 && (operand_code as u8) < 0x60 {
+ let reg = (operand_code as u8) & 0x07;
+ let category = ((operand_code as u8) & 0x18) >> 3;
+ if category == 0 {
+ // these are Zv_R
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let bank = if opwidth == 4 {
+ RegisterBank::D
+ } else {
+ RegisterBank::W
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts(reg, bank);
+ instruction.operand_count = 1;
+ // Zv_AX are missing!
+ } else if category == 2 {
+ // these are Zb_Ib_R
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts(reg, 1);
+ instruction.imm =
+ read_imm_unsigned(&mut bytes_iter, 1, length)?;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ instruction.operand_count = 2;
+ } else {
+ // category == 3, Zv_Iv_R
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let bank = if opwidth == 4 {
+ RegisterBank::D
+ } else {
+ RegisterBank::W
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts(reg, bank);
+ instruction.imm =
+ read_num(&mut bytes_iter, opwidth)? as u32;
+ *length += opwidth;
+ instruction.operands[1] = match opwidth {
+ 1 => OperandSpec::ImmI8,
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ o => unsafe { unreachable!("impossibe op width {}", o) }
+// _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 2;
+ }
+ return Ok(());
+ }
+
+ let mut modrm = 0;
+ let mut opwidth = 0;
+ let mut mem_oper = OperandSpec::Nothing;
+ let mut bank = RegisterBank::D;
+ let code_int = operand_code as u8;
+ if ((code_int) & 0x80) == 0x80 {
+ // cool! we can precompute opwidth and know we need to read_E.
+ if (code_int & 1) == 1 {
+ // further, this is an vd E
+ opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ if opwidth == 4 {
+ bank = RegisterBank::D;
+ } else if opwidth == 2 {
+ bank = RegisterBank::W;
+ }
+ } else {
+ opwidth = 1;
+ bank = RegisterBank::B;
+ };
+ modrm = read_modrm(&mut bytes_iter, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, bank);
+
+ mem_oper = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+
+ let numeric_code = (operand_code as u8) & 0xbf;
+ if numeric_code >= 0x80 && numeric_code < 0x84 {
+ let (mmm, rrr) = if numeric_code & 0x02 == 2 {
+ (1, 0)
+ } else {
+ (0, 1)
+ };
+ instruction.operands[mmm] = mem_oper;
+ instruction.operands[rrr] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ } else if operand_code == OperandCode::Ibs {
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[0] = OperandSpec::ImmI8;
+ instruction.operand_count = 1;
+ } else {
+ match operand_code {
+ /*
+ Gv_Ev_Iv,
+ Gb_Eb_Ib,
+ Yb_DX,
+ Yv_DX,
+ DX_Xb,
+ DX_Xv,
+ OR,
+ AH,
+ AL_Ib,
+ AL_Ob,
+ AL_Xb,
+ AX_AL,
+ AX_Ivd,
+ AX_Ov,
+ AX_Xv,
+ DX_AX,
+ Eb_1,
+ Eb_Ib,
+ Eb_CL,
+ Ev,
+ Ev_1,
+ Ev_CL,
+ Ev_Ibs,
+ Ev_Iv,
+ Ev_Ivs,
+ Ew_Sw,
+ Fw,
+ Gv_M,
+ I_3,
+ Ib,
+ Ibs,
+ Ivs,
+ Iw,
+ Iw_Ib,
+ Ob_AL,
+ Ov_AX,
+ Sw_Ew,
+ Yb_AL,
+ Yb_Xb,
+ Yv_AX,
+ Yv_Xv,
+ Zb_Ib,
+ Zv,
+ Zv_AX,
+ */
+ OperandCode::Eb_R0 => {
+ if (modrm & 0b00111000) != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc6".to_owned());
+ }
+
+ instruction.operands[0] = mem_oper;
+ instruction.operand_count = 1;
+ },
+ op @ OperandCode::AL_Ob |
+ op @ OperandCode::AX_Ov => {
+ let opwidth = match op {
+ OperandCode::AL_Ob => 1,
+ OperandCode::AX_Ov => {
+ imm_width_from_prefixes(SizeCode::vd, instruction.prefixes)
+ }
+ _ => {
+ unsafe { unreachable_unchecked() }
+ }
+ };
+ // stupid RCT thing:
+ let addr_width = if instruction.prefixes.address_size() { 2 } else { 4 };
+ let imm = read_num(&mut bytes_iter, addr_width)?;
+ *length += addr_width;
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts(0, opwidth);
+ instruction.disp = imm;
+ if instruction.prefixes.address_size() {
+ instruction.operands[1] = OperandSpec::DispU16;
+ } else {
+ instruction.operands[1] = OperandSpec::DispU32;
+ };
+ instruction.operand_count = 2;
+ }
+ op @ OperandCode::Ob_AL |
+ op @ OperandCode::Ov_AX => {
+ let opwidth = match op {
+ OperandCode::Ob_AL => 1,
+ OperandCode::Ov_AX => {
+ imm_width_from_prefixes(SizeCode::vd, instruction.prefixes)
+ }
+ _ => {
+ unsafe { unreachable_unchecked() }
+ }
+ };
+ let _addr_width = if instruction.prefixes.address_size() { 4 } else { 8 };
+ // stupid RCT thing:
+ let addr_width = if instruction.prefixes.address_size() { 2 } else { 4 };
+ let imm = read_num(&mut bytes_iter, addr_width)?;
+ *length += addr_width;
+ instruction.disp = imm;
+ instruction.operands[0] = if instruction.prefixes.address_size() {
+ OperandSpec::DispU32
+ } else {
+ OperandSpec::DispU16
+ };
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts(0, opwidth);
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ }
+ _op @ OperandCode::ModRM_0x80_Eb_Ib |
+ _op @ OperandCode::ModRM_0x81_Ev_Ivs => {
+ instruction.operands[0] = mem_oper;
+ let numwidth = if opwidth == 8 { 4 } else { opwidth };
+ instruction.imm = read_imm_signed(&mut bytes_iter, numwidth, length)? as u32;
+ instruction.opcode = base_opcode_map((modrm >> 3) & 7);
+ instruction.operands[1] = match opwidth {
+ 1 => OperandSpec::ImmI8,
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 2;
+ },
+ OperandCode::ModRM_0xc4 => {
+ let modrm = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?;
+ if modrm & 0b11000000 == 0b11000000 {
+ // interpret the c4 as a vex prefix
+ if instruction.prefixes.lock() || instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() {
+ // prefixes and then vex is invalid! reject it.
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidPrefixes);
+ } else {
+ vex::three_byte_vex(&mut bytes_iter, modrm, instruction, *length)?;
+ *length = instruction.length;
+
+ if decoder != &InstDecoder::default() {
+ decoder.revise_instruction(instruction)?;
+ }
+ return Ok(());
+ }
+ } else {
+ // LES
+ instruction.modrm_rrr = RegSpec::gp_from_parts((modrm >> 3) & 7, if instruction.prefixes.operand_size() { 2 } else { 4 });
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_M(&mut bytes_iter, instruction, modrm, length)?;
+ }
+ },
+ OperandCode::ModRM_0xc5 => {
+ let modrm = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?;
+ if (modrm & 0b1100_0000) == 0b1100_0000 {
+ // interpret the c5 as a vex prefix
+ if instruction.prefixes.lock() || instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() {
+ // prefixes and then vex is invalid! reject it.
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidPrefixes);
+ } else {
+ vex::two_byte_vex(&mut bytes_iter, modrm, instruction, *length)?;
+ *length = instruction.length;
+
+ if decoder != &InstDecoder::default() {
+ decoder.revise_instruction(instruction)?;
+ }
+ return Ok(());
+ }
+ } else {
+ // LDS
+ instruction.modrm_rrr = RegSpec::gp_from_parts((modrm >> 3) & 7, if instruction.prefixes.operand_size() { 2 } else { 4 });
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_M(&mut bytes_iter, instruction, modrm, length)?;
+ }
+ },
+ _op @ OperandCode::ModRM_0xc6_Eb_Ib |
+ _op @ OperandCode::ModRM_0xc7_Ev_Iv => {
+ if (modrm & 0b00111000) != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string());
+ }
+
+ instruction.operands[0] = mem_oper;
+ instruction.opcode = Opcode::MOV;
+ instruction.imm = read_imm_signed(&mut bytes_iter, opwidth, length)? as u32;
+ instruction.operands[1] = match opwidth {
+ 1 => OperandSpec::ImmI8,
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 2;
+ },
+ op @ OperandCode::ModRM_0xc0_Eb_Ib |
+ op @ OperandCode::ModRM_0xc1_Ev_Ib |
+ op @ OperandCode::ModRM_0xd0_Eb_1 |
+ op @ OperandCode::ModRM_0xd1_Ev_1 |
+ op @ OperandCode::ModRM_0xd3_Ev_CL => {
+ instruction.operands[0] = mem_oper;
+ instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone();
+ if let OperandCode::ModRM_0xd3_Ev_CL = op {
+ instruction.modrm_rrr = RegSpec::cl();
+ instruction.operands[1] = OperandSpec::RegRRR;
+ } else {
+ let num = match op {
+ OperandCode::ModRM_0xc0_Eb_Ib |
+ OperandCode::ModRM_0xc1_Ev_Ib => {
+ *length += 1;
+ read_num(&mut bytes_iter, 1)?
+ }
+ _ => {
+ // these are the _1 variants, everything else is unreachable
+ 1
+ }
+ };
+ instruction.imm = num;
+ instruction.operands[1] = OperandSpec::ImmI8;
+ }
+ instruction.operand_count = 2;
+ },
+ _op @ OperandCode::ModRM_0xf6 |
+ _op @ OperandCode::ModRM_0xf7 => {
+ instruction.operands[0] = mem_oper;
+ instruction.operand_count = 1;
+ match (modrm >> 3) & 7 {
+ 0 | 1 => {
+ instruction.opcode = Opcode::TEST;
+ instruction.imm = read_imm_signed(&mut bytes_iter, opwidth, length)? as u32;
+ instruction.operands[1] = match opwidth {
+ 1 => OperandSpec::ImmI8,
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 2;
+ },
+ 2 => {
+ instruction.opcode = Opcode::NOT;
+ },
+ 3 => {
+ instruction.opcode = Opcode::NEG;
+ },
+ 4 => {
+ instruction.opcode = Opcode::MUL;
+ },
+ 5 => {
+ instruction.opcode = Opcode::IMUL;
+ },
+ 6 => {
+ instruction.opcode = Opcode::DIV;
+ },
+ 7 => {
+ instruction.opcode = Opcode::IDIV;
+ },
+ _ => {
+ unsafe { unreachable_unchecked(); }
+ }
+ }
+ },
+ OperandCode::ModRM_0xfe_Eb => {
+ instruction.operands[0] = mem_oper;
+ instruction.opcode = [
+ Opcode::INC,
+ Opcode::DEC,
+ Opcode::Invalid,
+ Opcode::Invalid,
+ Opcode::Invalid,
+ Opcode::Invalid,
+ Opcode::Invalid,
+ Opcode::Invalid
+ ][((modrm >> 3) & 7) as usize];
+ instruction.operand_count = 1;
+ }
+ OperandCode::ModRM_0xff_Ev => {
+ instruction.operands[0] = mem_oper;
+ let opcode = [
+ Opcode::INC,
+ Opcode::DEC,
+ Opcode::CALL,
+ Opcode::CALLF,
+ Opcode::JMP,
+ Opcode::JMPF,
+ Opcode::PUSH,
+ Opcode::Invalid
+ ][((modrm >> 3) & 7) as usize];
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ if opcode == Opcode::CALL || opcode == Opcode::JMP {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ } else if opcode == Opcode::CALLF || opcode == Opcode::JMPF {
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
+ instruction.opcode = opcode;
+ instruction.operand_count = 1;
+ }
+ OperandCode::Gv_Eb => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 1, length)?;
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts((modrm >> 3) & 7, opwidth);
+ instruction.operand_count = 2;
+ },
+ OperandCode::Gv_Ew => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts((modrm >> 3) & 7, opwidth);
+ instruction.operand_count = 2;
+ },
+ OperandCode::Ew_Gw => {
+ let opwidth = 2;
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts((modrm >> 3) & 7, opwidth);
+ instruction.operand_count = 2;
+ },
+ OperandCode::Ev => {
+ instruction.operands[0] = mem_oper;
+ instruction.operand_count = 1;
+ },
+ OperandCode::Gv_M => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts((modrm >> 3) & 7, opwidth);
+ instruction.operand_count = 2;
+ },
+ OperandCode::E_G_xmm => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m);
+ instruction.operands[0] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ },
+ OperandCode::G_E_mm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ instruction.modrm_mmm.num &= 0b111;
+ }
+ instruction.operand_count = 2;
+ },
+ OperandCode::G_U_mm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::D;
+ if mem_oper != OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ instruction.modrm_mmm.num &= 0b111;
+ instruction.operand_count = 2;
+ },
+ OperandCode::G_U_xmm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper != OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ instruction.operand_count = 2;
+ },
+ 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(DecodeError::InvalidOperand);
+ } else {
+ // fix the register to XMM
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ }
+ }
+ },
+ OperandCode::G_E_xmm_Ib => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)? as u8 as u32;
+ *length += 1;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ },
+ OperandCode::G_E_mm_Ib => {
+ 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_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.modrm_rrr = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 };
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)? as u8 as u32;
+ *length += 1;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ },
+ OperandCode::G_mm_Ew_Ib => {
+ 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, 4, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::MM);
+ instruction.operands[0] = OperandSpec::RegRRR;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)? as u8 as u32;
+ *length += 1;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ }
+ OperandCode::AL_Ibs => {
+ instruction.modrm_rrr =
+ RegSpec::al();
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmI8;
+ instruction.operand_count = 2;
+ }
+ OperandCode::AX_Ivd => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr =
+ RegSpec::gp_from_parts(0, opwidth);
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, opwidth, length)? as u32;
+ instruction.operands[1] = match opwidth {
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 2;
+ }
+ OperandCode::Ivs => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.imm =
+ read_imm_unsigned(&mut bytes_iter, opwidth, length)?;
+ instruction.operands[0] = match opwidth {
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 1;
+ },
+ OperandCode::ModRM_0x83_Ev_Ibs => {
+ instruction.operands[0] = mem_oper;
+ instruction.opcode = base_opcode_map((modrm >> 3) & 7);
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmI8;
+ instruction.operand_count = 2;
+ },
+ OperandCode::Jvds => {
+ let offset = read_num(&mut bytes_iter, 4)?;
+ *length += 4;
+ instruction.imm = offset;
+ instruction.operand_count = 1;
+ instruction.operands[0] = OperandSpec::ImmI32;
+ }
+ OperandCode::Gb_Eb_Ib => {
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ }
+ OperandCode::Gv_Ev_Iv => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let numwidth = if opwidth == 8 { 4 } else { opwidth };
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, numwidth, length)? as u32;
+ instruction.operands[2] = match opwidth {
+ 2 => OperandSpec::ImmI16,
+ 4 => OperandSpec::ImmI32,
+ o => { unreachable!("impossible opwidth: {}", o); }
+// _ => unsafe { unreachable_unchecked() }
+ };
+ instruction.operand_count = 3;
+ }
+ OperandCode::Ev_Gv_Ib => {
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.imm =
+ read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ }
+ OperandCode::Ev_Gv_CL => {
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operands[2] = OperandSpec::CL;
+ instruction.operand_count = 3;
+ }
+ OperandCode::Nothing => {
+ instruction.operand_count = 0;
+ }
+ _ => {
+ unlikely_operands(decoder, bytes_iter, instruction, operand_code, mem_oper, length)?;
+ }
+ };
+ }
+
+ Ok(())
+}
+fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, length: &mut u8) -> Result<(), DecodeError> {
+ match operand_code {
+ OperandCode::Unsupported => {
+ return Err(DecodeError::IncompleteDecoder);
+ }
+ OperandCode::MOVQ_f30f => {
+ instruction.operand_count = 2;
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ }
+ OperandCode::ModRM_0x0f71 => {
+ instruction.operand_count = 2;
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 2 => {
+ instruction.opcode = Opcode::PSRLW;
+ }
+ 4 => {
+ instruction.opcode = Opcode::PSRAW;
+ }
+ 6 => {
+ instruction.opcode = Opcode::PSLLW;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::MM, num: modrm & 7 };
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ },
+ OperandCode::ModRM_0x0f72 => {
+ instruction.operand_count = 2;
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 2 => {
+ instruction.opcode = Opcode::PSRLD;
+ }
+ 4 => {
+ instruction.opcode = Opcode::PSRAD;
+ }
+ 6 => {
+ instruction.opcode = Opcode::PSLLD;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::MM, num: modrm & 7 };
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ },
+ OperandCode::ModRM_0x0f73 => {
+ instruction.operand_count = 2;
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 2 => {
+ instruction.opcode = Opcode::PSRLQ;
+ }
+ 6 => {
+ instruction.opcode = Opcode::PSLLQ;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::MM, num: modrm & 7 };
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ },
+ OperandCode::ModRM_0x660f12 => {
+ // If this is reg-reg, interpret the instruction as 66-prefixed (no-op here)
+ // `movhlps`. If this is reg-mem, it's a `movlpd`.
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 == 0xc0 {
+ instruction.opcode = Opcode::MOVHLPS;
+ } else {
+ instruction.opcode = Opcode::MOVLPD;
+ }
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCode::ModRM_0x660f16 => {
+ // If this is reg-reg, interpret the instruction as 66-prefixed (no-op here)
+ // `movlhps`. If this is reg-mem, it's a `movhpd`.
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 == 0xc0 {
+ instruction.opcode = Opcode::MOVLHPS;
+ } else {
+ instruction.opcode = Opcode::MOVHPD;
+ }
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCode::ModRM_0x660f38 => {
+ let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?;
+ match op {
+ 0xdb => { instruction.opcode = Opcode::AESIMC; }
+ 0xdc => { instruction.opcode = Opcode::AESENC; }
+ 0xdd => { instruction.opcode = Opcode::AESENCLAST; }
+ 0xde => { instruction.opcode = Opcode::AESDEC; }
+ 0xdf => { instruction.opcode = Opcode::AESDECLAST; }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ // all these SO FAR are G_E_xmm
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+
+
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.operand_count = 2;
+ }
+ OperandCode::ModRM_0x660f3a => {
+ let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?;
+ match op {
+ 0xdf => {
+ instruction.opcode = Opcode::AESKEYGENASSIST;
+ // read operands right here right now
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+
+
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = read_E_xmm(&mut bytes_iter, instruction, modrm, length)?;
+ instruction.imm =
+ read_imm_unsigned(&mut bytes_iter, 1, length)?;
+ instruction.operands[2] = OperandSpec::ImmU8;
+ instruction.operand_count = 3;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ }
+ OperandCode::ModRM_0x660f71 => {
+ instruction.operand_count = 2;
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 2 => {
+ instruction.opcode = Opcode::PSRLW;
+ }
+ 4 => {
+ instruction.opcode = Opcode::PSRAW;
+ }
+ 6 => {
+ instruction.opcode = Opcode::PSLLW;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::X, num: modrm & 7 };
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ },
+ OperandCode::ModRM_0x660f72 => {
+ instruction.operand_count = 2;
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 2 => {
+ instruction.opcode = Opcode::PSRLD;
+ }
+ 4 => {
+ instruction.opcode = Opcode::PSRAD;
+ }
+ 6 => {
+ instruction.opcode = Opcode::PSLLD;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::X, num: modrm & 7 };
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ },
+ OperandCode::ModRM_0x660f73 => {
+ instruction.operand_count = 2;
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm & 0xc0 != 0xc0 {
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 2 => {
+ instruction.opcode = Opcode::PSRLQ;
+ }
+ 3 => {
+ instruction.opcode = Opcode::PSRLDQ;
+ }
+ 6 => {
+ instruction.opcode = Opcode::PSLLQ;
+ }
+ 7 => {
+ instruction.opcode = Opcode::PSLLDQ;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::X, num: modrm & 7 };
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ },
+ OperandCode::ModRM_0x660fc7 => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 6 => {
+ instruction.opcode = Opcode::VMCLEAR;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.operand_count = 1;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ },
+ OperandCode::ModRM_0xf30fc7 => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ let r = (modrm >> 3) & 7;
+ match r {
+ 6 => {
+ instruction.opcode = Opcode::VMXON;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.operand_count = 1;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ },
+ OperandCode::G_mm_Edq => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ }
+ OperandCode::G_mm_E => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ instruction.modrm_mmm.num &= 0b111;
+ }
+ }
+ OperandCode::Edq_G_mm => {
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ }
+ OperandCode::Edq_G_xmm => {
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ }
+ OperandCode::E_G_mm => {
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ instruction.modrm_mmm.num &= 0b111;
+ }
+ }
+ /*
+ OperandCode::G_xmm_Ed => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ },
+ */
+ OperandCode::G_xmm_Edq => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ },
+ OperandCode::G_xmm_Ed_Ib => {
+ instruction.operands[1] = mem_oper;
+ instruction.operands[2] = OperandSpec::ImmU8;
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)?;
+ *length += 1;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ },
+ OperandCode::G_xmm_Ed => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::D;
+ }
+ },
+ OperandCode::G_mm_E_xmm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ }
+ },
+ op @ OperandCode::G_xmm_U_mm |
+ op @ OperandCode::G_xmm_E_mm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ instruction.modrm_mmm.num &= 0b111;
+ } else {
+ if op == OperandCode::G_xmm_U_mm {
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
+ },
+ OperandCode::U_mm_G_xmm => {
+ instruction.operands[1] = mem_oper;
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ if mem_oper == OperandSpec::RegMMM {
+ instruction.modrm_rrr.bank = RegisterBank::MM;
+ instruction.modrm_rrr.num &= 0b111;
+ } else {
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
+ // sure hope these aren't backwards huh
+ OperandCode::AL_Xb => {
+ instruction.operands[0] = OperandSpec::AL;
+ instruction.operands[1] = OperandSpec::Deref_esi;
+ }
+ // TODO: two memory operands! this is wrong!!!
+ OperandCode::Yb_Xb => {
+ instruction.operands[0] = OperandSpec::Deref_edi;
+ instruction.operands[1] = OperandSpec::Deref_esi;
+ }
+ OperandCode::Yb_AL => {
+ instruction.operands[0] = OperandSpec::Deref_edi;
+ instruction.operands[1] = OperandSpec::AL;
+ }
+ OperandCode::AX_Xv => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr = match opwidth {
+ 2 => RegSpec::ax(),
+ 4 => RegSpec::eax(),
+ _ => { unreachable!(); }
+ };
+ instruction.modrm_mmm = RegSpec::esi();
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::Deref;
+ }
+ OperandCode::Yv_AX => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr = match opwidth {
+ 2 => RegSpec::ax(),
+ 4 => RegSpec::eax(),
+ _ => { unreachable!(); }
+ };
+ instruction.modrm_mmm = RegSpec::edi();
+ instruction.operands[0] = OperandSpec::Deref;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ }
+ OperandCode::Yv_Xv => {
+ // TODO: repsect prefixes
+ instruction.operands[0] = OperandSpec::Deref_edi;
+ instruction.operands[1] = OperandSpec::Deref_esi;
+ }
+ OperandCode::ModRM_0x0f12 => {
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ instruction.operands[1] = mem_oper;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ instruction.opcode = Opcode::MOVHLPS;
+ } else {
+ instruction.opcode = Opcode::MOVLPS;
+ }
+ }
+ OperandCode::ModRM_0x0f16 => {
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ instruction.operands[1] = mem_oper;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ instruction.opcode = Opcode::MOVLHPS;
+ } else {
+ instruction.opcode = Opcode::MOVHPS;
+ }
+ }
+ OperandCode::ModRM_0x0f18 => {
+ if mem_oper == OperandSpec::RegMMM {
+ return Err(DecodeError::InvalidOperand);
+ }
+ let rrr = instruction.modrm_rrr.num & 0b111;
+ instruction.operands[0] = mem_oper;
+ instruction.opcode = match rrr {
+ 0 => Opcode::PREFETCHNTA,
+ 1 => Opcode::PREFETCH0,
+ 2 => Opcode::PREFETCH1,
+ 3 => Opcode::PREFETCH2,
+ _ => Opcode::NOP,
+ };
+ }
+ OperandCode::Gd_U_xmm => {
+ instruction.operands[1] = mem_oper;
+ if instruction.operands[1] != OperandSpec::RegMMM {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_rrr.bank = RegisterBank::D;
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ }
+ OperandCode::Gv_E_xmm => {
+ instruction.operands[1] = mem_oper;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::X;
+ }
+ }
+ OperandCode::M_G_xmm => {
+ instruction.operands[1] = instruction.operands[0];
+ instruction.operands[0] = mem_oper;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ instruction.modrm_rrr.bank = RegisterBank::X;
+ }
+ OperandCode::Ew_Sw => {
+ let opwidth = 2;
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ // check r
+ if ((modrm >> 3) & 7) > 5 {
+ // return Err(()); //Err("Invalid r".to_owned());
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ instruction.modrm_rrr =
+ RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 };
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+
+ let mod_bits = modrm >> 6;
+ if mod_bits == 0b11 {
+ instruction.modrm_mmm =
+ RegSpec { bank: RegisterBank::W, num: modrm & 7};
+ instruction.operands[0] = OperandSpec::RegMMM;
+ } else {
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+ },
+ OperandCode::Sw_Ew => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ // check r
+ if ((modrm >> 3) & 7) > 5 {
+ // return Err(()); // Err("Invalid r".to_owned());
+ return Err(DecodeError::InvalidOperand);
+ }
+
+ instruction.modrm_rrr =
+ RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 };
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+
+ let mod_bits = modrm >> 6;
+ if mod_bits == 0b11 {
+ instruction.modrm_mmm =
+ RegSpec { bank: RegisterBank::W, num: modrm & 7};
+ instruction.operands[1] = OperandSpec::RegMMM;
+ } else {
+ instruction.operands[1] = read_M(&mut bytes_iter, instruction, modrm, length)?;
+ }
+ },
+ OperandCode::CVT_AA => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.opcode = match opwidth {
+ 2 => { Opcode::CBW },
+ 4 => { Opcode::CWDE },
+ _ => { unreachable!("invalid operation width"); },
+ }
+ }
+ OperandCode::CVT_DA => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.opcode = match opwidth {
+ 2 => { Opcode::CBD },
+ 4 => { Opcode::CDQ },
+ _ => { unreachable!("invalid operation width"); },
+ }
+ }
+ OperandCode::Ib => {
+ instruction.imm =
+ read_imm_unsigned(&mut bytes_iter, 1, length)?;
+ instruction.operands[0] = OperandSpec::ImmU8;
+ instruction.operand_count = 1;
+ }
+ OperandCode::Iw => {
+ instruction.imm =
+ read_imm_unsigned(&mut bytes_iter, 2, length)?;
+ instruction.operands[0] = OperandSpec::ImmU16;
+ instruction.operand_count = 1;
+ }
+ OperandCode::ModRM_0x0f00 => {
+ instruction.operand_count = 1;
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ let r = (modrm >> 3) & 7;
+ if r == 0 {
+ instruction.opcode = Opcode::SLDT;
+ } else if r == 1 {
+ instruction.opcode = Opcode::STR;
+ } else if r == 2 {
+ instruction.opcode = Opcode::LLDT;
+ } else if r == 3 {
+ instruction.opcode = Opcode::LTR;
+ } else if r == 4 {
+ instruction.opcode = Opcode::VERR;
+ } else if r == 5 {
+ instruction.opcode = Opcode::VERW;
+ } else if r == 6 {
+ instruction.opcode = Opcode::JMPE;
+ instruction.operand_count = 0;
+ return Ok(());
+ } else if r == 7 {
+ instruction.opcode = Opcode::Invalid;
+ instruction.operand_count = 0;
+ return Err(DecodeError::InvalidOperand);
+ } else {
+ unreachable!("r <= 8");
+ }
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
+ }
+ OperandCode::ModRM_0x0f01 => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ let r = (modrm >> 3) & 7;
+ if r == 0 {
+ let mod_bits = modrm >> 6;
+ let m = modrm & 7;
+ if mod_bits == 0b11 {
+ instruction.operand_count = 0;
+ match m {
+ 0b000 => {
+ instruction.opcode = Opcode::ENCLV;
+ },
+ 0b001 => {
+ instruction.opcode = Opcode::VMCALL;
+ },
+ 0b010 => {
+ instruction.opcode = Opcode::VMLAUNCH;
+ },
+ 0b011 => {
+ instruction.opcode = Opcode::VMRESUME;
+ },
+ 0b100 => {
+ instruction.opcode = Opcode::VMXOFF;
+ },
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ instruction.opcode = Opcode::SGDT;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+ } else if r == 1 {
+ let mod_bits = modrm >> 6;
+ let m = modrm & 7;
+ if mod_bits == 0b11 {
+ instruction.operand_count = 0;
+ match m {
+ 0b000 => {
+ instruction.opcode = Opcode::MONITOR;
+ }
+ 0b001 => {
+ instruction.opcode = Opcode::MWAIT;
+ },
+ 0b010 => {
+ instruction.opcode = Opcode::CLAC;
+ }
+ 0b011 => {
+ instruction.opcode = Opcode::STAC;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::ENCLS;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ instruction.opcode = Opcode::SIDT;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+ } else if r == 2 {
+ let mod_bits = modrm >> 6;
+ let m = modrm & 7;
+ if mod_bits == 0b11 {
+ instruction.operand_count = 0;
+ match m {
+ 0b000 => {
+ instruction.opcode = Opcode::XGETBV;
+ }
+ 0b001 => {
+ instruction.opcode = Opcode::XSETBV;
+ }
+ 0b100 => {
+ instruction.opcode = Opcode::VMFUNC;
+ }
+ 0b101 => {
+ instruction.opcode = Opcode::XEND;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::XTEST;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::ENCLU;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ instruction.opcode = Opcode::LGDT;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+ } else if r == 3 {
+ let mod_bits = modrm >> 6;
+ if mod_bits == 0b11 {
+ instruction.opcode = Opcode::Invalid;
+ instruction.operand_count = 0;
+ return Err(DecodeError::InvalidOperand);
+ } else {
+ instruction.opcode = Opcode::LIDT;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+ } else if r == 4 {
+ // TODO: this permits storing only to word-size registers
+ // spec suggets this might do something different for f.ex edi?
+ instruction.opcode = Opcode::SMSW;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
+ } else if r == 5 {
+ let m = modrm & 7;
+ match m {
+ 0b110 => {
+ instruction.opcode = Opcode::RDPKRU;
+ instruction.operand_count = 1;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::WRPKRU;
+ instruction.operand_count = 1;
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ instruction.operand_count = 0;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else if r == 6 {
+ instruction.opcode = Opcode::LMSW;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?;
+ } else if r == 7 {
+ let mod_bits = modrm >> 6;
+ let m = modrm & 7;
+ if mod_bits == 0b11 {
+ if m == 0 {
+ instruction.opcode = Opcode::SWAPGS;
+ instruction.operand_count = 0;
+ } else if m == 1 {
+ instruction.opcode = Opcode::RDTSCP;
+ instruction.operand_count = 0;
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ } else {
+ instruction.opcode = Opcode::INVLPG;
+ instruction.operand_count = 1;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ }
+ } else {
+ unreachable!("r <= 8");
+ }
+ }
+ OperandCode::ModRM_0x0fae => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ let r = (modrm >> 3) & 7;
+ let mod_bits = modrm >> 6;
+
+ // all the 0b11 instructions are err or no-operands
+ if mod_bits == 0b11 {
+ instruction.operand_count = 0;
+ let m = modrm & 7;
+ match r {
+ // invalid rrr for 0x0fae, mod: 11
+ 0 | 1 | 2 | 3 | 4 => {
+ return Err(DecodeError::InvalidOpcode);
+ },
+ 5 => {
+ instruction.opcode = Opcode::LFENCE;
+ // Intel's manual accepts m != 0, AMD supports m != 0 though the manual
+ // doesn't say (tested on threadripper)
+ if !decoder.amd_quirks() && !decoder.intel_quirks() {
+ if m != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
+ },
+ 6 => {
+ instruction.opcode = Opcode::MFENCE;
+ // Intel's manual accepts m != 0, AMD supports m != 0 though the manual
+ // doesn't say (tested on threadripper)
+ if !decoder.amd_quirks() && !decoder.intel_quirks() {
+ if m != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
+ },
+ 7 => {
+ instruction.opcode = Opcode::SFENCE;
+ // Intel's manual accepts m != 0, AMD supports m != 0 though the manual
+ // doesn't say (tested on threadripper)
+ if !decoder.amd_quirks() && !decoder.intel_quirks() {
+ if m != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ }
+ },
+ _ => { unsafe { unreachable_unchecked() } /* r <=7 */ }
+ }
+ } else {
+ instruction.operand_count = 1;
+ instruction.opcode = [
+ Opcode::FXSAVE,
+ Opcode::FXRSTOR,
+ Opcode::LDMXCSR,
+ Opcode::STMXCSR,
+ Opcode::XSAVE,
+ Opcode::XRSTOR,
+ Opcode::XSAVEOPT,
+ Opcode::CLFLUSH,
+ ][r as usize];
+ instruction.operands[0] = read_M(&mut bytes_iter, instruction, modrm, length)?;
+ }
+ }
+ OperandCode::ModRM_0x0fba => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ let r = (modrm >> 3) & 7;
+ match r {
+ 0 | 1 | 2 | 3 => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ },
+ 4 => {
+ instruction.opcode = Opcode::BT;
+ }
+ 5 => {
+ instruction.opcode = Opcode::BTS;
+ }
+ 6 => {
+ instruction.opcode = Opcode::BTR;
+ }
+ 7 => {
+ instruction.opcode = Opcode::BTC;
+ }
+ _ => {
+ unreachable!("r < 8");
+ }
+ }
+
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+
+ instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as i8 as i32 as u32;
+ instruction.operands[1] = OperandSpec::ImmI8;
+ instruction.operand_count = 2;
+ }
+ op @ OperandCode::Rq_Cq_0 |
+ op @ OperandCode::Rq_Dq_0 |
+ op @ OperandCode::Cq_Rq_0 |
+ op @ OperandCode::Dq_Rq_0 => {
+ let bank = match op {
+ OperandCode::Rq_Cq_0 |
+ OperandCode::Cq_Rq_0 => RegisterBank::CR,
+ OperandCode::Rq_Dq_0 |
+ OperandCode::Dq_Rq_0 => RegisterBank::DR,
+ _ => unsafe { unreachable_unchecked() }
+ };
+ let (rrr, mmm) = match op {
+ OperandCode::Rq_Cq_0 |
+ OperandCode::Rq_Dq_0 => (1, 0),
+ OperandCode::Cq_Rq_0 |
+ OperandCode::Dq_Rq_0 => (0, 1),
+ _ => unsafe { unreachable_unchecked() }
+ };
+
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ let m = modrm & 7;
+ let r = (modrm >> 3) & 7;
+ instruction.modrm_rrr =
+ RegSpec { bank: bank, num: r };
+ instruction.modrm_mmm =
+ RegSpec { bank: RegisterBank::D, num: m };
+ instruction.operands[mmm] = OperandSpec::RegMMM;
+ instruction.operands[rrr] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ }
+ OperandCode::FS => {
+ instruction.modrm_rrr = RegSpec::fs();
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operand_count = 1;
+ }
+ OperandCode::GS => {
+ instruction.modrm_rrr = RegSpec::gs();
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operand_count = 1;
+ }
+ OperandCode::I_3 => {
+ instruction.imm = 3;
+ instruction.operands[0] = OperandSpec::ImmU8;
+ instruction.operand_count = 1;
+ }
+ OperandCode::AL_Ib => {
+ instruction.modrm_rrr =
+ RegSpec::al();
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)?;
+ *length += 1;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ instruction.operand_count = 2;
+ }
+ OperandCode::AX_Ib => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr = if opwidth == 4 {
+ RegSpec::eax()
+ } else {
+ RegSpec::ax()
+ };
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)?;
+ *length += 1;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::ImmU8;
+ instruction.operand_count = 2;
+ }
+ OperandCode::Ib_AL => {
+ instruction.modrm_rrr =
+ RegSpec::al();
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)?;
+ *length += 1;
+ instruction.operands[0] = OperandSpec::ImmU8;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ }
+ OperandCode::Ib_AX => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr = if opwidth == 4 {
+ RegSpec::eax()
+ } else {
+ RegSpec::ax()
+ };
+ instruction.imm =
+ read_num(&mut bytes_iter, 1)?;
+ *length += 1;
+ instruction.operands[0] = OperandSpec::ImmU8;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ }
+ OperandCode::AX_DX => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr = if opwidth == 4 {
+ RegSpec::eax()
+ } else {
+ RegSpec::ax()
+ };
+ instruction.modrm_mmm = RegSpec::dx();
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegMMM;
+ instruction.operand_count = 2;
+ }
+ OperandCode::AL_DX => {
+ instruction.modrm_rrr = RegSpec::al();
+ instruction.modrm_mmm = RegSpec::dx();
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegMMM;
+ instruction.operand_count = 2;
+ }
+ OperandCode::DX_AX => {
+ let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes);
+ instruction.modrm_rrr = if opwidth == 4 {
+ RegSpec::eax()
+ } else {
+ RegSpec::ax()
+ };
+ instruction.modrm_mmm = RegSpec::dx();
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ }
+ OperandCode::DX_AL => {
+ instruction.modrm_rrr = RegSpec::al();
+ instruction.modrm_mmm = RegSpec::dx();
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operand_count = 2;
+ }
+ _ => {
+ instruction.operand_count = 0;
+ instruction.opcode = Opcode::Invalid;
+// return Err(()); // Err(format!("unsupported operand code: {:?}", operand_code));
+ return Err(DecodeError::InvalidOperand);
+ }
+ };
+ Ok(())
+}
+
+fn decode_one<'b, T: IntoIterator<Item=u8>>(decoder: &InstDecoder, bytes: T, instr: &'b mut Instruction) -> Result<(), DecodeError> {
+ instr.operands = [
+ OperandSpec::Nothing,
+ OperandSpec::Nothing,
+ OperandSpec::Nothing,
+ OperandSpec::Nothing,
+ ];
+ let bytes_iter = bytes.into_iter();
+ read_instr(decoder, bytes_iter, instr)
+}
+
+#[inline]
+fn read_num<T: Iterator<Item=u8>>(bytes: &mut T, width: u8) -> Result<u32, DecodeError> {
+ let mut result = 0u32;
+ let mut idx = 0;
+ loop {
+ if idx == width {
+ return Ok(result);
+ }
+ let byte = bytes.next().ok_or(DecodeError::ExhaustedInput)?;
+ result |= (byte as u32) << (idx * 8);
+ idx += 1;
+ }
+}
+
+#[inline]
+fn read_imm_signed<T: Iterator<Item=u8>>(bytes: &mut T, num_width: u8, length: &mut u8) -> Result<i32, DecodeError> {
+ if num_width == 1 {
+ *length += 1;
+ Ok(read_num(bytes, 1)? as i8 as i32)
+ } else if num_width == 2 {
+ *length += 2;
+ Ok(read_num(bytes, 2)? as i16 as i32)
+ } else {
+ *length += 4;
+ Ok(read_num(bytes, 4)? as i32)
+ }
+}
+
+#[inline]
+fn read_imm_unsigned<T: Iterator<Item=u8>>(bytes: &mut T, width: u8, length: &mut u8) -> Result<u32, DecodeError> {
+ read_num(bytes, width).map(|res| {
+ *length += width;
+ res
+ })
+}
+
+#[inline]
+fn imm_width_from_prefixes(interpretation: SizeCode, prefixes: Prefixes) -> u8 {
+ match interpretation {
+ SizeCode::b => 1,
+ SizeCode::vd => {
+ if prefixes.operand_size() { 2 } else { 4 }
+ },
+ }
+}
+
+#[inline]
+fn read_modrm<T: Iterator<Item=u8>>(bytes_iter: &mut T, length: &mut u8) -> Result<u8, DecodeError> {
+ bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })
+}
diff --git a/src/protected_mode/vex.rs b/src/protected_mode/vex.rs
new file mode 100644
index 0000000..b4716d7
--- /dev/null
+++ b/src/protected_mode/vex.rs
@@ -0,0 +1,2513 @@
+use crate::protected_mode::OperandSpec;
+use crate::protected_mode::DecodeError;
+use crate::protected_mode::RegSpec;
+use crate::protected_mode::RegisterBank;
+use crate::protected_mode::Instruction;
+use crate::protected_mode::Opcode;
+use crate::protected_mode::read_modrm;
+use crate::protected_mode::read_E;
+use crate::protected_mode::read_E_xmm;
+use crate::protected_mode::read_E_ymm;
+use crate::protected_mode::read_imm_unsigned;
+
+#[derive(Debug)]
+enum VEXOpcodeMap {
+ Map0F,
+ Map0F38,
+ Map0F3A,
+}
+
+#[derive(Debug)]
+enum VEXOpcodePrefix {
+ None,
+ Prefix66,
+ PrefixF3,
+ PrefixF2,
+}
+
+#[allow(non_camel_case_types)]
+#[derive(Debug)]
+enum VEXOperandCode {
+ Nothing,
+ VPS_71,
+ VPS_71_L,
+ VPS_72,
+ VPS_72_L,
+ VPS_73,
+ VPS_73_L,
+ VMOVSS_10,
+ VMOVSD_10,
+ VMOVSD_11,
+ VMOVSS_11,
+ E_G_xmm,
+ U_G_xmm,
+ M_G_xmm,
+ G_M_xmm,
+ G_U_xmm,
+ E_G_xmm_imm8,
+ U_G_xmm_imm8,
+ E_G_ymm,
+ U_G_ymm,
+ M_G_ymm,
+ G_E_ymm,
+ G_M_ymm,
+ G_U_ymm,
+ E_V_G_ymm,
+ E_V_G_xmm,
+ E_xmm_G_ymm_imm8,
+ Ev_G_xmm_imm8,
+ G_Ex_V_xmm,
+ G_Ey_V_ymm,
+ G_E_xmm,
+ G_E_xmm_imm8,
+ G_E_ymm_imm8,
+ G_xmm_E_xmm,
+ G_xmm_E_ymm,
+ G_ymm_E_xmm,
+ G_ymm_E_ymm,
+ G_V_ymm_E_xmm,
+ M_V_G_xmm,
+ M_V_G_ymm,
+ G_V_E_xmm,
+ G_V_E_xmm_imm8,
+ G_V_E_xmm_xmm4,
+ G_V_E_ymm,
+ G_V_E_ymm_imm8,
+ G_V_E_ymm_ymm4,
+ G_V_M_xmm,
+ G_V_M_ymm,
+ V_xmm_G_ymm_E_ymm_imm8,
+ V_ymm_G_ymm_E_xmm_imm8,
+ G_V_xmm_Ew_imm8,
+ Eq_G_xmm,
+ Ed_G_xmm,
+ G_xmm_Ed,
+ G_xmm_Eq,
+}
+
+#[inline(never)]
+pub(crate) fn three_byte_vex<T: Iterator<Item=u8>>(bytes: &mut T, vex_byte_one: u8, instruction: &mut Instruction, mut length: u8) -> Result<(), DecodeError> {
+ let vex_byte_two = bytes.next().ok_or(DecodeError::ExhaustedInput)?;
+ length += 1;
+ let p = vex_byte_two & 0x03;
+ let p = match p {
+ 0x00 => VEXOpcodePrefix::None,
+ 0x01 => VEXOpcodePrefix::Prefix66,
+ 0x02 => VEXOpcodePrefix::PrefixF3,
+ 0x03 => VEXOpcodePrefix::PrefixF2,
+ _ => { unreachable!("p is two bits"); }
+ };
+ let m = vex_byte_one & 0b11111;
+// println!("m: {:05b}", m);
+ let m = match m {
+ 0b00001 => VEXOpcodeMap::Map0F,
+ 0b00010 => VEXOpcodeMap::Map0F38,
+ 0b00011 => VEXOpcodeMap::Map0F3A,
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ instruction.vex_reg = RegSpec {
+ bank: RegisterBank::X,
+ num: ((vex_byte_two >> 3) & 0b0111) ^ 0b0111, // ignore bit 4 in 32-bit mode
+ };
+ instruction.prefixes.vex_from_c4(vex_byte_one, vex_byte_two);
+
+ read_vex_instruction(m, bytes, instruction, &mut length, p)?;
+ instruction.length = length;
+ Ok(())
+}
+
+pub(crate) fn two_byte_vex<T: Iterator<Item=u8>>(bytes: &mut T, vex_byte: u8, instruction: &mut Instruction, mut length: u8) -> Result<(), DecodeError> {
+ let p = vex_byte & 0x03;
+ let p = match p {
+ 0x00 => VEXOpcodePrefix::None,
+ 0x01 => VEXOpcodePrefix::Prefix66,
+ 0x02 => VEXOpcodePrefix::PrefixF3,
+ 0x03 => VEXOpcodePrefix::PrefixF2,
+ _ => { unreachable!("p is two bits"); }
+ };
+ instruction.vex_reg = RegSpec {
+ bank: RegisterBank::X,
+ num: ((vex_byte >> 3) & 0b1111) ^ 0b1111,
+ };
+ instruction.prefixes.vex_from_c5(vex_byte);
+
+ read_vex_instruction(VEXOpcodeMap::Map0F, bytes, instruction, &mut length, p)?;
+ instruction.length = length;
+ Ok(())
+}
+
+fn read_vex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut Instruction, length: &mut u8, operand_code: VEXOperandCode) -> Result<(), DecodeError> {
+// println!("operand code: {:?}", operand_code);
+ match operand_code {
+ VEXOperandCode::VPS_71 => {
+ let modrm = read_modrm(bytes, length)?;
+ match (modrm >> 3) & 0b111 {
+ 0b010 => {
+ instruction.opcode = Opcode::VPSRLW;
+ }
+ 0b100 => {
+ instruction.opcode = Opcode::VPSRAW;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::VPSLLW;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ /*
+ 0x71 => (Opcode::VPSLLW, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x71 => (Opcode::VPSRAW, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x71 => (Opcode::VPSRLW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ }),
+ */
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+ VEXOperandCode::VPS_71_L => {
+ let modrm = read_modrm(bytes, length)?;
+ match (modrm >> 3) & 0b111 {
+ 0b010 => {
+ instruction.opcode = Opcode::VPSRLW;
+ }
+ 0b100 => {
+ instruction.opcode = Opcode::VPSRAW;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::VPSLLW;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ /*
+ 0x71 => (Opcode::VPSLLW, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x71 => (Opcode::VPSRAW, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x71 => (Opcode::VPSRLW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ }),
+ */
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+ VEXOperandCode::VPS_72 => {
+ let modrm = read_modrm(bytes, length)?;
+ match (modrm >> 3) & 0b111 {
+ 0b010 => {
+ instruction.opcode = Opcode::VPSRLD;
+ }
+ 0b100 => {
+ instruction.opcode = Opcode::VPSRAD;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::VPSLLD;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ /*
+ 0x72 => (Opcode::VPSLLD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x72 => (Opcode::VPSRAD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x72 => (Opcode::VPSRLD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ */
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+ VEXOperandCode::VPS_72_L => {
+ let modrm = read_modrm(bytes, length)?;
+ match (modrm >> 3) & 0b111 {
+ 0b010 => {
+ instruction.opcode = Opcode::VPSRLD;
+ }
+ 0b100 => {
+ instruction.opcode = Opcode::VPSRAD;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::VPSLLD;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ /*
+ 0x72 => (Opcode::VPSLLD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x72 => (Opcode::VPSRAD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x72 => (Opcode::VPSRLD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ */
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+ VEXOperandCode::VPS_73 => {
+ let modrm = read_modrm(bytes, length)?;
+ match (modrm >> 3) & 0b111 {
+ 0b010 => {
+ instruction.opcode = Opcode::VPSRLQ;
+ }
+ 0b011 => {
+ instruction.opcode = Opcode::VPSRLDQ;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::VPSLLQ;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::VPSLLDQ;
+ }
+ _ => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ // VEXOperandCode::G_E_xmm_imm8 ? this is reg1, reg2, imm8, but r is used for
+ // picking the opcode. is one of these actually the vex reg?
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+ VEXOperandCode::VPS_73_L => {
+ let modrm = read_modrm(bytes, length)?;
+ match (modrm >> 3) & 0b111 {
+ 0b000 |
+ 0b001 |
+ 0b100 |
+ 0b101 => {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ 0b010 => {
+ instruction.opcode = Opcode::VPSRLQ;
+ }
+ 0b011 => {
+ instruction.opcode = Opcode::VPSRLDQ;
+ }
+ 0b110 => {
+ instruction.opcode = Opcode::VPSLLQ;
+ }
+ 0b111 => {
+ instruction.opcode = Opcode::VPSLLDQ;
+ }
+ _ => {
+ unreachable!("r is only three bits");
+ }
+ }
+ // VEXOperandCode::G_E_ymm_imm8 ? this is reg1, reg2, imm8, but r is used for
+ // picking the opcode. is one of these actually the vex reg?
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+ VEXOperandCode::VMOVSS_10 |
+ VEXOperandCode::VMOVSD_10 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ match mem_oper {
+ OperandSpec::RegMMM => {
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = OperandSpec::RegMMM;
+ },
+ other => {
+ instruction.operands[1] = other;
+ }
+ }
+ Ok(())
+ },
+ VEXOperandCode::VMOVSS_11 |
+ VEXOperandCode::VMOVSD_11 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ match mem_oper {
+ OperandSpec::RegMMM => {
+ instruction.operands[0] = OperandSpec::RegVex;
+ instruction.operands[2] = OperandSpec::RegMMM;
+ },
+ other => {
+ instruction.operands[0] = other;
+ }
+ }
+ Ok(())
+ },
+ VEXOperandCode::Nothing => {
+ Ok(())
+ },
+ VEXOperandCode::Ev_G_xmm_imm8 => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E(bytes, instruction, modrm, 4, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operands[2] = OperandSpec::ImmU8;
+ instruction.imm = read_imm_unsigned(bytes, 1, length)?;
+ Ok(())
+ },
+ VEXOperandCode::G_xmm_Eq => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E(bytes, instruction, modrm, 4, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ VEXOperandCode::G_xmm_Ed => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E(bytes, instruction, modrm, 4, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ VEXOperandCode::Eq_G_xmm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E(bytes, instruction, modrm, 4, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ Ok(())
+ }
+ VEXOperandCode::Ed_G_xmm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E(bytes, instruction, modrm, 4, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ Ok(())
+ }
+ _op @ VEXOperandCode::E_G_xmm |
+ _op @ VEXOperandCode::U_G_xmm |
+ _op @ VEXOperandCode::M_G_xmm |
+ _op @ VEXOperandCode::E_G_xmm_imm8 |
+ _op @ VEXOperandCode::U_G_xmm_imm8 => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ Ok(())
+ }
+ _op @ VEXOperandCode::E_xmm_G_ymm_imm8 => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ Ok(())
+ }
+
+ _op @ VEXOperandCode::G_M_xmm |
+ _op @ VEXOperandCode::G_U_xmm |
+ _op @ VEXOperandCode::G_E_xmm |
+ _op @ VEXOperandCode::G_E_xmm_imm8 => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_xmm_E_xmm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_xmm_E_ymm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_ymm_E_xmm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_ymm_E_ymm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+
+ _op @ VEXOperandCode::E_G_ymm |
+ _op @ VEXOperandCode::U_G_ymm |
+ _op @ VEXOperandCode::M_G_ymm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ Ok(())
+ }
+
+ _op @ VEXOperandCode::G_M_ymm |
+ _op @ VEXOperandCode::G_U_ymm |
+ _op @ VEXOperandCode::G_E_ymm => {
+ if instruction.vex_reg.num != 0 {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_V_E_ymm |
+ _op @ VEXOperandCode::G_V_M_ymm => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ instruction.vex_reg.bank = RegisterBank::Y;
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_V_E_ymm_imm8 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ instruction.vex_reg.bank = RegisterBank::Y;
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = mem_oper;
+ instruction.imm = read_imm_unsigned(bytes, 1, length)?;
+ instruction.operands[3] = OperandSpec::ImmU8;
+ Ok(())
+ }
+ _op @ VEXOperandCode::E_V_G_ymm |
+ _op @ VEXOperandCode::M_V_G_ymm => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ instruction.vex_reg.bank = RegisterBank::Y;
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = OperandSpec::RegRRR;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_V_M_xmm |
+ _op @ VEXOperandCode::G_V_E_xmm => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = mem_oper;
+ Ok(())
+ }
+ _op @ VEXOperandCode::G_V_E_xmm_imm8 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = mem_oper;
+ instruction.imm = read_imm_unsigned(bytes, 1, length)?;
+ instruction.operands[3] = OperandSpec::ImmU8;
+ Ok(())
+ }
+ _op @ VEXOperandCode::V_ymm_G_ymm_E_xmm_imm8 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ instruction.vex_reg.bank = RegisterBank::Y;
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegVex;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operands[2] = mem_oper;
+ instruction.imm = read_imm_unsigned(bytes, 1, length)?;
+ instruction.operands[3] = OperandSpec::ImmU8;
+ Ok(())
+ }
+ _op @ VEXOperandCode::V_xmm_G_ymm_E_ymm_imm8 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = OperandSpec::RegVex;
+ instruction.operands[1] = OperandSpec::RegRRR;
+ instruction.operands[2] = mem_oper;
+ instruction.imm = read_imm_unsigned(bytes, 1, length)?;
+ instruction.operands[3] = OperandSpec::ImmU8;
+ Ok(())
+ }
+ _op @ VEXOperandCode::E_V_G_xmm |
+ _op @ VEXOperandCode::M_V_G_xmm => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.operands[0] = mem_oper;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = OperandSpec::RegRRR;
+ Ok(())
+ }
+
+ VEXOperandCode::G_Ex_V_xmm => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X);
+ let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?;
+ instruction.sib_index.bank = RegisterBank::X;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.operands[2] = OperandSpec::RegVex;
+ Ok(())
+ }
+ VEXOperandCode::G_Ey_V_ymm => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::Y);
+ let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?;
+ instruction.vex_reg.bank = RegisterBank::Y;
+ instruction.sib_index.bank = RegisterBank::Y;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.operands[2] = OperandSpec::RegVex;
+ Ok(())
+ }
+
+ VEXOperandCode::G_E_ymm_imm8 |
+ VEXOperandCode::G_V_E_xmm_xmm4 |
+ VEXOperandCode::G_V_E_ymm_ymm4 |
+ VEXOperandCode::G_V_ymm_E_xmm |
+ VEXOperandCode::G_V_xmm_Ew_imm8 => {
+ Err(DecodeError::IncompleteDecoder) // :)
+ }
+
+ }
+}
+
+fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &mut T, instruction: &mut Instruction, length: &mut u8, p: VEXOpcodePrefix) -> Result<(), DecodeError> {
+ let opc = bytes.next().ok_or(DecodeError::ExhaustedInput)?;
+ *length += 1;
+
+ // the name of this bit is `L` in the documentation, so use the same name here.
+ #[allow(non_snake_case)]
+ let L = instruction.prefixes.vex().l();
+
+// println!("reading vex instruction from opcode prefix {:?}, L: {}, opc: {:#x}, map:{:?}", p, L, opc, opcode_map);
+// println!("w? {}", instruction.prefixes.vex().w());
+
+ // several combinations simply have no instructions. check for those first.
+ let (opcode, operand_code) = match opcode_map {
+ VEXOpcodeMap::Map0F => {
+ match p {
+ VEXOpcodePrefix::None => {
+ match opc {
+ 0x10 => (Opcode::VMOVUPS, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }),
+ 0x11 => (Opcode::VMOVUPS, if L { VEXOperandCode::E_G_ymm } else { VEXOperandCode::E_G_xmm }),
+ // ugh
+// 0x12 => (Opcode::VMOVHLPS, ..),
+// 0x12 => (Opcode::VMOVLPS, ..),
+ 0x13 => (Opcode::VMOVLPS, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0x14 => (Opcode::VUNPCKLPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x15 => (Opcode::VUNPCKHPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ // ugh
+// 0x16 => (Opcode::VMOVHPS, ..),
+// 0x16 => (Opcode::VMOVLHPS, ..),
+ 0x17 => (Opcode::VMOVHPS, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0x28 => (Opcode::VMOVAPS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x29 => (Opcode::VMOVAPS, if L {
+ VEXOperandCode::E_G_ymm
+ } else {
+ VEXOperandCode::E_G_xmm
+ }),
+ 0x2B => (Opcode::VMOVNTPS, if L {
+ VEXOperandCode::M_G_ymm
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0x2e => (Opcode::VUCOMISS, VEXOperandCode::G_E_xmm),
+ 0x2f => (Opcode::VCOMISS, VEXOperandCode::G_E_xmm),
+ 0x50 => (Opcode::VMOVMSKPS, if L {
+ VEXOperandCode::U_G_ymm
+ } else {
+ VEXOperandCode::U_G_xmm
+ }),
+ 0x51 => (Opcode::VSQRTPS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x52 => (Opcode::VRSQRTPS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x53 => (Opcode::VRCPPS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x57 => (Opcode::VXORPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x58 => (Opcode::VADDPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x59 => (Opcode::VMULPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5A => (Opcode::VCVTPS2PD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x5B => (Opcode::VCVTDQ2PS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x5C => (Opcode::VSUBPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5D => (Opcode::VMINPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5E => (Opcode::VDIVPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5F => (Opcode::VMAXPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x77 => (Opcode::VZEROUPPER, VEXOperandCode::Nothing),
+ 0xC2 => (Opcode::VCMPPS, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0xC6 => (Opcode::VSHUFPS, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ },
+ VEXOpcodePrefix::Prefix66 => {
+ match opc {
+ 0x0a => (Opcode::VROUNDSS, VEXOperandCode::G_V_E_xmm_imm8),
+ 0x0b => (Opcode::VROUNDSD, VEXOperandCode::G_V_E_xmm_imm8),
+ 0x10 => (Opcode::VMOVUPD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x11 => (Opcode::VMOVUPD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x12 => (Opcode::VMOVLPD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_M_xmm
+ }),
+ 0x13 => (Opcode::VMOVLPD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0x14 => (Opcode::VUNPCKLPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x15 => (Opcode::VUNPCKHPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x16 => (Opcode::VMOVHPD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_M_xmm
+ }),
+ 0x17 => (Opcode::VMOVHPD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0x28 => (Opcode::VMOVAPD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x29 => (Opcode::VMOVAPD, if L {
+ VEXOperandCode::E_G_ymm
+ } else {
+ VEXOperandCode::E_G_xmm
+ }),
+ 0x2B => (Opcode::VMOVNTPD, if L {
+ VEXOperandCode::M_G_ymm
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0x2e => (Opcode::VUCOMISD, VEXOperandCode::G_E_xmm),
+ 0x2f => (Opcode::VCOMISD, VEXOperandCode::G_E_xmm),
+ 0x50 => (Opcode::VMOVMSKPD, if L {
+ VEXOperandCode::G_U_ymm
+ } else {
+ VEXOperandCode::G_U_xmm
+ }),
+ 0x51 => (Opcode::VSQRTPD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x57 => (Opcode::VXORPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x58 => (Opcode::VADDPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x59 => (Opcode::VMULPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5A => (Opcode::VCVTPD2PS, if L {
+ VEXOperandCode::G_xmm_E_ymm
+ } else {
+ VEXOperandCode::G_xmm_E_xmm
+ }),
+ 0x5B => (Opcode::VCVTPS2DQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x5C => (Opcode::VSUBPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5D => (Opcode::VMINPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5E => (Opcode::VDIVPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x5F => (Opcode::VMAXPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x60 => (Opcode::VPUNPCKLBW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x61 => (Opcode::VPUNPCKLWD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x62 => (Opcode::VPUNPCKLDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x63 => (Opcode::VPACKSSWB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x64 => (Opcode::VPCMPGTB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x65 => (Opcode::VPCMPGTW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x66 => (Opcode::VPCMPGTD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x67 => (Opcode::VPACKUSWB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x68 => (Opcode::VPUNPCKHBW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x69 => (Opcode::VPUNPCKHWD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x6A => (Opcode::VPUNPCKHDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x6B => (Opcode::VPACKSSDW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x6C => (Opcode::VPUNPCKLQDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x6D => (Opcode::VPUNPCKHQDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x6E => if instruction.prefixes.vex().w() {
+ (Opcode::VMOVQ, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_xmm_Eq
+ })
+ } else {
+ (Opcode::VMOVD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_xmm_Ed
+ })
+ },
+ 0x6F => (Opcode::VMOVDQA, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x70 => (Opcode::VPSHUFD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0x71 => (Opcode::Invalid, if L {
+ VEXOperandCode::VPS_71_L
+ } else {
+ VEXOperandCode::VPS_71
+ }),
+ 0x72 => (Opcode::Invalid, if L {
+ VEXOperandCode::VPS_72_L
+ } else {
+ VEXOperandCode::VPS_72
+ }),
+ 0x73 => (Opcode::Invalid, if L {
+ VEXOperandCode::VPS_73_L
+ } else {
+ VEXOperandCode::VPS_73
+ }),
+ 0x74 => (Opcode::VPCMPEQB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x75 => (Opcode::VPCMPEQW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x76 => (Opcode::VPCMPEQD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x7C => (Opcode::VHADDPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x7D => (Opcode::VHSUBPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x7E => if instruction.prefixes.vex().w() {
+ (Opcode::VMOVQ, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::Eq_G_xmm
+ })
+ } else {
+ (Opcode::VMOVD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::Ed_G_xmm
+ })
+ }
+ 0x7F => (Opcode::VMOVDQA, if L {
+ VEXOperandCode::E_G_ymm
+ } else {
+ VEXOperandCode::E_G_xmm
+ }),
+ 0xC2 => (Opcode::VCMPPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xC4 => (Opcode::VPINSRW, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_xmm_Ew_imm8
+ }),
+ 0xC5 => (Opcode::VPEXTRW, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::U_G_xmm_imm8
+ }),
+ 0xC6 => (Opcode::VSHUFPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD0 => (Opcode::VADDSUBPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD1 => (Opcode::VPSRLW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD2 => (Opcode::VPSRLD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD3 => (Opcode::VPSRLQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD4 => (Opcode::VPADDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD5 => (Opcode::VPMULLW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD6 => (Opcode::VMOVQ, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0xD7 => (Opcode::VPMOVMSKB, if L {
+ VEXOperandCode::U_G_ymm
+ } else {
+ VEXOperandCode::U_G_xmm
+ }),
+ 0xD8 => (Opcode::VPSUBUSB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xD9 => (Opcode::VPSUBUSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xDB => (Opcode::VPAND, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xDC => (Opcode::VPADDUSB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0xDD => (Opcode::VPADDUSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xDF => (Opcode::VPANDN, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE0 => (Opcode::VPAVGB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE1 => (Opcode::VPSRAW, if L {
+ VEXOperandCode::G_V_ymm_E_xmm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE2 => (Opcode::VPSRAD, if L {
+ VEXOperandCode::G_V_ymm_E_xmm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE3 => (Opcode::VPAVGW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE4 => (Opcode::VPMULHUW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE5 => (Opcode::VPMULHW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE6 => (Opcode::VCVTTPD2DQ, if L {
+ VEXOperandCode::G_xmm_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0xE7 => (Opcode::VMOVNTDQ, if L {
+ VEXOperandCode::M_G_ymm
+ } else {
+ VEXOperandCode::M_G_xmm
+ }),
+ 0xE8 => (Opcode::VPSUBSB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xE9 => (Opcode::VPSUBSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xEB => (Opcode::VPOR, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xEC => (Opcode::VPADDSB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xED => (Opcode::VPADDSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xEE => (Opcode::VPMAXSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xEF => (Opcode::VPXOR, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF1 => (Opcode::VPSLLW, if L {
+ VEXOperandCode::G_V_ymm_E_xmm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF2 => (Opcode::VPSLLD, if L {
+ VEXOperandCode::G_V_ymm_E_xmm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF3 => (Opcode::VPSLLQ, if L {
+ VEXOperandCode::G_V_ymm_E_xmm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF4 => (Opcode::VPMULUDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF5 => (Opcode::VPMADDWD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF6 => (Opcode::VPSADBW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF7 => (Opcode::VMASKMOVDQU, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0xF8 => (Opcode::VPSUBB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xF9 => (Opcode::VPSUBW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xFA => (Opcode::VPSUBD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xFB => (Opcode::VPSUBQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xFC => (Opcode::VPADDB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xFD => (Opcode::VPADDW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xFE => (Opcode::VPADDD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ VEXOpcodePrefix::PrefixF2 => {
+ match opc {
+ 0x10 => (Opcode::VMOVSD, VEXOperandCode::VMOVSD_10),
+ 0x11 => (Opcode::VMOVSD, VEXOperandCode::VMOVSD_11),
+ 0x12 => (Opcode::VMOVDDUP, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x2a => (Opcode::VCVTSI2SD, if instruction.prefixes.vex().w() {
+ VEXOperandCode::G_V_E_xmm // 64-bit last operand
+ } else {
+ VEXOperandCode::G_V_E_xmm // 32-bit last operand
+ }),
+ 0x2c => (Opcode::VCVTTSD2SI, if instruction.prefixes.vex().w() {
+ VEXOperandCode::G_E_xmm // 64-bit
+ } else {
+ VEXOperandCode::G_E_xmm // 32-bit
+ }),
+ 0x2d => (Opcode::VCVTSD2SI, if instruction.prefixes.vex().w() {
+ VEXOperandCode::G_E_xmm // 64-bit
+ } else {
+ VEXOperandCode::G_E_xmm // 32-bit
+ }),
+ 0x51 => (Opcode::VSQRTSD, VEXOperandCode::G_V_E_xmm),
+ 0x58 => (Opcode::VADDSD, VEXOperandCode::G_V_E_xmm),
+ 0x59 => (Opcode::VMULSD, VEXOperandCode::G_V_E_xmm),
+ 0x5a => (Opcode::CVTSD2SS, VEXOperandCode::G_V_E_xmm),
+ 0x5c => (Opcode::VSUBSD, VEXOperandCode::G_V_E_xmm),
+ 0x5d => (Opcode::VMINSD, VEXOperandCode::G_V_E_xmm),
+ 0x5e => (Opcode::VDIVSD, VEXOperandCode::G_V_E_xmm),
+ 0x5f => (Opcode::VMAXSD, VEXOperandCode::G_V_E_xmm),
+ 0x70 => (Opcode::VPSHUFLW, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0x7c => (Opcode::VHADDPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x7d => (Opcode::VHSUBPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xc2 => (Opcode::VCMPSD, VEXOperandCode::G_V_E_xmm_imm8),
+ 0xd0 => (Opcode::VADDSUBPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xe6 => (Opcode::VCVTPD2DQ, if L {
+ VEXOperandCode::G_xmm_E_ymm
+ } else {
+ VEXOperandCode::G_xmm_E_xmm
+ }),
+ 0xf0 => (Opcode::VLDDQU, if L {
+ VEXOperandCode::G_M_ymm
+ } else {
+ VEXOperandCode::G_M_ymm
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ VEXOpcodePrefix::PrefixF3 => {
+ match opc {
+ 0x10 => (Opcode::VMOVSS, VEXOperandCode::VMOVSS_10),
+ 0x11 => (Opcode::VMOVSS, VEXOperandCode::VMOVSS_11),
+ 0x12 => (Opcode::VMOVSLDUP, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }),
+ 0x16 => (Opcode::VMOVSHDUP, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }),
+ 0x2a => (Opcode::VCVTSI2SS, if instruction.prefixes.vex().w() {
+ VEXOperandCode::G_V_E_xmm // 64-bit last operand
+ } else {
+ VEXOperandCode::G_V_E_xmm // 32-bit last operand
+ }),
+ 0x2c => (Opcode::VCVTTSS2SI, if instruction.prefixes.vex().w() {
+ VEXOperandCode::G_E_xmm // 64-bit
+ } else {
+ VEXOperandCode::G_E_xmm // 32-bit
+ }),
+ 0x2d => (Opcode::VCVTSD2SI, if instruction.prefixes.vex().w() {
+ VEXOperandCode::G_E_xmm // 64-bit
+ } else {
+ VEXOperandCode::G_E_xmm // 32-bit
+ }),
+ 0x51 => (Opcode::VSQRTSS, VEXOperandCode::G_V_E_xmm),
+ 0x52 => (Opcode::VRSQRTSS, VEXOperandCode::G_V_E_xmm),
+ 0x53 => (Opcode::VRCPSS, VEXOperandCode::G_V_E_xmm),
+ 0x58 => (Opcode::VADDSS, VEXOperandCode::G_V_E_xmm),
+ 0x59 => (Opcode::VMULSS, VEXOperandCode::G_V_E_xmm),
+ 0x5a => (Opcode::VCVTSS2SD, VEXOperandCode::G_V_E_xmm),
+ 0x5b => (Opcode::VCVTTPS2DQ, if L { VEXOperandCode::G_ymm_E_ymm } else { VEXOperandCode::G_xmm_E_xmm }),
+ 0x5c => (Opcode::VSUBSS, VEXOperandCode::G_V_E_xmm),
+ 0x5d => (Opcode::VMINSS, VEXOperandCode::G_V_E_xmm),
+ 0x5e => (Opcode::VDIVSS, VEXOperandCode::G_V_E_xmm),
+ 0x5f => (Opcode::VMAXSS, VEXOperandCode::G_V_E_xmm),
+ 0x6f => (Opcode::VMOVDQU, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }),
+ 0x70 => (Opcode::VMOVSHDUP, if L { VEXOperandCode::G_E_ymm_imm8 } else { VEXOperandCode::G_E_xmm_imm8 }),
+ 0x7e => (Opcode::VMOVQ, if L { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { VEXOperandCode::G_E_xmm }),
+ 0x7f => (Opcode::VMOVDQU, if L { VEXOperandCode::E_G_ymm } else { VEXOperandCode::E_G_xmm }),
+ 0xc2 => (Opcode::VCMPSS, VEXOperandCode::G_V_E_xmm_imm8),
+ 0xe6 => (Opcode::VCVTDQ2PD, if L { VEXOperandCode::G_ymm_E_xmm } else { VEXOperandCode::G_xmm_E_xmm }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ }
+ }
+ VEXOpcodeMap::Map0F38 => {
+ // TODO: verify rejecting invalid W bit
+ if let VEXOpcodePrefix::Prefix66 = p {
+ // possibly valid!
+ match opc {
+ 0x00 => (Opcode::VPSHUFB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x01 => (Opcode::VPHADDW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x02 => (Opcode::VPHADDD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x03 => (Opcode::VPHADDSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x04 => (Opcode::VPHADDUBSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x05 => (Opcode::VPHSUBW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x06 => (Opcode::VPHSUBD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x07 => (Opcode::VPHSUBSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x08 => (Opcode::VPSIGNB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x09 => (Opcode::VPSIGNW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x0A => (Opcode::VPSIGND, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x0B => (Opcode::VPMULHRSW, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x0C => (Opcode::VPERMILPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x0D => (Opcode::VPERMILPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x0E => (Opcode::VTESTPS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x0F => (Opcode::VTESTPD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x13 => (Opcode::VCVTPH2PS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x16 => (Opcode::VPERMPS, if L {
+ VEXOperandCode::G_V_E_xmm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x17 => (Opcode::VPTEST, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x18 => (Opcode::VBROADCASTSS, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x19 => (Opcode::VBROADCASTSD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x1A => (Opcode::VBROADCASTF128, if L {
+ VEXOperandCode::G_M_ymm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x1C => (Opcode::VPABSB, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x1D => (Opcode::VPABSW, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x1E => (Opcode::VPABSD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x20 => (Opcode::VPMOVSXBW, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x21 => (Opcode::VPMOVSXBD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x22 => (Opcode::VPMOVSXBQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x23 => (Opcode::VPMOVSXWD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x24 => (Opcode::VPMOVSXWQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x25 => (Opcode::VPMOVSXDQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x28 => (Opcode::VPMULDQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x29 => (Opcode::VPCMPEQQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x2A => (Opcode::VMOVNTDQA, if L {
+ VEXOperandCode::G_M_ymm
+ } else {
+ VEXOperandCode::G_M_xmm
+ }),
+ 0x2C => (Opcode::VMASKMOVPS, if L {
+ VEXOperandCode::G_V_M_ymm
+ } else {
+ VEXOperandCode::G_V_M_xmm
+ }),
+ 0x2D => (Opcode::VMASKMOVPD, if L {
+ VEXOperandCode::G_V_M_ymm
+ } else {
+ VEXOperandCode::G_V_M_xmm
+ }),
+ 0x2E => (Opcode::VMASKMOVPS, if L {
+ VEXOperandCode::M_V_G_ymm
+ } else {
+ VEXOperandCode::M_V_G_xmm
+ }),
+ 0x2F => (Opcode::VMASKMOVPD, if L {
+ VEXOperandCode::M_V_G_ymm
+ } else {
+ VEXOperandCode::M_V_G_xmm
+ }),
+ 0x30 => (Opcode::VPMOVZXBW, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x31 => (Opcode::VPMOVZXBD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x32 => (Opcode::VPMOVZXBQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x33 => (Opcode::VPMOVZXWD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x34 => (Opcode::VPMOVZXWQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x35 => (Opcode::VPMOVZXDQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x36 => (Opcode::VPERMD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x37 => (Opcode::VPCMPGTQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x39 => (Opcode::VPMINSD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x3B => (Opcode::VPMINUD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x3C => (Opcode::VPMAXSB, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x3D => (Opcode::VPMAXSD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x3F => (Opcode::VPMAXUD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x40 => (Opcode::VPMULLD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x41 => (Opcode::VPHMINPOSUW, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x45 => if instruction.prefixes.vex().w() {
+ (Opcode::VPSRLVQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ })
+ } else {
+ (Opcode::VPSRLVD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ })
+ },
+ 0x46 => (Opcode::VPSRAVD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x47 => if instruction.prefixes.vex().w() {
+ (Opcode::VPSLLVQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ })
+ } else {
+ (Opcode::VPSLLVD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ })
+ },
+ 0x58 => (Opcode::VPBROADCASTD, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x59 => (Opcode::VPBROADCASTQ, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0x5A => (Opcode::VBROADCASTI128, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x78 => (Opcode::VPBROADCASTB, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_ymm
+ }),
+ 0x79 => (Opcode::VPBROADCASTW, if L {
+ VEXOperandCode::G_E_ymm
+ } else {
+ VEXOperandCode::G_E_ymm
+ }),
+ 0x8C => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VPMASKMOVD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VPMASKMOVQ, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x8E => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VPMASKMOVD, if L {
+ VEXOperandCode::E_V_G_ymm
+ } else {
+ VEXOperandCode::E_V_G_xmm
+ })
+ } else {
+ (Opcode::VPMASKMOVQ, if L {
+ VEXOperandCode::E_V_G_ymm
+ } else {
+ VEXOperandCode::E_V_G_xmm
+ })
+ }
+ },
+ 0x90 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VPGATHERDQ, if L {
+ VEXOperandCode::G_Ey_V_ymm
+ } else {
+ VEXOperandCode::G_Ex_V_xmm
+ })
+ } else {
+ (Opcode::VPGATHERDD, if L {
+ VEXOperandCode::G_Ey_V_ymm
+ } else {
+ VEXOperandCode::G_Ex_V_xmm
+ })
+ }
+ },
+ 0x91 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VPGATHERQQ, if L {
+ VEXOperandCode::G_Ey_V_ymm
+ } else {
+ VEXOperandCode::G_Ex_V_xmm
+ })
+ } else {
+ (Opcode::VPGATHERQD, if L {
+ VEXOperandCode::G_Ey_V_ymm
+ } else {
+ VEXOperandCode::G_Ex_V_xmm
+ })
+ }
+ },
+ 0x92 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VGATHERDPD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ })
+ } else {
+ (Opcode::VGATHERDPS, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ })
+ }
+ },
+ 0x93 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VGATHERQPD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ })
+ } else {
+ (Opcode::VGATHERQPS, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ })
+ }
+ },
+ 0x96 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMADDSUB132PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMADDSUB132PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x97 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUBADD132PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMSUBADD132PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x98 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMADD132PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMADD132PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x99 => if instruction.prefixes.vex().w() {
+ (Opcode::VFMADD132SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFMADD132SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0x9A => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUB132PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMSUB132PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x9B => if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUB132SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFMSUB132SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0x9C => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFNMADD132PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFNMADD132PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x9D => if instruction.prefixes.vex().w() {
+ (Opcode::VFNMADD132SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFNMADD132SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0x9E => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFNMSUB132PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFNMSUB132PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0x9F => if instruction.prefixes.vex().w() {
+ (Opcode::VFNMSUB132SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFNMSUB132SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xA6 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMADDSUB213PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMADDSUB213PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xA7 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUBADD213PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMSUBADD213PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xA8 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMADD213PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMADD213PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xA9 => if instruction.prefixes.vex().w() {
+ (Opcode::VFMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xAA => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUB213PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMSUB213PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xAB => if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xAC => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFNMADD213PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFNMADD213PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xAD => if instruction.prefixes.vex().w() {
+ (Opcode::VFNMADD213SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFNMADD213SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xAE => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFNMSUB213PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFNMSUB213PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xAF => if instruction.prefixes.vex().w() {
+ (Opcode::VFNMSUB213SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFNMSUB213SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xB6 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMADDSUB231PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMADDSUB231PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xB7 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUBADD231PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMSUBADD231PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xB8 => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMADD231PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMADD231PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xB9 => if instruction.prefixes.vex().w() {
+ (Opcode::VFMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xBA => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUB231PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFMSUB231PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xBB => if instruction.prefixes.vex().w() {
+ (Opcode::VFMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xBC => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFNMADD231PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFNMADD231PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xBD => if instruction.prefixes.vex().w() {
+ (Opcode::VFNMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFNMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xBE => {
+ if instruction.prefixes.vex().w() {
+ (Opcode::VFNMSUB231PD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ } else {
+ (Opcode::VFNMSUB231PS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_ymm
+ })
+ }
+ },
+ 0xBF => if instruction.prefixes.vex().w() {
+ (Opcode::VFNMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ } else {
+ (Opcode::VFNMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */)
+ },
+ 0xDB => (Opcode::VAESIMC, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm
+ }),
+ 0xDC => (Opcode::VAESENC, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xDD => (Opcode::VAESENCLAST, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xDE => (Opcode::VAESDEC, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0xDF => (Opcode::VAESDECLAST, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ // the only VEX* 0f38 instructions have an implied 66 prefix.
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ VEXOpcodeMap::Map0F3A => {
+ if let VEXOpcodePrefix::Prefix66 = p {
+ // possibly valid!
+ match opc {
+ 0x00 => (Opcode::VPERMQ, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x01 => (Opcode::VPERMPD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x02 => (Opcode::VPBLENDD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x04 => (Opcode::VPERMILPS, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x05 => (Opcode::VPERMILPD, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ VEXOperandCode::G_V_E_xmm
+ }),
+ 0x06 => (Opcode::VPERM2F128, if L {
+ VEXOperandCode::G_V_E_ymm
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x08 => (Opcode::VROUNDPS, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0x09 => (Opcode::VROUNDPD, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0x0C => (Opcode::VBLENDPS, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x0D => (Opcode::VBLENDPD, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x0E => (Opcode::VPBLENDW, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x0F => (Opcode::VPALIGNR, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x14 => (Opcode::VPEXTRB, if L || instruction.prefixes.vex().w() {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::Ev_G_xmm_imm8
+ }),
+ 0x15 => (Opcode::VPEXTRW, if L || instruction.prefixes.vex().w() {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::Ev_G_xmm_imm8
+ }),
+ 0x16 => if instruction.prefixes.vex().w() {
+ (Opcode::VPEXTRQ, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ })
+ } else {
+ (Opcode::VPEXTRD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ // varies on W
+ VEXOperandCode::Ev_G_xmm_imm8
+ })
+ },
+ 0x17 => (Opcode::VEXTRACTPS, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_ymm_imm8
+ }),
+ 0x18 => (Opcode::VINSERTF128, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x19 => (Opcode::VEXTRACTF128, if L {
+ VEXOperandCode::E_xmm_G_ymm_imm8
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x1D => (Opcode::VCVTPS2PH, if L {
+ VEXOperandCode::E_xmm_G_ymm_imm8
+ } else {
+ VEXOperandCode::E_G_xmm_imm8
+ }),
+ 0x20 => (Opcode::VPINSRB, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x21 => (Opcode::VINSERTPS, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x22 => if instruction.prefixes.vex().w() {
+ (Opcode::VPINSRQ, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ })
+ } else {
+ (Opcode::VPINSRD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ })
+ },
+ 0x38 => (Opcode::VINSERTI128, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::V_ymm_G_ymm_E_xmm_imm8
+ }),
+ 0x39 => (Opcode::VEXTRACTI128, if L {
+ VEXOperandCode::V_xmm_G_ymm_E_ymm_imm8
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x40 => (Opcode::VDPPS, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x41 => (Opcode::VDPPD, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x42 => (Opcode::VMPSADBW, if L {
+ VEXOperandCode::G_E_ymm_imm8
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0x44 => (Opcode::VPCLMULQDQ, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E_xmm_imm8
+ }),
+ 0x46 => (Opcode::VPERM2I128, if L {
+ VEXOperandCode::G_V_E_ymm_imm8
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }),
+ 0x4A => (Opcode::VBLENDVPS, if L {
+ VEXOperandCode::G_V_E_ymm_ymm4
+ } else {
+ VEXOperandCode::G_V_E_xmm_xmm4
+ }),
+ 0x4B => (Opcode::VBLENDVPD, if L {
+ VEXOperandCode::G_V_E_ymm_ymm4
+ } else {
+ VEXOperandCode::G_V_E_xmm_xmm4
+ }),
+ 0x4C => (Opcode::VPBLENDVB, if L {
+ VEXOperandCode::G_V_E_ymm_ymm4
+ } else {
+ VEXOperandCode::G_V_E_xmm_xmm4
+ }),
+ 0x62 => (Opcode::VPCMPISTRM, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0x63 => (Opcode::VPCMPISTRI, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ 0xDF => (Opcode::VAESKEYGENASSIST, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_xmm_imm8
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else {
+ // the only VEX* 0f3a instructions have an implied 66 prefix.
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ };
+ instruction.opcode = opcode;
+ read_vex_operands(bytes, instruction, length, operand_code)
+}
diff --git a/test/long_mode/mod.rs b/test/long_mode/mod.rs
new file mode 100644
index 0000000..33de87f
--- /dev/null
+++ b/test/long_mode/mod.rs
@@ -0,0 +1,1094 @@
+mod regspec;
+
+use std::fmt::Write;
+
+use yaxpeax_arch::{Decoder, LengthedInstruction};
+use yaxpeax_x86::long_mode::{DecodeError, InstDecoder, Opcode};
+
+fn test_invalid(data: &[u8]) {
+ test_invalid_under(&InstDecoder::default(), data);
+}
+
+fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) {
+ if let Ok(inst) = decoder.decode(data.into_iter().cloned()) {
+ assert_eq!(inst.opcode, Opcode::Invalid, "decoded {:?} from {:02x?} under decoder {}", inst.opcode, data, decoder);
+ } else {
+ // this is fine
+ }
+}
+
+fn test_display(data: &[u8], expected: &'static str) {
+ test_display_under(&InstDecoder::default(), data, expected);
+}
+
+fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str) {
+ let mut hex = String::new();
+ for b in data {
+ write!(hex, "{:02x}", b).unwrap();
+ }
+ match decoder.decode(data.into_iter().map(|x| *x)) {
+ Ok(instr) => {
+ let text = format!("{}", instr);
+ assert!(
+ text == expected,
+ "display error for {}:\n decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n",
+ hex,
+ instr,
+ decoder,
+ text,
+ expected
+ );
+ // while we're at it, test that the instruction is as long, and no longer, than its
+ // input
+ assert_eq!(instr.len() as usize, data.len(), "instruction length is incorrect, wanted instruction {}", expected);
+ },
+ Err(e) => {
+ assert!(false, "decode error ({}) for {} under decoder {}:\n expected: {}\n", e, hex, decoder, expected);
+ }
+ }
+}
+
+#[test]
+fn test_mmx() {
+ test_display(&[0x4f, 0x0f, 0x7e, 0xcf], "movd r15, mm1");
+ test_display(&[0x41, 0x0f, 0x7e, 0xcf], "movd r15d, mm1");
+ test_display(&[0x4f, 0x0f, 0x7f, 0xcf], "movq mm7, mm1");
+ test_display(&[0x4f, 0x0f, 0x7f, 0x0f], "movq [r15], mm1");
+ test_display(&[0x0f, 0xc4, 0xc0, 0x14], "pinsrw mm0, eax, 0x14");
+ test_display(&[0x4f, 0x0f, 0xc4, 0xc0, 0x14], "pinsrw mm0, r8d, 0x14");
+ test_display(&[0x4f, 0x0f, 0xc4, 0x00, 0x14], "pinsrw mm0, [r8], 0x14");
+ test_display(&[0x4f, 0x0f, 0xd1, 0xcf], "psrlw mm1, mm7");
+ test_display(&[0x4f, 0x0f, 0xd1, 0x00], "psrlw mm0, [r8]");
+ test_invalid(&[0x4f, 0x0f, 0xd7, 0x00]);
+ test_display(&[0x4f, 0x0f, 0xd7, 0xcf], "pmovmskb r9d, mm7");
+}
+
+#[test]
+fn test_cvt() {
+ test_display(&[0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm7");
+ test_display(&[0x48, 0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm7");
+ test_display(&[0x4f, 0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm15");
+ test_display(&[0x4f, 0x0f, 0x2a, 0xcf], "cvtpi2ps xmm9, mm7");
+ test_display(&[0x4f, 0x0f, 0x2a, 0x00], "cvtpi2ps xmm8, [r8]");
+ test_display(&[0x4f, 0x66, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm1, mm7");
+ test_display(&[0x66, 0x4f, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm9, mm7");
+ test_display(&[0x4f, 0xf3, 0x0f, 0x2a, 0xcf], "cvtsi2ss xmm1, edi");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0xcf], "cvtsi2ss xmm9, r15");
+ test_display(&[0x4f, 0xf2, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm1, edi");
+ test_display(&[0xf2, 0x4f, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm9, r15");
+ test_display(&[0x4f, 0xf2, 0x0f, 0x2a, 0x00], "cvtsi2sd xmm0, [rax]");
+ test_display(&[0xf2, 0x4f, 0x0f, 0x2a, 0x00], "cvtsi2sd xmm8, [r8]");
+ test_display(&[0x4f, 0xf3, 0x0f, 0x2a, 0x00], "cvtsi2ss xmm0, [rax]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0x00], "cvtsi2ss xmm8, [r8]");
+ test_display(&[0x4f, 0x66, 0x0f, 0x2a, 0x00], "cvtpi2pd xmm0, [rax]");
+ test_display(&[0x66, 0x4f, 0x0f, 0x2a, 0x00], "cvtpi2pd xmm8, [r8]");
+}
+
+#[test]
+fn test_aesni() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_aesni(), bytes, text);
+ test_display_under(&InstDecoder::default(), bytes, text);
+ test_invalid_under(&InstDecoder::minimal(), bytes);
+ }
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdb, 0xcf], "aesimc xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdc, 0x0f], "aesenc xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdc, 0xcf], "aesenc xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdd, 0x0f], "aesenclast xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdd, 0xcf], "aesenclast xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xde, 0x0f], "aesdec xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xde, 0xcf], "aesdec xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdf, 0x0f], "aesdeclast xmm1, [rdi]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdf, 0xcf], "aesdeclast xmm9, xmm15");
+
+ test_instr(&[0x66, 0x0f, 0x3a, 0xdf, 0x0f, 0xaa], "aeskeygenassist xmm1, [rdi], 0xaa");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x3a, 0xdf, 0xcf, 0xaa], "aeskeygenassist xmm9, xmm15, 0xaa");
+}
+
+#[test]
+fn test_sse2() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ // sse and sse2 are part of amd64, so x86_64, meaning even the minimal decoder must support
+ // them.
+ test_display_under(&InstDecoder::minimal(), bytes, text);
+ }
+
+ test_instr(&[0xf2, 0x0f, 0x10, 0x0c, 0xc7], "movsd xmm1, [rdi + rax * 8]");
+ test_instr(&[0xf2, 0x0f, 0x11, 0x0c, 0xc7], "movsd [rdi + rax * 8], xmm1");
+ test_instr(&[0x66, 0x0f, 0x11, 0x0c, 0xc7], "movupd [rdi + rax * 8], xmm1");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x12, 0xc3], "movhlps xmm8, xmm11"); // reg-reg form is movhlps
+ test_instr(&[0x66, 0x4f, 0x0f, 0x12, 0x03], "movlpd xmm8, [r11]"); // reg-mem is movlpd
+ test_instr(&[0x66, 0x4f, 0x0f, 0x13, 0x03], "movlpd [r11], xmm8");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x13, 0xc3]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x14, 0x03], "unpcklpd xmm8, [r11]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x14, 0xc3], "unpcklpd xmm8, xmm11");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x15, 0x03], "unpckhpd xmm8, [r11]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x15, 0xc3], "unpckhpd xmm8, xmm11");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x16, 0x03], "movhpd xmm8, [r11]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x16, 0xc3], "movlhps xmm8, xmm11");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x17, 0x03], "movhpd [r11], xmm8");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x17, 0xc3]);
+
+ test_instr(&[0x66, 0x4f, 0x0f, 0x28, 0xd0], "movapd xmm10, xmm8");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8]");
+
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm9, mm7");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2a, 0x0f], "cvtpi2pd xmm9, [r15]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm9, r15");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x2a, 0x0f], "cvtsi2sd xmm9, [r15]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2b, 0x0f], "movntpd [r15], xmm9");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2c, 0xcf], "cvttpd2pi mm1, xmm15");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2c, 0x0f], "cvttpd2pi mm1, [r15]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x2c, 0xcf], "cvttsd2si xmm9, xmm15");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x2c, 0x0f], "cvttsd2si xmm9, [r15]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2d, 0xcf], "cvtpd2pi mm1, xmm15");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2d, 0x0f], "cvtpd2pi mm1, [r15]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x2d, 0xcf], "cvtsd2si xmm9, xmm15");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x2d, 0x0f], "cvtsd2si xmm9, [r15]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2e, 0xcf], "ucomisd xmm9, xmm15");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2e, 0x0f], "ucomisd xmm9, [r15]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2f, 0xcf], "comisd xmm9, xmm15");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x2f, 0x0f], "comisd xmm9, [r15]");
+
+ /*
+ * .... 660f38
+ * .... 660f7f
+ */
+
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x50, 0x01]);
+ 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_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]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x57, 0x01], "xorpd xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x58, 0x01], "addpd xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x58, 0x01], "addsd xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x59, 0x01], "mulpd xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x59, 0x01], "mulsd xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x5a, 0x01], "cvtpd2ps xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x5a, 0x01], "cvtsd2ss xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x5b, 0x01], "cvtps2dq xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x5c, 0x01], "subpd xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x5c, 0x01], "subsd xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x5d, 0x01], "minpd xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x5d, 0x01], "minsd xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x5e, 0x01], "divpd xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x5e, 0x01], "divsd xmm8, [r9]");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x5f, 0x01], "maxpd xmm8, [r9]");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0x5f, 0x01], "maxsd xmm8, [r9]");
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x60, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpcklbw xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x61, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpcklwd xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x62, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckldq xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x63, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "packsswb xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x64, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "pcmpgtb xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x65, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "pcmpgtw xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x66, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "pcmpgtd xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x67, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "packuswb xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x68, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhbw xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x69, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhwd xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x6a, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhdq xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x6b, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "packssdw xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x6c, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpcklqdq xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x6d, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhqdq xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ // TODO: this needs to be clear that the operand is `dword`
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x6e, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movq xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x6f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqa xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+
+ test_instr(&[0x66, 0x48, 0x0f, 0x6e, 0xc0], "movq xmm0, rax");
+ test_instr(&[0x66, 0x0f, 0x70, 0xc0, 0x4e], "pshufd xmm0, xmm0, 0x4e");
+ test_instr(&[0xf2, 0x0f, 0x70, 0xc0, 0x4e], "pshuflw xmm0, xmm0, 0x4e");
+ test_instr(&[0xf3, 0x0f, 0x70, 0xc0, 0x4e], "pshufhw xmm0, xmm0, 0x4e");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x71, 0x10, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x71, 0xd0, 0x8f], "psrlw xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x71, 0x20, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x71, 0xe0, 0x8f], "psraw xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x71, 0x30, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x71, 0xf0, 0x8f], "psllw xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x72, 0x10, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x72, 0xd0, 0x8f], "psrld xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x72, 0x20, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x72, 0xe0, 0x8f], "psrad xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x72, 0x30, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x72, 0xf0, 0x8f], "pslld xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x10, 0x8f]);
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x18, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xd0, 0x8f], "psrlq xmm0, 0x8f");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xd8, 0x8f], "psrldq xmm0, 0x8f");
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x30, 0x8f]);
+ test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x38, 0x8f]);
+ test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xf0, 0x8f], "psllq xmm0, 0x8f");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xf8, 0x8f], "pslldq xmm0, 0x8f");
+ test_instr(&[0x66, 0x0f, 0x7e, 0xc1], "movd ecx, xmm0");
+ test_instr(&[0x66, 0x48, 0x0f, 0x7e, 0xc1], "movq rcx, xmm0");
+ test_instr(&[0x66, 0x48, 0x0f, 0x7e, 0x01], "movd [rcx], xmm0");
+ test_instr(&[0x66, 0x4f, 0x0f, 0x7e, 0xc1], "movq r9, xmm8");
+ test_instr(
+ &[0x66, 0x4f, 0x0f, 0x7f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqa [r12 + r11 * 4 - 0x334455cc], xmm11"
+ );
+
+ test_instr(&[0x66, 0x0f, 0xc2, 0xc3, 0x08], "cmppd xmm0, xmm3, 0x8");
+ test_instr(&[0x66, 0x4f, 0x0f, 0xc2, 0xc3, 0x08], "cmppd xmm8, xmm11, 0x8");
+ test_instr(&[0x66, 0x4f, 0x0f, 0xc2, 0x03, 0x08], "cmppd xmm8, [r11], 0x8");
+ test_instr(&[0xf2, 0x0f, 0xc2, 0xc3, 0x08], "cmpsd xmm0, xmm3, 0x8");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0xc2, 0xc3, 0x08], "cmpsd xmm8, xmm11, 0x8");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0xc2, 0x03, 0x08], "cmpsd xmm8, [r11], 0x8");
+
+ test_instr(&[0x66, 0x0f, 0xc4, 0xc3, 0x08], "pinsrw xmm0, ebx, 0x8");
+ test_instr(&[0x66, 0x4f, 0x0f, 0xc4, 0xc3, 0x08], "pinsrw xmm8, r11d, 0x8");
+
+ test_instr(&[0x66, 0x0f, 0xc4, 0x03, 0x08], "pinsrw xmm0, [rbx], 0x8");
+ test_instr(&[0x66, 0x4f, 0x0f, 0xc4, 0x03, 0x08], "pinsrw xmm8, [r11], 0x8");
+
+// test_instr(&[0x66, 0x0f, 0xc5, 0xc3, 0x08], "pextrw eax, xmm3, 0x8");
+// test_instr(&[0x66, 0x4f, 0x0f, 0xc5, 0xc3, 0x08], "pextrw r8d, xmm11, 0x8");
+// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x03, 0x08]);
+// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x40, 0x08]);
+// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x80, 0x08]);
+
+ test_instr(&[0x66, 0x4f, 0x0f, 0xc6, 0x03, 0x08], "shufpd xmm8, [r11], 0x8");
+ test_instr(&[0x66, 0x0f, 0xc6, 0x03, 0x08], "shufpd xmm0, [rbx], 0x8");
+ test_instr(&[0x66, 0x0f, 0xc6, 0xc3, 0x08], "shufpd xmm0, xmm3, 0x8");
+ test_instr(&[0x66, 0x0f, 0xd1, 0xc1], "psrlw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd1, 0x01], "psrlw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xd2, 0xc1], "psrld xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd2, 0x01], "psrld xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xd3, 0xc1], "psrlq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd3, 0x01], "psrlq xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xd4, 0xc1], "paddq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd4, 0x01], "paddq xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xd5, 0xc1], "pmullw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd5, 0x01], "pmullw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xd6, 0xc1], "movq xmm1, xmm0");
+ test_instr(&[0x66, 0x0f, 0xd6, 0x01], "movq [rcx], xmm0");
+ test_invalid(&[0xf3, 0x4f, 0x0f, 0xd6, 0x03]);
+ test_instr(&[0xf3, 0x4f, 0x0f, 0xd6, 0xc3], "movq2dq xmm8, mm3");
+ test_instr(&[0xf2, 0x4f, 0x0f, 0xd6, 0xc3], "movdq2q mm0, xmm11");
+ test_instr(&[0x66, 0x0f, 0xd7, 0xc1], "pmovmskb eax, xmm1");
+ test_instr(&[0x66, 0x4f, 0x0f, 0xd7, 0xc1], "pmovmskb r8d, xmm9");
+ test_invalid(&[0x66, 0x0f, 0xd7, 0x01]);
+ test_instr(&[0x66, 0x0f, 0xd8, 0xc1], "psubusb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd8, 0x01], "psubusb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xd9, 0xc1], "psubusw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd9, 0x01], "psubusw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xda, 0xc1], "pminub xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xda, 0x01], "pminub xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xdb, 0xc1], "pand xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdb, 0x01], "pand xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xdc, 0xc1], "paddusb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdc, 0x01], "paddusb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xdd, 0xc1], "paddusw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdd, 0x01], "paddusw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xde, 0xc1], "pmaxub xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xde, 0x01], "pmaxub xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xdf, 0xc1], "pandn xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdf, 0x01], "pandn xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe0, 0xc1], "pavgb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe0, 0x01], "pavgb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe1, 0xc1], "psraw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe1, 0x01], "psraw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe2, 0xc1], "psrad xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe2, 0x01], "psrad xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe3, 0xc1], "pavgw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe3, 0x01], "pavgw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe4, 0xc1], "pmulhuw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe4, 0x01], "pmulhuw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe5, 0xc1], "pmulhw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe5, 0x01], "pmulhw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe6, 0xc1], "cvttpd2dq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe6, 0x01], "cvttpd2dq xmm0, [rcx]");
+ test_invalid(&[0x66, 0x0f, 0xe7, 0xc1]);
+ test_instr(&[0x66, 0x0f, 0xe7, 0x01], "movntdq [rcx], xmm0");
+ test_instr(&[0x66, 0x0f, 0xe8, 0xc1], "psubsb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe8, 0x01], "psubsb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xe9, 0xc1], "psubsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe9, 0x01], "psubsw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xea, 0xc1], "pminsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xea, 0x01], "pminsw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xc3], "por xmm0, xmm3");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xc4], "por xmm0, xmm4");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xd3], "por xmm2, xmm3");
+ test_instr(&[0x66, 0x0f, 0xeb, 0x12], "por xmm2, [rdx]");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xc1], "por xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xeb, 0x01], "por xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xec, 0xc1], "paddsb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xec, 0x01], "paddsb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xed, 0xc1], "paddsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xed, 0x01], "paddsw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xee, 0xc1], "pmaxsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xee, 0x01], "pmaxsw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xef, 0xc1], "pxor xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xef, 0x01], "pxor xmm0, [rcx]");
+ test_invalid(&[0x66, 0x0f, 0xf0, 0xc1]);
+ test_invalid(&[0x66, 0x0f, 0xf0, 0x01]);
+ test_instr(&[0x66, 0x0f, 0xf1, 0xc1], "psllw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf1, 0x01], "psllw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf2, 0xc1], "pslld xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf2, 0x01], "pslld xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf3, 0xc1], "psllq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf3, 0x01], "psllq xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf4, 0xc1], "pmuludq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf4, 0x01], "pmuludq xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf5, 0xc1], "pmaddwd xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf5, 0x01], "pmaddwd xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf6, 0xc1], "psadbw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf6, 0x01], "psadbw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf7, 0xc1], "maskmovdqu xmm0, xmm1");
+ test_invalid(&[0x66, 0x0f, 0xf7, 0x01]);
+ test_instr(&[0x66, 0x0f, 0xf8, 0xc1], "psubb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf8, 0x01], "psubb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xf9, 0xc1], "psubw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf9, 0x01], "psubw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xfa, 0xc1], "psubd xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfa, 0x01], "psubd xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xfb, 0xc1], "psubq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfb, 0x01], "psubq xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xfc, 0xc1], "paddb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfc, 0x01], "paddb xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xfd, 0xc1], "paddw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfd, 0x01], "paddw xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xfe, 0xc1], "paddd xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfe, 0x01], "paddd xmm0, [rcx]");
+ test_instr(&[0x66, 0x0f, 0xff, 0xc1], "paddq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xff, 0x01], "paddq xmm0, [rcx]");
+
+ test_instr(&[0x66, 0x0f, 0x74, 0xc1], "pcmpeqb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0x74, 0x12], "pcmpeqb xmm2, [rdx]");
+ test_instr(&[0x66, 0x0f, 0xf8, 0xc8], "psubb xmm1, xmm0");
+ test_instr(&[0x66, 0x0f, 0xf8, 0xd0], "psubb xmm2, xmm0");
+ test_instr(&[0x66, 0x0f, 0xf8, 0x12], "psubb xmm2, [rdx]");
+}
+
+#[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"
+ test_display(&[0x0f, 0x01, 0x38], "invlpg [rax]");
+ test_display(&[0x0f, 0x01, 0x3f], "invlpg [rdi]");
+ test_display(&[0x0f, 0x01, 0x40, 0xff], "sgdt [rax - 0x1]");
+ test_display(&[0x0f, 0x01, 0x41, 0xff], "sgdt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x49, 0xff], "sidt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x51, 0xff], "lgdt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x59, 0xff], "lidt [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x61, 0xff], "smsw [rcx - 0x1]");
+ test_display(&[0x0f, 0x01, 0xc0], "enclv");
+ test_display(&[0x0f, 0x01, 0xc1], "vmcall");
+ test_display(&[0x0f, 0x01, 0xc2], "vmlaunch");
+ test_display(&[0x0f, 0x01, 0xc3], "vmresume");
+ test_display(&[0x0f, 0x01, 0xc4], "vmxoff");
+ test_invalid(&[0x0f, 0x01, 0xc5]);
+ test_invalid(&[0x0f, 0x01, 0xc6]);
+ test_invalid(&[0x0f, 0x01, 0xc7]);
+ test_display(&[0x0f, 0x01, 0xc8], "monitor");
+ test_display(&[0x0f, 0x01, 0xc9], "mwait");
+ test_display(&[0x0f, 0x01, 0xca], "clac");
+ test_display(&[0x0f, 0x01, 0xcb], "stac");
+ test_display(&[0x0f, 0x01, 0xcf], "encls");
+ test_display(&[0x0f, 0x01, 0xd0], "xgetbv");
+ test_display(&[0x0f, 0x01, 0xd1], "xsetbv");
+ test_invalid(&[0x0f, 0x01, 0xd2]);
+ test_invalid(&[0x0f, 0x01, 0xd3]);
+ test_display(&[0x0f, 0x01, 0xd4], "vmfunc");
+ test_display(&[0x0f, 0x01, 0xd5], "xend");
+ test_display(&[0x0f, 0x01, 0xd6], "xtest");
+ test_display(&[0x0f, 0x01, 0xd7], "enclu");
+ test_invalid(&[0x0f, 0x01, 0xd8]);
+ test_invalid(&[0x0f, 0x01, 0xd9]);
+ test_invalid(&[0x0f, 0x01, 0xda]);
+ test_invalid(&[0x0f, 0x01, 0xdb]);
+ test_invalid(&[0x0f, 0x01, 0xdc]);
+ test_invalid(&[0x0f, 0x01, 0xdd]);
+ test_invalid(&[0x0f, 0x01, 0xde]);
+ test_invalid(&[0x0f, 0x01, 0xdf]);
+ test_display(&[0x0f, 0x01, 0xee], "rdpkru");
+ test_display(&[0x0f, 0x01, 0xef], "wrpkru");
+ test_display(&[0x0f, 0x01, 0xf8], "swapgs");
+ test_display(&[0x0f, 0x01, 0xf9], "rdtscp");
+}
+
+#[test]
+fn test_0fae() {
+ let intel = InstDecoder::minimal().with_intel_quirks();
+ let amd = InstDecoder::minimal().with_amd_quirks();
+ let default = InstDecoder::default();
+ let minimal = InstDecoder::minimal();
+ // drawn heavily from "Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group
+ // Number"
+ test_display(&[0x0f, 0xae, 0x04, 0x4f], "fxsave [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x0c, 0x4f], "fxrstor [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x14, 0x4f], "ldmxcsr [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x1c, 0x4f], "stmxcsr [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x24, 0x4f], "xsave [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x2c, 0x4f], "xrstor [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x34, 0x4f], "xsaveopt [rdi + rcx * 2]");
+ test_display(&[0x0f, 0xae, 0x3c, 0x4f], "clflush [rdi + rcx * 2]");
+
+ for (modrm, text) in &[(0xe8u8, "lfence"), (0xf0u8, "mfence"), (0xf8u8, "sfence")] {
+ test_display_under(&intel, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&amd, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&default, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&minimal, &[0x0f, 0xae, *modrm], text);
+ // it turns out intel and amd accept m != 0 for {l,m,s}fence:
+ // from intel:
+ // ```
+ // Specification of the instruction's opcode above indicates a ModR/M byte of F0. For this
+ // instruction, the processor ignores the r/m field of the ModR/M byte. Thus, MFENCE is encoded
+ // by any opcode of the form 0F AE Fx, where x is in the range 0-7.
+ // ```
+ // whereas amd does not discuss the r/m field at all. at least as of zen, amd also accepts
+ // these encodings.
+ for m in 1u8..8u8 {
+ test_display_under(&intel, &[0x0f, 0xae, modrm | m], text);
+ test_display_under(&amd, &[0x0f, 0xae, modrm | m], text);
+ test_display_under(&default, &[0x0f, 0xae, modrm | m], text);
+ test_invalid_under(&minimal, &[0x0f, 0xae, modrm | m]);
+ }
+ }
+}
+
+#[test]
+fn test_system() {
+ test_display(&[0x66, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8]");
+ test_display(&[0x67, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8d]");
+ test_display(&[0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8]");
+ test_display(&[0x45, 0x0f, 0x22, 0xc8], "mov cr9, r8");
+ test_display(&[0x45, 0x0f, 0x20, 0xc8], "mov r8, cr9");
+ test_display(&[0x40, 0x0f, 0x22, 0xc8], "mov cr1, rax");
+ test_display(&[0x0f, 0x22, 0xc8], "mov cr1, rax");
+ test_display(&[0x44, 0x0f, 0x22, 0xcf], "mov cr9, rdi");
+ test_display(&[0x0f, 0x22, 0xcf], "mov cr1, rdi");
+ test_display(&[0x0f, 0x20, 0xc8], "mov rax, cr1");
+
+ test_display(&[0x45, 0x0f, 0x23, 0xc8], "mov dr9, r8");
+ test_display(&[0x45, 0x0f, 0x21, 0xc8], "mov r8, dr9");
+ test_display(&[0x40, 0x0f, 0x23, 0xc8], "mov dr1, rax");
+ test_display(&[0x0f, 0x23, 0xc8], "mov dr1, rax");
+ test_display(&[0x0f, 0x21, 0xc8], "mov rax, dr1");
+}
+
+#[test]
+fn test_arithmetic() {
+ test_display(&[0x81, 0xec, 0x10, 0x03, 0x00, 0x00], "sub esp, 0x310");
+ test_display(&[0x0f, 0xaf, 0xc2], "imul eax, edx");
+ test_display(&[0x4b, 0x69, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65], "imul rax, [r11 + 0x6f], 0x656c706d");
+ test_display(&[0x66, 0x0f, 0xaf, 0xd1], "imul dx, cx");
+ test_display(&[0x4b, 0x6b, 0x43, 0x6f, 0x6d], "imul al, [r11 + 0x6f], 0x6d");
+ test_display(&[0x4f, 0x4e, 0x00, 0xcc], "add spl, r9b");
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn test_E_decode() {
+ test_display(&[0xff, 0x75, 0xb8], "push [rbp - 0x48]");
+ test_display(&[0xff, 0x75, 0x08], "push [rbp + 0x8]");
+}
+
+#[test]
+fn test_sse() {
+ test_display(&[0xf3, 0x0f, 0x10, 0x0c, 0xc7], "movss xmm1, [rdi + rax * 8]");
+ test_display(&[0xf3, 0x0f, 0x11, 0x0c, 0xc7], "movss [rdi + rax * 8], xmm1");
+ test_display(&[0x4f, 0x0f, 0x28, 0x00], "movaps xmm8, [r8]");
+ test_display(&[0x4f, 0x0f, 0x29, 0x00], "movaps [r8], xmm8");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0xc1], "cvtsi2ss xmm8, r9");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0x01], "cvtsi2ss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x2b, 0x00], "movntps [r8], xmm8");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2c, 0xc1], "cvttss2si r8, xmm9");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2c, 0x01], "cvttss2si r8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2d, 0xc1], "cvtss2si r8, xmm9");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x2d, 0x01], "cvtss2si r8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x2e, 0x00], "ucomiss xmm8, [r8]");
+ test_display(&[0x4f, 0x0f, 0x2f, 0x00], "comiss xmm8, [r8]");
+ test_display(&[0x0f, 0x28, 0xd0], "movaps xmm2, xmm0");
+ test_display(&[0x66, 0x0f, 0x28, 0xd0], "movapd xmm2, xmm0");
+ test_display(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [rax]");
+ test_display(&[0x4f, 0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [rax]");
+ test_display(&[0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8]");
+ test_display(&[0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8]");
+ test_display(&[0x67, 0x4f, 0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
+ test_display(&[0x67, 0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8d]");
+ test_display(&[0x66, 0x0f, 0x29, 0x00], "movapd [rax], xmm0");
+ test_invalid(&[0x4f, 0x0f, 0x50, 0x00]);
+ test_display(&[0x4f, 0x0f, 0x50, 0xc1], "movmskps r8d, xmm9");
+ test_display(&[0x4f, 0x0f, 0x51, 0x01], "sqrtps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x51, 0x01], "sqrtss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x52, 0x01], "rsqrtps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x52, 0x01], "rsqrtss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x53, 0x01], "rcpps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x53, 0x01], "rcpss xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x53, 0xc1], "rcpss xmm8, xmm9");
+ test_display(&[0x4f, 0x0f, 0x54, 0x01], "andps xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x55, 0x01], "andnps xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x56, 0x01], "orps xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x57, 0x01], "xorps xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x58, 0x01], "addps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x58, 0x01], "addss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x59, 0x01], "mulps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x59, 0x01], "mulss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x5a, 0x01], "cvtps2pd xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x5a, 0x01], "cvtss2sd xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x5b, 0x01], "cvtdq2ps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x5b, 0x01], "cvttps2dq xmm8, [r9]");
+ test_display(&[0x67, 0x4f, 0x0f, 0x5b, 0x01], "cvtdq2ps xmm8, [r9d]");
+ test_display(&[0x4f, 0x0f, 0x5c, 0x01], "subps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x5c, 0x01], "subss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x5d, 0x01], "minps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x5d, 0x01], "minss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x5e, 0x01], "divps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x5e, 0x01], "divss xmm8, [r9]");
+ test_display(&[0x4f, 0x0f, 0x5f, 0x01], "maxps xmm8, [r9]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x5f, 0x01], "maxss xmm8, [r9]");
+
+ test_display(&[0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [rax], 0x7f");
+ test_display(&[0x4f, 0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [r8], 0x7f");
+
+ test_display(&[0x66, 0x0f, 0xef, 0xc0], "pxor xmm0, xmm0");
+ test_display(&[0x66, 0x4f, 0x0f, 0xef, 0xc0], "pxor xmm8, xmm8");
+ test_display(&[0xf2, 0x0f, 0x10, 0x0c, 0xc6], "movsd xmm1, [rsi + rax * 8]");
+ test_display(&[0xf3, 0x0f, 0x10, 0x04, 0x86], "movss xmm0, [rsi + rax * 4]");
+ test_display(&[0xf2, 0x0f, 0x59, 0xc8], "mulsd xmm1, xmm0");
+ test_display(&[0xf3, 0x0f, 0x59, 0xc8], "mulss xmm1, xmm0");
+ test_display(&[0xf2, 0x4f, 0x0f, 0x59, 0xc8], "mulsd xmm9, xmm8");
+
+ test_display(
+ &[0xf3, 0x4f, 0x0f, 0x6f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqu xmm11, [r12 + r11 * 4 - 0x334455cc]"
+ );
+ test_display(&[0xf3, 0x0f, 0x70, 0xc0, 0x4e], "pshufhw xmm0, xmm0, 0x4e");
+ test_display(&[0xf3, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
+ test_display(&[0xf3, 0x4f, 0x0f, 0x7e, 0xc1], "movd r9, mm0"); // use of rex.w demotes to movd r/mm
+ test_display(&[0xf3, 0x40, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
+ test_display(&[0xf3, 0x41, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm9");
+ test_display(&[0xf3, 0x42, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
+ test_display(&[0xf3, 0x44, 0x0f, 0x7e, 0xc1], "movq xmm8, xmm1");
+ test_display(&[0xf3, 0x48, 0x0f, 0x7e, 0xc1], "movd rcx, mm0");
+ test_display(
+ &[0xf3, 0x4f, 0x0f, 0x7f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqu [r12 + r11 * 4 - 0x334455cc], xmm11"
+ );
+
+ test_display(&[0xf3, 0x0f, 0xc2, 0xc3, 0x08], "cmpss xmm0, xmm3, 0x8");
+ test_display(&[0xf3, 0x4f, 0x0f, 0xc2, 0xc3, 0x08], "cmpss xmm8, xmm11, 0x8");
+ test_display(&[0xf3, 0x4f, 0x0f, 0xc2, 0x03, 0x08], "cmpss xmm8, [r11], 0x8");
+}
+
+// SETLE, SETNG, ...
+
+#[test]
+fn test_mov() {
+ // test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00, 0x12, 0x34, 0x12, 0x34], "mov eax, [0x3412341200c46293]");
+ // RCT.exe 32bit version, TODO: FIX
+ test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00], "mov eax, [0xc46293]");
+ test_display(&[0xba, 0x01, 0x00, 0x00, 0x00], "mov edx, 0x1");
+ test_display(&[0x48, 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00], "mov [rsp], 0x0");
+ test_display(&[0x48, 0x89, 0x44, 0x24, 0x08], "mov [rsp + 0x8], rax");
+ test_display(&[0x48, 0x89, 0x43, 0x18], "mov [rbx + 0x18], rax");
+ test_display(&[0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00], "mov [rbx + 0x10], 0x0");
+ test_display(&[0x49, 0x89, 0x4e, 0x08], "mov [r14 + 0x8], rcx");
+ test_display(&[0x48, 0x8b, 0x32], "mov rsi, [rdx]");
+ test_display(&[0x4d, 0x8b, 0x4c, 0x10, 0xf8], "mov r9, [r8 + rdx * 1 - 0x8]");
+ test_display(&[0x49, 0x89, 0x46, 0x10], "mov [r14 + 0x10], rax");
+ test_display(&[0x4d, 0x0f, 0x43, 0xec], "cmovnb r13, r12");
+ test_display(&[0x0f, 0xb6, 0x06], "movzx eax, byte [rsi]");
+ test_display(&[0x0f, 0xb7, 0x06], "movzx eax, word [rsi]");
+ test_display(&[0x89, 0x55, 0x94], "mov [rbp - 0x6c], edx");
+ test_display(&[0x65, 0x4c, 0x89, 0x04, 0x25, 0xa8, 0x01, 0x00, 0x00], "mov gs:[0x1a8], r8");
+ test_display(&[0x0f, 0xbe, 0x83, 0xb4, 0x00, 0x00, 0x00], "movsx eax, byte [rbx + 0xb4]");
+ test_display(&[0x46, 0x63, 0xc1], "movsxd r8, ecx");
+ test_display(&[0x48, 0x63, 0x04, 0xba], "movsxd rax, [rdx + rdi * 4]");
+ test_display(&[0xf3, 0x0f, 0x6f, 0x07], "movdqu xmm0, [rdi]");
+ test_display(&[0xf3, 0x0f, 0x7f, 0x45, 0x00], "movdqu [rbp], xmm0");
+}
+
+#[test]
+fn test_stack() {
+ test_display(&[0x66, 0x41, 0x50], "push r8w");
+}
+
+#[test]
+fn test_prefixes() {
+ test_display(&[0x66, 0x41, 0x31, 0xc0], "xor r8w, ax");
+ test_display(&[0x66, 0x41, 0x32, 0xc0], "xor al, r8b");
+ test_display(&[0x40, 0x32, 0xc5], "xor al, bpl");
+
+ // test that WAIT doesn't blow up, at least...
+ assert_eq!(InstDecoder::default().decode([0x9b, 0xf8].iter().cloned()).err(), Some(DecodeError::IncompleteDecoder));
+}
+
+#[test]
+fn test_control_flow() {
+ test_display(&[0x73, 0x31], "jnb 0x31");
+ test_display(&[0x72, 0x5a], "jb 0x5a");
+ test_display(&[0x0f, 0x86, 0x8b, 0x01, 0x00, 0x00], "jna 0x18b");
+ test_display(&[0x74, 0x47], "jz 0x47");
+ test_display(&[0xff, 0x15, 0x7e, 0x72, 0x24, 0x00], "call [rip + 0x24727e]");
+ test_display(&[0xff, 0x24, 0xcd, 0x70, 0xa0, 0xbc, 0x01], "jmp [rcx * 8 + 0x1bca070]");
+ test_display(&[0xff, 0xe0], "jmp rax");
+ test_display(&[0x66, 0xff, 0xe0], "jmp rax");
+ test_display(&[0x67, 0xff, 0xe0], "jmp rax");
+ test_invalid(&[0xff, 0xd8]);
+ test_display(&[0xff, 0x18], "callf [rax]");
+ test_display(&[0xc3], "ret");
+}
+
+#[test]
+fn test_test_cmp() {
+ test_display(&[0xf6, 0x05, 0x2c, 0x9b, 0xff, 0xff, 0x01], "test [rip - 0x64d4], 0x1");
+ test_display(&[0x48, 0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp rax, -0xfff");
+ test_display(&[0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp eax, -0xfff");
+ test_display(&[0x48, 0x83, 0xf8, 0xff], "cmp rax, -0x1");
+ test_display(&[0x48, 0x39, 0xc6], "cmp rsi, rax");
+}
+
+#[test]
+fn test_push_pop() {
+ test_display(&[0x5b], "pop rbx");
+ test_display(&[0x41, 0x5e], "pop r14");
+ test_display(&[0x68, 0x7f, 0x63, 0xc4, 0x00], "push 0xc4637f");
+}
+
+#[test]
+fn test_bmi1() {
+ let bmi1 = InstDecoder::minimal().with_bmi1();
+ let no_bmi1 = InstDecoder::minimal();
+ test_display_under(&bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "tzcnt edx, r11d");
+ test_display_under(&no_bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
+
+ test_display_under(&bmi1, &[0xf3, 0x0f, 0xb8, 0xc1], "popcnt eax, ecx");
+ test_display_under(&bmi1, &[0xf3, 0x4f, 0x0f, 0xb8, 0xc1], "popcnt r8, r9");
+}
+
+#[test]
+fn test_bitwise() {
+ test_display_under(&InstDecoder::minimal(), &[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
+ test_display(&[0x48, 0x0f, 0xa3, 0xd0], "bt rax, rdx");
+ test_display(&[0x48, 0x0f, 0xab, 0xd0], "bts rax, rdx");
+}
+
+#[test]
+fn test_misc() {
+ // TODO
+// test_display(&[0xf2, 0x0f, 0x38, 0xf0, 0xc1], "crc32 eax, cl");
+// test_display(&[0xf2, 0x0f, 0x38, 0xf1, 0xc1], "crc32 eax, ecx");
+ test_display(&[0xfe, 0x00], "inc [rax]"); // TODO: inc byte [rax]
+ test_display(&[0xfe, 0x08], "dec [rax]"); // TODO: dec byte [rax]
+ test_display(&[0xff, 0x00], "inc [rax]"); // TODO: inc dword [rax]
+ test_display(&[0x48, 0xff, 0x00], "inc [rax]"); // TODO: inc qword [rax]
+ test_display(&[0xe4, 0x99], "in al, 0x99");
+ test_display(&[0xe5, 0x99], "in eax, 0x99");
+ test_display(&[0x67, 0xe5, 0x99], "in eax, 0x99");
+ test_display(&[0x4f, 0xe5, 0x99], "in eax, 0x99");
+ test_display(&[0xe6, 0x99], "out 0x99, al");
+ test_display(&[0x4f, 0xe7, 0x99], "out 0x99, eax");
+ test_display(&[0xec], "in al, dx");
+ test_display(&[0xed], "in eax, dx");
+ test_display(&[0xee], "out dx, al");
+ test_display(&[0xef], "out dx, eax");
+ test_display(&[0xcd, 0x00], "int 0x0");
+ test_display(&[0xcd, 0xff], "int 0xff");
+ test_display(&[0x9c], "pushf");
+ test_display(&[0x48, 0x98], "cdqe");
+ test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop cs:[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");
+ test_display(&[0x48, 0x8d, 0x53, 0x08], "lea rdx, [rbx + 0x8]");
+ test_display(&[0x31, 0xc9], "xor ecx, ecx");
+ test_display(&[0x48, 0x29, 0xc8], "sub rax, rcx");
+ test_display(&[0x48, 0x03, 0x0b], "add rcx, [rbx]");
+ test_display(&[0x48, 0x8d, 0x0c, 0x12], "lea rcx, [rdx + rdx * 1]");
+ test_display(&[0xf6, 0xc2, 0x18], "test dl, 0x18");
+ test_display(&[0xf3, 0x48, 0xab], "rep stos es:[rdi], rax");
+ test_display(&[0xf3, 0x48, 0xa5], "rep movs es:[rdi], ds:[rsi]");
+ test_display(&[0xf3, 0x45, 0x0f, 0xbc, 0xd7], "tzcnt r10d, r15d");
+
+ // this is actually vmx
+ // test_invalid(&[0x66, 0x0f, 0xc7, 0x03]);
+ test_display(&[0x66, 0x4f, 0x0f, 0xc7, 0x33], "vmclear [r11]");
+ test_display(&[0x66, 0x0f, 0xc7, 0x33], "vmclear [rbx]");
+ test_display(&[0xf3, 0x4f, 0x0f, 0xc7, 0x33], "vmxon [r11]");
+ test_display(&[0xf3, 0x0f, 0xc7, 0x33], "vmxon [rbx]");
+}
+
+#[test]
+#[ignore]
+// TODO also not supported at all
+fn evex() {
+ test_display(&[0x62, 0xf2, 0x7d, 0x48, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa zmm0, [rax + rax*2 + 0x40]");
+ test_display(&[0x62, 0xf2, 0x7d, 0x08, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa xmm0, [rax + rax*2 + 0x10]");
+}
+
+#[test]
+fn test_vex() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_avx(), bytes, text);
+ test_display_under(&InstDecoder::default(), bytes, text);
+ test_invalid_under(&InstDecoder::minimal(), bytes);
+ }
+
+ fn test_instr_invalid(bytes: &[u8]) {
+ test_invalid_under(&InstDecoder::minimal().with_avx(), bytes);
+ test_invalid_under(&InstDecoder::default(), bytes);
+ }
+
+ test_instr(&[0xc5, 0xf8, 0x10, 0x00], "vmovups xmm0, [rax]");
+ test_instr(&[0xc5, 0xf8, 0x10, 0x01], "vmovups xmm0, [rcx]");
+ test_instr(&[0xc5, 0x78, 0x10, 0x0f], "vmovups xmm9, [rdi]");
+ test_instr(&[0xc5, 0xf8, 0x10, 0xcf], "vmovups xmm1, xmm7");
+ test_instr(&[0xc5, 0xf9, 0x10, 0x0f], "vmovupd xmm1, [rdi]");
+ test_instr(&[0xc5, 0xfa, 0x7e, 0x10], "vmovq xmm2, [rax]");
+ test_instr(&[0xc5, 0xfc, 0x10, 0x0f], "vmovups ymm1, [rdi]");
+ test_instr(&[0xc5, 0xfd, 0x10, 0x0f], "vmovupd ymm1, [rdi]");
+ test_instr(&[0xc5, 0xfe, 0x10, 0x0f], "vmovss xmm1, [rdi]");
+ test_instr(&[0xc5, 0xff, 0x10, 0xcf], "vmovsd xmm1, xmm0, xmm7");
+ test_instr(&[0xc5, 0xff, 0x10, 0x01], "vmovsd xmm0, [rcx]");
+ test_instr(&[0xc5, 0xf9, 0x6e, 0xc6], "vmovd xmm0, esi");
+ test_instr(&[0xc5, 0xf9, 0x6e, 0x13], "vmovd xmm2, [rbx]");
+ test_instr(&[0xc5, 0xf9, 0x7e, 0xc6], "vmovd esi, xmm0");
+ test_instr(&[0xc5, 0xf9, 0x7e, 0x13], "vmovd [rbx], xmm2");
+ test_instr_invalid(&[0x4f, 0xc5, 0xf8, 0x10, 0x00]);
+ test_instr_invalid(&[0xf0, 0xc5, 0xf8, 0x10, 0x00]);
+ test_instr(&[0xc4, 0x02, 0x71, 0x00, 0x0f], "vpshufb xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x00, 0x0f], "vpshufb ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x00, 0xcd], "vpshufb xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x00, 0xcd], "vpshufb ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x01, 0x0f], "vphaddw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x01, 0x0f], "vphaddw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x01, 0xcd], "vphaddw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x01, 0xcd], "vphaddw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x02, 0x0f], "vphaddd xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x02, 0x0f], "vphaddd ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x02, 0xcd], "vphaddd xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x02, 0xcd], "vphaddd ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x03, 0x0f], "vphaddsw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x03, 0x0f], "vphaddsw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x03, 0xcd], "vphaddsw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x03, 0xcd], "vphaddsw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x04, 0x0f], "vphaddubsw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x04, 0x0f], "vphaddubsw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x04, 0xcd], "vphaddubsw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x04, 0xcd], "vphaddubsw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x05, 0x0f], "vphsubw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x05, 0x0f], "vphsubw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x05, 0xcd], "vphsubw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x05, 0xcd], "vphsubw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x06, 0x0f], "vphsubd xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x06, 0x0f], "vphsubd ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x06, 0xcd], "vphsubd xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x06, 0xcd], "vphsubd ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x07, 0x0f], "vphsubsw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x07, 0x0f], "vphsubsw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x07, 0xcd], "vphsubsw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x07, 0xcd], "vphsubsw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x08, 0x0f], "vpsignb xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x08, 0x0f], "vpsignb ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x08, 0xcd], "vpsignb xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x08, 0xcd], "vpsignb ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x09, 0x0f], "vpsignw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x09, 0x0f], "vpsignw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x09, 0xcd], "vpsignw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x09, 0xcd], "vpsignw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0a, 0x0f], "vpsignd xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0a, 0x0f], "vpsignd ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0a, 0xcd], "vpsignd xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0a, 0xcd], "vpsignd ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0b, 0x0f], "vpmulhrsw xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0b, 0x0f], "vpmulhrsw ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0b, 0xcd], "vpmulhrsw xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0b, 0xcd], "vpmulhrsw ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0c, 0x0f], "vpermilps xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0c, 0x0f], "vpermilps ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0c, 0xcd], "vpermilps xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0c, 0xcd], "vpermilps ymm9, ymm1, ymm13");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0d, 0x0f], "vpermilpd xmm9, xmm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0d, 0x0f], "vpermilpd ymm9, ymm1, [r15]");
+ test_instr(&[0xc4, 0x02, 0x71, 0x0d, 0xcd], "vpermilpd xmm9, xmm1, xmm13");
+ test_instr(&[0xc4, 0x02, 0x75, 0x0d, 0xcd], "vpermilpd ymm9, ymm1, ymm13");
+ test_instr_invalid(&[0xc4, 0x02, 0x71, 0x0e, 0x00]);
+ test_instr(&[0xc4, 0x02, 0x79, 0x0e, 0x0f], "vtestps xmm9, [r15]");
+ test_instr(&[0xc4, 0x02, 0x7d, 0x0e, 0x0f], "vtestps ymm9, [r15]");
+ test_instr(&[0xc4, 0x02, 0x79, 0x0e, 0xcd], "vtestps xmm9, xmm13");
+ test_instr(&[0xc4, 0x02, 0x7d, 0x0e, 0xcd], "vtestps ymm9, ymm13");
+ test_instr_invalid(&[0xc4, 0x02, 0x71, 0x0f, 0x00]);
+ test_instr(&[0xc4, 0x02, 0x79, 0x0f, 0x0f], "vtestpd xmm9, [r15]");
+ test_instr(&[0xc4, 0x02, 0x7d, 0x0f, 0x0f], "vtestpd ymm9, [r15]");
+ test_instr(&[0xc4, 0x02, 0x79, 0x0f, 0xcd], "vtestpd xmm9, xmm13");
+ test_instr(&[0xc4, 0x02, 0x7d, 0x0f, 0xcd], "vtestpd ymm9, ymm13");
+ test_instr(&[0xc4, 0xe2, 0x65, 0x90, 0x04, 0x51], "vpgatherdd ymm0, [rcx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xe2, 0xe5, 0x90, 0x04, 0x51], "vpgatherdq ymm0, [rcx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xe2, 0x65, 0x91, 0x04, 0x51], "vpgatherqd ymm0, [rcx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xe2, 0xe5, 0x91, 0x04, 0x51], "vpgatherqq ymm0, [rcx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0x02, 0x09, 0x9d, 0xcd], "vfnmadd132ss xmm9, xmm14, xmm13");
+ test_instr(&[0xc4, 0x02, 0x89, 0x9d, 0xcd], "vfnmadd132sd xmm9, xmm14, xmm13");
+// ...
+ test_instr(&[0xc4, 0xe3, 0x79, 0x14, 0xd0, 0x0a], "vpextrb rax, xmm2, 0xa");
+ test_instr(&[0xc4, 0xe3, 0x79, 0x14, 0x10, 0x0a], "vpextrb [rax], xmm2, 0xa");
+ test_instr_invalid(&[0xc4, 0xe3, 0xf9, 0x14, 0x00, 0xd0]);
+ test_instr_invalid(&[0xc4, 0xe3, 0xf9, 0x14, 0x00, 0x0a]);
+}
+
+#[test]
+fn strange_prefixing() {
+ test_display(&[0x45, 0x66, 0x0f, 0x21, 0xc8], "mov rax, dr1");
+ test_display(&[0x45, 0xf2, 0x0f, 0x21, 0xc8], "mov rax, dr1");
+ test_display(&[0x45, 0xf3, 0x0f, 0x21, 0xc8], "mov rax, dr1");
+}
+
+#[test]
+fn prefixed_0f() {
+ test_display(&[0x0f, 0x02, 0xc0], "lar eax, ax");
+ test_display(&[0x48, 0x0f, 0x02, 0xc0], "lar rax, ax");
+ test_display(&[0x0f, 0x03, 0xc0], "lsl eax, eax");
+ test_display(&[0x48, 0x0f, 0x03, 0xc0], "lsl rax, rax");
+ test_display(&[0x0f, 0x05], "syscall");
+ test_display(&[0x48, 0x0f, 0x05], "syscall");
+ test_display(&[0x66, 0x0f, 0x05], "syscall");
+ test_display(&[0x0f, 0x06], "clts");
+ test_display(&[0xf2, 0x0f, 0x06], "clts");
+ test_display(&[0x0f, 0x07], "sysret");
+ test_display(&[0xf2, 0x0f, 0x07], "sysret");
+ test_display(&[0x0f, 0x12, 0x0f], "movlps xmm1, [rdi]");
+ test_display(&[0x0f, 0x12, 0xcf], "movhlps xmm1, xmm7");
+ test_display(&[0x0f, 0x16, 0x0f], "movhps xmm1, [rdi]");
+ test_display(&[0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
+ test_display(&[0x0f, 0x12, 0xc0], "movhlps xmm0, xmm0");
+ test_invalid(&[0x0f, 0x13, 0xc0]);
+ test_display(&[0x0f, 0x13, 0x00], "movlps [rax], xmm0");
+ test_display(&[0x0f, 0x14, 0x08], "unpcklps xmm1, [rax]");
+ test_display(&[0x0f, 0x15, 0x08], "unpckhps xmm1, [rax]");
+ test_display(&[0x0f, 0x16, 0x0f], "movhps xmm1, [rdi]");
+ test_display(&[0x0f, 0x16, 0xc0], "movlhps xmm0, xmm0");
+ test_invalid(&[0x0f, 0x17, 0xc0]);
+ test_display(&[0x0f, 0x17, 0x00], "movhps [rax], xmm0");
+ test_invalid(&[0x0f, 0x18, 0xc0]);
+ test_display(&[0x0f, 0x18, 0x00], "prefetchnta [rax]");
+ test_display(&[0x0f, 0x18, 0x08], "prefetch0 [rax]");
+ test_display(&[0x0f, 0x18, 0x10], "prefetch1 [rax]");
+ test_display(&[0x0f, 0x18, 0x18], "prefetch2 [rax]");
+ test_display(&[0x0f, 0x18, 0x20], "nop [rax]");
+ test_display(&[0x4f, 0x0f, 0x18, 0x20], "nop [r8]");
+ test_display(&[0x0f, 0x19, 0x20], "nop [rax]");
+ test_display(&[0x0f, 0x1a, 0x20], "nop [rax]");
+ test_display(&[0x0f, 0x1b, 0x20], "nop [rax]");
+ test_display(&[0x0f, 0x1c, 0x20], "nop [rax]");
+ test_display(&[0x0f, 0x1d, 0x20], "nop [rax]");
+ test_display(&[0x0f, 0x1e, 0x20], "nop [rax]");
+ test_display(&[0x0f, 0x1f, 0x20], "nop [rax]");
+ test_display(&[0x45, 0x0f, 0x20, 0xc8], "mov r8, cr9");
+ test_display(&[0x0f, 0x20, 0xc8], "mov rax, cr1");
+ test_display(&[0x45, 0x0f, 0x21, 0xc8], "mov r8, dr9");
+ test_display(&[0x0f, 0x21, 0xc8], "mov rax, dr1");
+ test_display(&[0x45, 0x0f, 0x22, 0xc8], "mov cr9, r8");
+ test_display(&[0x40, 0x0f, 0x22, 0xc8], "mov cr1, rax");
+ test_display(&[0x0f, 0x22, 0xc8], "mov cr1, rax");
+ test_display(&[0x44, 0x0f, 0x22, 0xcf], "mov cr9, rdi");
+ test_display(&[0x0f, 0x22, 0xcf], "mov cr1, rdi");
+ test_display(&[0x45, 0x0f, 0x23, 0xc8], "mov dr9, r8");
+ test_display(&[0x40, 0x0f, 0x23, 0xc8], "mov dr1, rax");
+ test_display(&[0x0f, 0x23, 0xc8], "mov dr1, rax");
+ test_display(&[0x44, 0x0f, 0x23, 0xcf], "mov dr9, rdi");
+ test_display(&[0x0f, 0x23, 0xcf], "mov dr1, rdi");
+ test_display(&[0x0f, 0x30], "wrmsr");
+ test_display(&[0x0f, 0x31], "rdtsc");
+ test_display(&[0x0f, 0x32], "rdmsr");
+ test_display(&[0x0f, 0x33], "rdpmc");
+ test_display(&[0x0f, 0x34], "sysenter");
+ test_display(&[0x0f, 0x35], "sysexit");
+ test_invalid(&[0x0f, 0x36]);
+ test_display(&[0x0f, 0x37], "getsec");
+ test_display(&[0x0f, 0x60, 0x00], "punpcklbw mm0, [rax]");
+ test_display(&[0x0f, 0x60, 0xc2], "punpcklbw mm0, mm2");
+ test_display(&[0x0f, 0x61, 0x00], "punpcklwd mm0, [rax]");
+ test_display(&[0x0f, 0x61, 0xc2], "punpcklwd mm0, mm2");
+ test_display(&[0x0f, 0x62, 0x00], "punpckldq mm0, [rax]");
+ test_display(&[0x0f, 0x62, 0xc2], "punpckldq mm0, mm2");
+ test_display(&[0x0f, 0x63, 0x00], "packsswb mm0, [rax]");
+ test_display(&[0x0f, 0x63, 0xc2], "packsswb mm0, mm2");
+ test_display(&[0x0f, 0x64, 0x00], "pcmpgtb mm0, [rax]");
+ test_display(&[0x0f, 0x64, 0xc2], "pcmpgtb mm0, mm2");
+ test_display(&[0x0f, 0x65, 0x00], "pcmpgtw mm0, [rax]");
+ test_display(&[0x0f, 0x65, 0xc2], "pcmpgtw mm0, mm2");
+ test_display(&[0x0f, 0x66, 0x00], "pcmpgtd mm0, [rax]");
+ test_display(&[0x0f, 0x66, 0xc2], "pcmpgtd mm0, mm2");
+ test_display(&[0x0f, 0x67, 0x00], "packuswb mm0, [rax]");
+ test_display(&[0x0f, 0x67, 0xc2], "packuswb mm0, mm2");
+ test_display(&[0x0f, 0x68, 0x00], "punpckhbw mm0, [rax]");
+ test_display(&[0x0f, 0x68, 0xc2], "punpckhbw mm0, mm2");
+ test_display(&[0x0f, 0x69, 0x00], "punpckhwd mm0, [rax]");
+ test_display(&[0x0f, 0x69, 0xc2], "punpckhwd mm0, mm2");
+ test_display(&[0x0f, 0x6a, 0x00], "punpckhdq mm0, [rax]");
+ test_display(&[0x0f, 0x6a, 0xc2], "punpckhdq mm0, mm2");
+ test_display(&[0x0f, 0x6b, 0x00], "packssdw mm0, [rax]");
+ test_display(&[0x0f, 0x6b, 0xc2], "packssdw mm0, mm2");
+ test_invalid(&[0x0f, 0x6c]);
+ test_invalid(&[0x0f, 0x6d]);
+ test_display(&[0x0f, 0x6e, 0x00], "movd mm0, [rax]");
+ test_display(&[0x0f, 0x6e, 0xc2], "movd mm0, edx");
+ test_display(&[0x0f, 0x6f, 0x00], "movq mm0, [rax]");
+ test_display(&[0x0f, 0x6f, 0xc2], "movq mm0, mm2");
+ test_display(&[0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [rax], 0x7f");
+ test_display(&[0x4f, 0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [r8], 0x7f");
+ test_invalid(&[0x0f, 0x71, 0x00, 0x7f]);
+ test_invalid(&[0x0f, 0x71, 0xc0, 0x7f]);
+ test_display(&[0x0f, 0x71, 0xd0, 0x7f], "psrlw mm0, 0x7f");
+ test_display(&[0x0f, 0x71, 0xe0, 0x7f], "psraw mm0, 0x7f");
+ test_display(&[0x0f, 0x71, 0xf0, 0x7f], "psllw mm0, 0x7f");
+ test_invalid(&[0x0f, 0x72, 0x00, 0x7f]);
+ test_invalid(&[0x0f, 0x72, 0xc0, 0x7f]);
+ test_display(&[0x0f, 0x72, 0xd0, 0x7f], "psrld mm0, 0x7f");
+ test_display(&[0x0f, 0x72, 0xe0, 0x7f], "psrad mm0, 0x7f");
+ test_display(&[0x0f, 0x72, 0xf0, 0x7f], "pslld mm0, 0x7f");
+ test_invalid(&[0x0f, 0x73, 0x00, 0x7f]);
+ test_invalid(&[0x0f, 0x73, 0xc0, 0x7f]);
+ test_display(&[0x0f, 0x73, 0xd0, 0x7f], "psrlq mm0, 0x7f");
+ test_invalid(&[0x0f, 0x73, 0xe0, 0x7f]);
+ test_display(&[0x0f, 0x73, 0xf0, 0x7f], "psllq mm0, 0x7f");
+ test_display(&[0x0f, 0xa0], "push fs");
+ test_display(&[0x0f, 0xa1], "pop fs");
+ test_display(&[0x0f, 0xa2], "cpuid");
+ test_display(&[0x0f, 0xa4, 0xc0, 0x11], "shld eax, eax, 0x11");
+ test_display(&[0x66, 0x0f, 0xa4, 0xcf, 0x11], "shld di, cx, 0x11");
+ test_display(&[0x66, 0x45, 0x0f, 0xa4, 0xcf, 0x11], "shld r15w, r9w, 0x11");
+ test_display(&[0x0f, 0xa5, 0xc0], "shld eax, eax, cl");
+ test_display(&[0x0f, 0xa5, 0xc9], "shld ecx, ecx, cl");
+}
+
+#[test]
+fn prefixed_660f() {
+ test_display(&[0x66, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
+ test_display(&[0x66, 0x48, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
+ test_display(&[0x66, 0x4a, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
+ test_display(&[0x66, 0x4b, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm8");
+ test_display(&[0x66, 0x4c, 0x0f, 0x10, 0xc0], "movupd xmm8, xmm0");
+ test_display(&[0x66, 0x4d, 0x0f, 0x10, 0xc0], "movupd xmm8, xmm8");
+ test_display(&[0xf2, 0x66, 0x66, 0x4d, 0x0f, 0x10, 0xc0], "movupd xmm8, xmm8");
+}
+
+#[test]
+fn prefixed_f20f() {
+ test_display(&[0xf2, 0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
+ test_display(&[0xf2, 0x4d, 0x0f, 0x16, 0xcf], "movlhps xmm9, xmm15");
+ test_display(&[0x40, 0x66, 0xf2, 0x66, 0x4d, 0x0f, 0x16, 0xcf], "movlhps xmm9, xmm15");
+}
+
+#[test]
+fn prefixed_f30f() {
+ test_display(&[0xf3, 0x0f, 0x16, 0xcf], "movshdup xmm1, xmm7");
+ test_display(&[0xf3, 0x4d, 0x0f, 0x16, 0xcf], "movshdup xmm9, xmm15");
+}
diff --git a/test/regspec.rs b/test/long_mode/regspec.rs
index 914c376..914c376 100644
--- a/test/regspec.rs
+++ b/test/long_mode/regspec.rs
diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs
new file mode 100644
index 0000000..e1fb281
--- /dev/null
+++ b/test/protected_mode/mod.rs
@@ -0,0 +1,1035 @@
+mod regspec;
+
+use std::fmt::Write;
+
+use yaxpeax_arch::{Decoder, LengthedInstruction};
+use yaxpeax_x86::protected_mode::{DecodeError, InstDecoder, Opcode};
+
+fn test_invalid(data: &[u8]) {
+ test_invalid_under(&InstDecoder::default(), data);
+}
+
+fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) {
+ if let Ok(inst) = decoder.decode(data.into_iter().cloned()) {
+ assert_eq!(inst.opcode, Opcode::Invalid, "decoded {:?} from {:02x?} under decoder {}", inst.opcode, data, decoder);
+ } else {
+ // this is fine
+ }
+}
+
+fn test_display(data: &[u8], expected: &'static str) {
+ test_display_under(&InstDecoder::default(), data, expected);
+}
+
+fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str) {
+ let mut hex = String::new();
+ for b in data {
+ write!(hex, "{:02x}", b).unwrap();
+ }
+ match decoder.decode(data.into_iter().map(|x| *x)) {
+ Ok(instr) => {
+ let text = format!("{}", instr);
+ assert!(
+ text == expected,
+ "display error for {}:\n decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n",
+ hex,
+ instr,
+ decoder,
+ text,
+ expected
+ );
+ // while we're at it, test that the instruction is as long, and no longer, than its
+ // input
+ assert_eq!(instr.len() as usize, data.len(), "instruction length is incorrect, wanted instruction {}", expected);
+ },
+ Err(e) => {
+ assert!(false, "decode error ({}) for {} under decoder {}:\n expected: {}\n", e, hex, decoder, expected);
+ }
+ }
+}
+
+#[test]
+fn test_mmx() {
+ test_display(&[0x0f, 0x7e, 0xcf], "movd edi, mm1");
+ test_display(&[0x0f, 0x7f, 0xcf], "movq mm7, mm1");
+ test_display(&[0x0f, 0x7f, 0x0f], "movq [edi], mm1");
+ test_display(&[0x0f, 0xc4, 0xc0, 0x14], "pinsrw mm0, eax, 0x14");
+ test_display(&[0x0f, 0xc4, 0x00, 0x14], "pinsrw mm0, [eax], 0x14");
+ test_display(&[0x0f, 0xd1, 0xcf], "psrlw mm1, mm7");
+ test_display(&[0x0f, 0xd1, 0x00], "psrlw mm0, [eax]");
+ test_invalid(&[0x0f, 0xd7, 0x00]);
+ test_display(&[0x0f, 0xd7, 0xcf], "pmovmskb ecx, mm7");
+}
+
+#[test]
+fn test_cvt() {
+ test_display(&[0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm7");
+ test_display(&[0x0f, 0x2a, 0xcf], "cvtpi2ps xmm1, mm7");
+ test_display(&[0x0f, 0x2a, 0x00], "cvtpi2ps xmm0, [eax]");
+ test_display(&[0x66, 0x0f, 0x2a, 0x00], "cvtpi2pd xmm0, [eax]");
+ test_display(&[0x66, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm1, mm7");
+ test_display(&[0xf2, 0x0f, 0x2a, 0x00], "cvtsi2sd xmm0, [eax]");
+ test_display(&[0xf2, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm1, edi");
+ test_display(&[0xf3, 0x0f, 0x2a, 0x00], "cvtsi2ss xmm0, [eax]");
+ test_display(&[0xf3, 0x0f, 0x2a, 0xcf], "cvtsi2ss xmm1, edi");
+}
+
+#[test]
+fn test_aesni() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_aesni(), bytes, text);
+ test_display_under(&InstDecoder::default(), bytes, text);
+ test_invalid_under(&InstDecoder::minimal(), bytes);
+ }
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, [edi]");
+ test_instr(&[0x67, 0x66, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, [bx]");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdc, 0x0f], "aesenc xmm1, [edi]");
+ test_instr(&[0x67, 0x66, 0x0f, 0x38, 0xdc, 0x0f], "aesenc xmm1, [bx]");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdd, 0x0f], "aesenclast xmm1, [edi]");
+ test_instr(&[0x67, 0x66, 0x0f, 0x38, 0xdd, 0x0f], "aesenclast xmm1, [bx]");
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xde, 0x0f], "aesdec xmm1, [edi]");
+ test_instr(&[0x67, 0x66, 0x0f, 0x38, 0xde, 0x0f], "aesdec xmm1, [bx]");
+ test_invalid(&[0x66, 0x67, 0x0f, 0x38, 0xde, 0x0f]);
+
+ test_instr(&[0x66, 0x0f, 0x38, 0xdf, 0x0f], "aesdeclast xmm1, [edi]");
+ test_instr(&[0x67, 0x66, 0x0f, 0x38, 0xdf, 0x0f], "aesdeclast xmm1, [bx]");
+
+ test_instr(&[0x66, 0x0f, 0x3a, 0xdf, 0x0f, 0xaa], "aeskeygenassist xmm1, [edi], 0xaa");
+}
+
+#[test]
+fn test_sse2() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ // sse and sse2 are part of amd64, so x86_64, meaning even the minimal decoder must support
+ // them.
+ test_display_under(&InstDecoder::minimal(), bytes, text);
+ }
+
+ test_instr(&[0xf2, 0x0f, 0x10, 0x0c, 0xc7], "movsd xmm1, [edi + eax * 8]");
+ test_instr(&[0xf2, 0x0f, 0x11, 0x0c, 0xc7], "movsd [edi + eax * 8], xmm1");
+ test_instr(&[0x66, 0x0f, 0x11, 0x0c, 0xc7], "movupd [edi + eax * 8], xmm1");
+ test_instr(&[0x66, 0x0f, 0x12, 0xc3], "movhlps xmm0, xmm3"); // reg-reg form is movhlps
+ test_instr(&[0x66, 0x0f, 0x12, 0x03], "movlpd xmm0, [ebx]"); // reg-mem is movlpd
+ test_instr(&[0x66, 0x0f, 0x13, 0x03], "movlpd [ebx], xmm0");
+ test_invalid(&[0x66, 0x0f, 0x13, 0xc3]);
+ test_instr(&[0x66, 0x0f, 0x14, 0x03], "unpcklpd xmm0, [ebx]");
+ test_instr(&[0x66, 0x0f, 0x14, 0xc3], "unpcklpd xmm0, xmm3");
+ test_instr(&[0x66, 0x0f, 0x15, 0x03], "unpckhpd xmm0, [ebx]");
+ test_instr(&[0x66, 0x0f, 0x15, 0xc3], "unpckhpd xmm0, xmm3");
+ test_instr(&[0x66, 0x0f, 0x16, 0x03], "movhpd xmm0, [ebx]");
+ test_instr(&[0x66, 0x0f, 0x16, 0xc3], "movlhps xmm0, xmm3");
+ test_instr(&[0x66, 0x0f, 0x17, 0x03], "movhpd [ebx], xmm0");
+ test_invalid(&[0x66, 0x0f, 0x17, 0xc3]);
+
+ test_instr(&[0x66, 0x0f, 0x28, 0xd0], "movapd xmm2, xmm0");
+ test_instr(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
+
+ test_instr(&[0x66, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm1, mm7");
+ test_instr(&[0x66, 0x0f, 0x2a, 0x0f], "cvtpi2pd xmm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm1, edi");
+ test_instr(&[0xf2, 0x0f, 0x2a, 0x0f], "cvtsi2sd xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0x2b, 0x0f], "movntpd [edi], xmm1");
+ test_instr(&[0x66, 0x0f, 0x2c, 0xcf], "cvttpd2pi mm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0x2c, 0x0f], "cvttpd2pi mm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0x2c, 0xcf], "cvttsd2si xmm1, xmm7");
+ test_instr(&[0xf2, 0x0f, 0x2c, 0x0f], "cvttsd2si xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0x2d, 0xcf], "cvtpd2pi mm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0x2d, 0x0f], "cvtpd2pi mm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0x2d, 0xcf], "cvtsd2si xmm1, xmm7");
+ test_instr(&[0xf2, 0x0f, 0x2d, 0x0f], "cvtsd2si xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0x2e, 0xcf], "ucomisd xmm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0x2e, 0x0f], "ucomisd xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0x2f, 0xcf], "comisd xmm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0x2f, 0x0f], "comisd xmm1, [edi]");
+
+ /*
+ * .... 660f38
+ * .... 660f7f
+ */
+
+ test_invalid(&[0x66, 0x0f, 0x50, 0x01]);
+ test_instr(&[0x66, 0x0f, 0x50, 0xc1], "movmskpd eax, xmm1");
+ test_instr(&[0x66, 0x0f, 0x51, 0x01], "sqrtpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x51, 0x01], "sqrtsd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x52, 0x01], "rsqrtps xmm0, [ecx]"); // note: NOT "rsqrtpd" - no such instruction exists, so fall back to just 0f52 parse.
+ test_instr(&[0x66, 0x0f, 0x53, 0x01], "rcpps xmm0, [ecx]"); // note: NOT "rcppd" - no such instruction exists, so fall back to just 0f53 parse.
+ test_instr(&[0x66, 0x0f, 0x54, 0x01], "andpd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x55, 0x01], "andnpd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x56, 0x01], "orpd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x57, 0x01], "xorpd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x58, 0x01], "addpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x58, 0x01], "addsd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x59, 0x01], "mulpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x59, 0x01], "mulsd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x5a, 0x01], "cvtpd2ps xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x5a, 0x01], "cvtsd2ss xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x5b, 0x01], "cvtps2dq xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x5c, 0x01], "subpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x5c, 0x01], "subsd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x5d, 0x01], "minpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x5d, 0x01], "minsd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x5e, 0x01], "divpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x5e, 0x01], "divsd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0x5f, 0x01], "maxpd xmm0, [ecx]");
+ test_instr(&[0xf2, 0x0f, 0x5f, 0x01], "maxsd xmm0, [ecx]");
+ test_instr(
+ &[0x66, 0x0f, 0x60, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpcklbw xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x61, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpcklwd xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x62, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckldq xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x63, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "packsswb xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x64, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "pcmpgtb xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x65, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "pcmpgtw xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x66, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "pcmpgtd xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x67, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "packuswb xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x68, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhbw xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x69, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhwd xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x6a, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhdq xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x6b, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "packssdw xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x6c, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpcklqdq xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x6d, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "punpckhqdq xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ // TODO: this needs to be clear that the operand is `dword`
+ test_instr(
+ &[0x66, 0x0f, 0x6e, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movd xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_instr(
+ &[0x66, 0x0f, 0x6f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqa xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+
+ test_instr(&[0x66, 0x0f, 0x6e, 0xc0], "movd xmm0, eax");
+ test_instr(&[0x66, 0x0f, 0x70, 0xc0, 0x4e], "pshufd xmm0, xmm0, 0x4e");
+ test_instr(&[0xf2, 0x0f, 0x70, 0xc0, 0x4e], "pshuflw xmm0, xmm0, 0x4e");
+ test_instr(&[0xf3, 0x0f, 0x70, 0xc0, 0x4e], "pshufhw xmm0, xmm0, 0x4e");
+ test_invalid(&[0x66, 0x0f, 0x71, 0x10, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x71, 0xd0, 0x8f], "psrlw xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x71, 0x20, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x71, 0xe0, 0x8f], "psraw xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x71, 0x30, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x71, 0xf0, 0x8f], "psllw xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x72, 0x10, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x72, 0xd0, 0x8f], "psrld xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x72, 0x20, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x72, 0xe0, 0x8f], "psrad xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x72, 0x30, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x72, 0xf0, 0x8f], "pslld xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x73, 0x10, 0x8f]);
+ test_invalid(&[0x66, 0x0f, 0x73, 0x18, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x73, 0xd0, 0x8f], "psrlq xmm0, 0x8f");
+ test_instr(&[0x66, 0x0f, 0x73, 0xd8, 0x8f], "psrldq xmm0, 0x8f");
+ test_invalid(&[0x66, 0x0f, 0x73, 0x30, 0x8f]);
+ test_invalid(&[0x66, 0x0f, 0x73, 0x38, 0x8f]);
+ test_instr(&[0x66, 0x0f, 0x73, 0xf0, 0x8f], "psllq xmm0, 0x8f");
+ test_instr(&[0x66, 0x0f, 0x73, 0xf8, 0x8f], "pslldq xmm0, 0x8f");
+ test_instr(&[0x66, 0x0f, 0x7e, 0xc1], "movd ecx, xmm0");
+ test_instr(&[0x66, 0x0f, 0x7e, 0x01], "movd [ecx], xmm0");
+ test_instr(
+ &[0x66, 0x0f, 0x7f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqa [esp + ebx * 4 - 0x334455cc], xmm3"
+ );
+
+ test_instr(&[0x66, 0x0f, 0xc2, 0xc3, 0x08], "cmppd xmm0, xmm3, 0x8");
+ test_instr(&[0x66, 0x0f, 0xc2, 0x03, 0x08], "cmppd xmm0, [ebx], 0x8");
+ test_instr(&[0xf2, 0x0f, 0xc2, 0xc3, 0x08], "cmpsd xmm0, xmm3, 0x8");
+ test_instr(&[0xf2, 0x0f, 0xc2, 0x03, 0x08], "cmpsd xmm0, [ebx], 0x8");
+
+ test_instr(&[0x66, 0x0f, 0xc4, 0xc3, 0x08], "pinsrw xmm0, ebx, 0x8");
+ test_instr(&[0x66, 0x0f, 0xc4, 0x03, 0x08], "pinsrw xmm0, [ebx], 0x8");
+
+// test_instr(&[0x66, 0x0f, 0xc5, 0xc3, 0x08], "pextrw eax, xmm3, 0x8");
+// test_instr(&[0x66, 0x4f, 0x0f, 0xc5, 0xc3, 0x08], "pextrw eax, xmm11, 0x8");
+// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x03, 0x08]);
+// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x40, 0x08]);
+// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x80, 0x08]);
+
+ test_instr(&[0x66, 0x0f, 0xc6, 0x03, 0x08], "shufpd xmm0, [ebx], 0x8");
+ test_instr(&[0x66, 0x0f, 0xc6, 0xc3, 0x08], "shufpd xmm0, xmm3, 0x8");
+ test_instr(&[0x66, 0x0f, 0xd1, 0xc1], "psrlw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd1, 0x01], "psrlw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xd2, 0xc1], "psrld xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd2, 0x01], "psrld xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xd3, 0xc1], "psrlq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd3, 0x01], "psrlq xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xd4, 0xc1], "paddq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd4, 0x01], "paddq xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xd5, 0xc1], "pmullw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd5, 0x01], "pmullw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xd6, 0xc1], "movq xmm1, xmm0");
+ test_instr(&[0x66, 0x0f, 0xd6, 0x01], "movq [ecx], xmm0");
+ test_invalid(&[0xf3, 0x0f, 0xd6, 0x03]);
+ test_instr(&[0xf3, 0x0f, 0xd6, 0xc3], "movq2dq xmm0, mm3");
+ test_instr(&[0xf2, 0x0f, 0xd6, 0xc3], "movdq2q mm0, xmm3");
+ test_instr(&[0x66, 0x0f, 0xd7, 0xc1], "pmovmskb eax, xmm1");
+ test_invalid(&[0x66, 0x0f, 0xd7, 0x01]);
+ test_instr(&[0x66, 0x0f, 0xd8, 0xc1], "psubusb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd8, 0x01], "psubusb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xd9, 0xc1], "psubusw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xd9, 0x01], "psubusw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xda, 0xc1], "pminub xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xda, 0x01], "pminub xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xdb, 0xc1], "pand xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdb, 0x01], "pand xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xdc, 0xc1], "paddusb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdc, 0x01], "paddusb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xdd, 0xc1], "paddusw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdd, 0x01], "paddusw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xde, 0xc1], "pmaxub xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xde, 0x01], "pmaxub xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xdf, 0xc1], "pandn xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xdf, 0x01], "pandn xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe0, 0xc1], "pavgb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe0, 0x01], "pavgb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe1, 0xc1], "psraw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe1, 0x01], "psraw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe2, 0xc1], "psrad xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe2, 0x01], "psrad xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe3, 0xc1], "pavgw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe3, 0x01], "pavgw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe4, 0xc1], "pmulhuw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe4, 0x01], "pmulhuw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe5, 0xc1], "pmulhw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe5, 0x01], "pmulhw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe6, 0xc1], "cvttpd2dq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe6, 0x01], "cvttpd2dq xmm0, [ecx]");
+ test_invalid(&[0x66, 0x0f, 0xe7, 0xc1]);
+ test_instr(&[0x66, 0x0f, 0xe7, 0x01], "movntdq [ecx], xmm0");
+ test_instr(&[0x66, 0x0f, 0xe8, 0xc1], "psubsb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe8, 0x01], "psubsb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xe9, 0xc1], "psubsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xe9, 0x01], "psubsw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xea, 0xc1], "pminsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xea, 0x01], "pminsw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xc3], "por xmm0, xmm3");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xc4], "por xmm0, xmm4");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xd3], "por xmm2, xmm3");
+ test_instr(&[0x66, 0x0f, 0xeb, 0x12], "por xmm2, [edx]");
+ test_instr(&[0x66, 0x0f, 0xeb, 0xc1], "por xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xeb, 0x01], "por xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xec, 0xc1], "paddsb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xec, 0x01], "paddsb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xed, 0xc1], "paddsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xed, 0x01], "paddsw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xee, 0xc1], "pmaxsw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xee, 0x01], "pmaxsw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xef, 0xc1], "pxor xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xef, 0x01], "pxor xmm0, [ecx]");
+ test_invalid(&[0x66, 0x0f, 0xf0, 0xc1]);
+ test_invalid(&[0x66, 0x0f, 0xf0, 0x01]);
+ test_instr(&[0x66, 0x0f, 0xf1, 0xc1], "psllw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf1, 0x01], "psllw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf2, 0xc1], "pslld xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf2, 0x01], "pslld xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf3, 0xc1], "psllq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf3, 0x01], "psllq xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf4, 0xc1], "pmuludq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf4, 0x01], "pmuludq xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf5, 0xc1], "pmaddwd xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf5, 0x01], "pmaddwd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf6, 0xc1], "psadbw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf6, 0x01], "psadbw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf7, 0xc1], "maskmovdqu xmm0, xmm1");
+ test_invalid(&[0x66, 0x0f, 0xf7, 0x01]);
+ test_instr(&[0x66, 0x0f, 0xf8, 0xc1], "psubb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf8, 0x01], "psubb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xf9, 0xc1], "psubw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xf9, 0x01], "psubw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xfa, 0xc1], "psubd xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfa, 0x01], "psubd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xfb, 0xc1], "psubq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfb, 0x01], "psubq xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xfc, 0xc1], "paddb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfc, 0x01], "paddb xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xfd, 0xc1], "paddw xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfd, 0x01], "paddw xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xfe, 0xc1], "paddd xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xfe, 0x01], "paddd xmm0, [ecx]");
+ test_instr(&[0x66, 0x0f, 0xff, 0xc1], "paddq xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0xff, 0x01], "paddq xmm0, [ecx]");
+
+ test_instr(&[0x66, 0x0f, 0x74, 0xc1], "pcmpeqb xmm0, xmm1");
+ test_instr(&[0x66, 0x0f, 0x74, 0x12], "pcmpeqb xmm2, [edx]");
+ test_instr(&[0x66, 0x0f, 0xf8, 0xc8], "psubb xmm1, xmm0");
+ test_instr(&[0x66, 0x0f, 0xf8, 0xd0], "psubb xmm2, xmm0");
+ test_instr(&[0x66, 0x0f, 0xf8, 0x12], "psubb xmm2, [edx]");
+}
+
+#[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, [edi]");
+ test_instr_invalid(&[0xf2, 0x0f, 0xf0, 0xcf]);
+ test_instr(&[0xf2, 0x0f, 0xd0, 0x0f], "addsubps xmm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0xd0, 0xcf], "addsubps xmm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0xd0, 0x0f], "addsubpd xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0xd0, 0xcf], "addsubpd xmm1, xmm7");
+
+ test_instr(&[0xf2, 0x0f, 0x7c, 0x0f], "haddps xmm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0x7c, 0xcf], "haddps xmm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0x7c, 0x0f], "haddpd xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0x7c, 0xcf], "haddpd xmm1, xmm7");
+
+ test_instr(&[0xf2, 0x0f, 0x7d, 0x0f], "hsubps xmm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0x7d, 0xcf], "hsubps xmm1, xmm7");
+ test_instr(&[0x66, 0x0f, 0x7d, 0x0f], "hsubpd xmm1, [edi]");
+ test_instr(&[0x66, 0x0f, 0x7d, 0xcf], "hsubpd xmm1, xmm7");
+
+ test_instr(&[0xf3, 0x0f, 0x12, 0x0f], "movsldup xmm1, [edi]");
+ test_instr(&[0xf3, 0x0f, 0x12, 0xcf], "movsldup xmm1, xmm7");
+ test_instr(&[0xf3, 0x0f, 0x16, 0x0f], "movshdup xmm1, [edi]");
+ test_instr(&[0xf3, 0x0f, 0x16, 0xcf], "movshdup xmm1, xmm7");
+
+ test_instr(&[0xf2, 0x0f, 0x12, 0x0f], "movddup xmm1, [edi]");
+ test_instr(&[0xf2, 0x0f, 0x12, 0xcf], "movddup xmm1, xmm7");
+
+ 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"
+ test_display(&[0x0f, 0x01, 0x38], "invlpg [eax]");
+ test_display(&[0x0f, 0x01, 0x3f], "invlpg [edi]");
+ test_display(&[0x0f, 0x01, 0x40, 0xff], "sgdt [eax - 0x1]");
+ test_display(&[0x0f, 0x01, 0x41, 0xff], "sgdt [ecx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x49, 0xff], "sidt [ecx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x51, 0xff], "lgdt [ecx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x59, 0xff], "lidt [ecx - 0x1]");
+ test_display(&[0x0f, 0x01, 0x61, 0xff], "smsw [ecx - 0x1]");
+ test_display(&[0x0f, 0x01, 0xc0], "enclv");
+ test_display(&[0x0f, 0x01, 0xc1], "vmcall");
+ test_display(&[0x0f, 0x01, 0xc2], "vmlaunch");
+ test_display(&[0x0f, 0x01, 0xc3], "vmresume");
+ test_display(&[0x0f, 0x01, 0xc4], "vmxoff");
+ test_invalid(&[0x0f, 0x01, 0xc5]);
+ test_invalid(&[0x0f, 0x01, 0xc6]);
+ test_invalid(&[0x0f, 0x01, 0xc7]);
+ test_display(&[0x0f, 0x01, 0xc8], "monitor");
+ test_display(&[0x0f, 0x01, 0xc9], "mwait");
+ test_display(&[0x0f, 0x01, 0xca], "clac");
+ test_display(&[0x0f, 0x01, 0xcb], "stac");
+ test_display(&[0x0f, 0x01, 0xcf], "encls");
+ test_display(&[0x0f, 0x01, 0xd0], "xgetbv");
+ test_display(&[0x0f, 0x01, 0xd1], "xsetbv");
+ test_invalid(&[0x0f, 0x01, 0xd2]);
+ test_invalid(&[0x0f, 0x01, 0xd3]);
+ test_display(&[0x0f, 0x01, 0xd4], "vmfunc");
+ test_display(&[0x0f, 0x01, 0xd5], "xend");
+ test_display(&[0x0f, 0x01, 0xd6], "xtest");
+ test_display(&[0x0f, 0x01, 0xd7], "enclu");
+ test_invalid(&[0x0f, 0x01, 0xd8]);
+ test_invalid(&[0x0f, 0x01, 0xd9]);
+ test_invalid(&[0x0f, 0x01, 0xda]);
+ test_invalid(&[0x0f, 0x01, 0xdb]);
+ test_invalid(&[0x0f, 0x01, 0xdc]);
+ test_invalid(&[0x0f, 0x01, 0xdd]);
+ test_invalid(&[0x0f, 0x01, 0xde]);
+ test_invalid(&[0x0f, 0x01, 0xdf]);
+ test_display(&[0x0f, 0x01, 0xee], "rdpkru");
+ test_display(&[0x0f, 0x01, 0xef], "wrpkru");
+ test_display(&[0x0f, 0x01, 0xf8], "swapgs");
+ test_display(&[0x0f, 0x01, 0xf9], "rdtscp");
+}
+
+#[test]
+fn test_0fae() {
+ let intel = InstDecoder::minimal().with_intel_quirks();
+ let amd = InstDecoder::minimal().with_amd_quirks();
+ let default = InstDecoder::default();
+ let minimal = InstDecoder::minimal();
+ // drawn heavily from "Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group
+ // Number"
+ test_display(&[0x0f, 0xae, 0x04, 0x4f], "fxsave [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x0c, 0x4f], "fxrstor [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x14, 0x4f], "ldmxcsr [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x1c, 0x4f], "stmxcsr [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x24, 0x4f], "xsave [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x2c, 0x4f], "xrstor [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x34, 0x4f], "xsaveopt [edi + ecx * 2]");
+ test_display(&[0x0f, 0xae, 0x3c, 0x4f], "clflush [edi + ecx * 2]");
+
+ for (modrm, text) in &[(0xe8u8, "lfence"), (0xf0u8, "mfence"), (0xf8u8, "sfence")] {
+ test_display_under(&intel, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&amd, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&default, &[0x0f, 0xae, *modrm], text);
+ test_display_under(&minimal, &[0x0f, 0xae, *modrm], text);
+ // it turns out intel and amd accept m != 0 for {l,m,s}fence:
+ // from intel:
+ // ```
+ // Specification of the instruction's opcode above indicates a ModR/M byte of F0. For this
+ // instruction, the processor ignores the r/m field of the ModR/M byte. Thus, MFENCE is encoded
+ // by any opcode of the form 0F AE Fx, where x is in the range 0-7.
+ // ```
+ // whereas amd does not discuss the r/m field at all. at least as of zen, amd also accepts
+ // these encodings.
+ for m in 1u8..8u8 {
+ test_display_under(&intel, &[0x0f, 0xae, modrm | m], text);
+ test_display_under(&amd, &[0x0f, 0xae, modrm | m], text);
+ test_display_under(&default, &[0x0f, 0xae, modrm | m], text);
+ test_invalid_under(&minimal, &[0x0f, 0xae, modrm | m]);
+ }
+ }
+}
+
+#[test]
+fn test_system() {
+ test_display(&[0x63, 0xc1], "arpl cx, ax");
+ test_display(&[0x63, 0x04, 0xba], "arpl [edx + edi * 4], ax");
+}
+
+#[test]
+fn test_arithmetic() {
+ test_display(&[0x81, 0xec, 0x10, 0x03, 0x00, 0x00], "sub esp, 0x310");
+ test_display(&[0x0f, 0xaf, 0xc2], "imul eax, edx");
+ test_display(&[0x69, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65], "imul eax, [ebx + 0x6f], 0x656c706d");
+ test_display(&[0x66, 0x0f, 0xaf, 0xd1], "imul dx, cx");
+ test_display(&[0x6b, 0x43, 0x6f, 0x6d], "imul al, [ebx + 0x6f], 0x6d");
+ test_display(&[0x00, 0xcc], "add ah, cl");
+}
+
+#[test]
+#[allow(non_snake_case)]
+fn test_E_decode() {
+ test_display(&[0xff, 0x75, 0xb8], "push [ebp - 0x48]");
+ test_display(&[0xff, 0x75, 0x08], "push [ebp + 0x8]");
+}
+
+#[test]
+fn test_sse() {
+ test_display(&[0xf3, 0x0f, 0x10, 0x0c, 0xc7], "movss xmm1, [edi + eax * 8]");
+ test_display(&[0xf3, 0x0f, 0x11, 0x0c, 0xc7], "movss [edi + eax * 8], xmm1");
+ test_display(&[0x0f, 0x28, 0x00], "movaps xmm0, [eax]");
+ test_display(&[0x0f, 0x29, 0x00], "movaps [eax], xmm0");
+ test_display(&[0xf3, 0x0f, 0x2a, 0xc1], "cvtsi2ss xmm0, ecx");
+ test_display(&[0xf3, 0x0f, 0x2a, 0x01], "cvtsi2ss xmm0, [ecx]");
+ test_display(&[0x0f, 0x2b, 0x00], "movntps [eax], xmm0");
+ test_display(&[0xf3, 0x0f, 0x2c, 0xc1], "cvttss2si eax, xmm1");
+ test_display(&[0xf3, 0x0f, 0x2c, 0x01], "cvttss2si eax, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x2d, 0xc1], "cvtss2si eax, xmm1");
+ test_display(&[0xf3, 0x0f, 0x2d, 0x01], "cvtss2si eax, [ecx]");
+ test_display(&[0x0f, 0x2e, 0x00], "ucomiss xmm0, [eax]");
+ test_display(&[0x0f, 0x2f, 0x00], "comiss xmm0, [eax]");
+ test_display(&[0x0f, 0x28, 0xd0], "movaps xmm2, xmm0");
+ test_display(&[0x66, 0x0f, 0x28, 0xd0], "movapd xmm2, xmm0");
+ test_display(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
+ test_display(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
+ test_display(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
+ test_display(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
+ test_display(&[0x67, 0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [bx + si]");
+ test_display(&[0x66, 0x0f, 0x29, 0x00], "movapd [eax], xmm0");
+ test_invalid(&[0x0f, 0x50, 0x00]);
+ test_display(&[0x0f, 0x50, 0xc1], "movmskps eax, xmm1");
+ test_display(&[0x0f, 0x51, 0x01], "sqrtps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x51, 0x01], "sqrtss xmm0, [ecx]");
+ test_display(&[0x0f, 0x52, 0x01], "rsqrtps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x52, 0x01], "rsqrtss xmm0, [ecx]");
+ test_display(&[0x0f, 0x53, 0x01], "rcpps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x53, 0x01], "rcpss xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x53, 0xc1], "rcpss xmm0, xmm1");
+ test_display(&[0x0f, 0x54, 0x01], "andps xmm0, [ecx]");
+ test_display(&[0x0f, 0x55, 0x01], "andnps xmm0, [ecx]");
+ test_display(&[0x0f, 0x56, 0x01], "orps xmm0, [ecx]");
+ test_display(&[0x0f, 0x57, 0x01], "xorps xmm0, [ecx]");
+ test_display(&[0x0f, 0x58, 0x01], "addps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x58, 0x01], "addss xmm0, [ecx]");
+ test_display(&[0x0f, 0x59, 0x01], "mulps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x59, 0x01], "mulss xmm0, [ecx]");
+ test_display(&[0x0f, 0x5a, 0x01], "cvtps2pd xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x5a, 0x01], "cvtss2sd xmm0, [ecx]");
+ test_display(&[0x0f, 0x5b, 0x01], "cvtdq2ps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x5b, 0x01], "cvttps2dq xmm0, [ecx]");
+ test_display(&[0x67, 0x0f, 0x5b, 0x01], "cvtdq2ps xmm0, [bx + di]");
+ test_display(&[0x0f, 0x5c, 0x01], "subps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x5c, 0x01], "subss xmm0, [ecx]");
+ test_display(&[0x0f, 0x5d, 0x01], "minps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x5d, 0x01], "minss xmm0, [ecx]");
+ test_display(&[0x0f, 0x5e, 0x01], "divps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x5e, 0x01], "divss xmm0, [ecx]");
+ test_display(&[0x0f, 0x5f, 0x01], "maxps xmm0, [ecx]");
+ test_display(&[0xf3, 0x0f, 0x5f, 0x01], "maxss xmm0, [ecx]");
+
+ test_display(&[0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [eax], 0x7f");
+
+ test_display(&[0x66, 0x0f, 0xef, 0xc0], "pxor xmm0, xmm0");
+ test_display(&[0x66, 0x0f, 0xef, 0xc0], "pxor xmm0, xmm0");
+ test_display(&[0xf2, 0x0f, 0x10, 0x0c, 0xc6], "movsd xmm1, [esi + eax * 8]");
+ test_display(&[0xf3, 0x0f, 0x10, 0x04, 0x86], "movss xmm0, [esi + eax * 4]");
+ test_display(&[0xf2, 0x0f, 0x59, 0xc8], "mulsd xmm1, xmm0");
+ test_display(&[0xf3, 0x0f, 0x59, 0xc8], "mulss xmm1, xmm0");
+
+ test_display(
+ &[0xf3, 0x0f, 0x6f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqu xmm3, [esp + ebx * 4 - 0x334455cc]"
+ );
+ test_display(&[0xf3, 0x0f, 0x70, 0xc0, 0x4e], "pshufhw xmm0, xmm0, 0x4e");
+ test_display(&[0xf3, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
+ test_display(
+ &[0xf3, 0x0f, 0x7f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
+ "movdqu [esp + ebx * 4 - 0x334455cc], xmm3"
+ );
+
+ test_display(&[0xf3, 0x0f, 0xc2, 0xc3, 0x08], "cmpss xmm0, xmm3, 0x8");
+ test_display(&[0xf3, 0x0f, 0xc2, 0x03, 0x08], "cmpss xmm0, [ebx], 0x8");
+}
+
+// SETLE, SETNG, ...
+
+#[test]
+fn test_mov() {
+ // test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00, 0x12, 0x34, 0x12, 0x34], "mov eax, [0x3412341200c46293]");
+ // RCT.exe 32bit version, TODO: FIX
+ test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00], "mov eax, [0xc46293]");
+ test_display(&[0xba, 0x01, 0x00, 0x00, 0x00], "mov edx, 0x1");
+ test_display(&[0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00], "mov [esp], 0x0");
+ test_display(&[0x89, 0x44, 0x24, 0x08], "mov [esp + 0x8], eax");
+ test_display(&[0x89, 0x43, 0x18], "mov [ebx + 0x18], eax");
+ test_display(&[0xc7, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00], "mov [ebx + 0x10], 0x0");
+ test_display(&[0x89, 0x4e, 0x08], "mov [esi + 0x8], ecx");
+ test_display(&[0x8b, 0x32], "mov esi, [edx]");
+ test_display(&[0x8b, 0x4c, 0x10, 0xf8], "mov ecx, [eax + edx * 1 - 0x8]");
+ test_display(&[0x89, 0x46, 0x10], "mov [esi + 0x10], eax");
+ test_display(&[0x0f, 0x43, 0xec], "cmovnb ebp, esp");
+ test_display(&[0x0f, 0xb6, 0x06], "movzx eax, byte [esi]");
+ test_display(&[0x0f, 0xb7, 0x06], "movzx eax, word [esi]");
+ test_display(&[0x89, 0x55, 0x94], "mov [ebp - 0x6c], edx");
+ test_display(&[0x65, 0x89, 0x04, 0x25, 0xa8, 0x01, 0x00, 0x00], "mov gs:[0x1a8], eax");
+ test_display(&[0x0f, 0xbe, 0x83, 0xb4, 0x00, 0x00, 0x00], "movsx eax, byte [ebx + 0xb4]");
+ test_display(&[0xf3, 0x0f, 0x6f, 0x07], "movdqu xmm0, [edi]");
+ test_display(&[0xf3, 0x0f, 0x7f, 0x45, 0x00], "movdqu [ebp], xmm0");
+}
+
+#[test]
+fn test_stack() {
+ test_display(&[0x66, 0x50], "push ax");
+}
+
+#[test]
+fn test_prefixes() {
+ test_display(&[0x66, 0x31, 0xc0], "xor ax, ax");
+ test_display(&[0x66, 0x32, 0xc0], "xor al, al");
+ test_display(&[0x66, 0x32, 0xc5], "xor al, ch");
+
+ // test that WAIT doesn't blow up, at least...
+ assert_eq!(InstDecoder::default().decode([0x9b, 0xf8].iter().cloned()).err(), Some(DecodeError::IncompleteDecoder));
+}
+
+#[test]
+fn test_control_flow() {
+ test_display(&[0x73, 0x31], "jnb 0x31");
+ test_display(&[0x72, 0x5a], "jb 0x5a");
+ test_display(&[0x0f, 0x86, 0x8b, 0x01, 0x00, 0x00], "jna 0x18b");
+ test_display(&[0x74, 0x47], "jz 0x47");
+ test_display(&[0xff, 0x15, 0x7e, 0x72, 0x24, 0x00], "call [0x24727e]");
+ test_display(&[0xff, 0x24, 0xcd, 0x70, 0xa0, 0xbc, 0x01], "jmp [ecx * 8 + 0x1bca070]");
+ test_display(&[0xff, 0xe0], "jmp eax");
+ test_display(&[0x66, 0xff, 0xe0], "jmp eax");
+ test_display(&[0x67, 0xff, 0xe0], "jmp eax");
+ test_invalid(&[0xff, 0xd8]);
+ test_display(&[0xff, 0x18], "callf [eax]");
+ test_display(&[0xc3], "ret");
+}
+
+#[test]
+fn test_test_cmp() {
+ test_display(&[0xf6, 0x05, 0x2c, 0x9b, 0xff, 0xff, 0x01], "test [0xffff9b2c], 0x1");
+ test_display(&[0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp eax, -0xfff");
+ test_display(&[0x83, 0xf8, 0xff], "cmp eax, -0x1");
+ test_display(&[0x39, 0xc6], "cmp esi, eax");
+}
+
+#[test]
+fn test_push_pop() {
+ test_display(&[0x5b], "pop ebx");
+ test_display(&[0x5e], "pop esi");
+ test_display(&[0x68, 0x7f, 0x63, 0xc4, 0x00], "push 0xc4637f");
+}
+
+#[test]
+fn test_bmi1() {
+ let bmi1 = InstDecoder::minimal().with_bmi1();
+ let no_bmi1 = InstDecoder::minimal();
+ test_display_under(&bmi1, &[0x0f, 0xbc, 0xd3], "tzcnt edx, ebx");
+ test_display_under(&no_bmi1, &[0x0f, 0xbc, 0xd3], "bsf edx, ebx");
+
+ test_display_under(&bmi1, &[0xf3, 0x0f, 0xb8, 0xc1], "popcnt eax, ecx");
+}
+
+#[test]
+fn test_bitwise() {
+ test_display_under(&InstDecoder::minimal(), &[0x0f, 0xbc, 0xd3], "bsf edx, ebx");
+ test_display(&[0x0f, 0xa3, 0xd0], "bt eax, edx");
+ test_display(&[0x0f, 0xab, 0xd0], "bts eax, edx");
+}
+
+#[test]
+fn test_misc() {
+ // TODO
+// test_display(&[0xf2, 0x0f, 0x38, 0xf0, 0xc1], "crc32 eax, cl");
+// test_display(&[0xf2, 0x0f, 0x38, 0xf1, 0xc1], "crc32 eax, ecx");
+ test_display(&[0xfe, 0x00], "inc [eax]"); // TODO: inc byte [eax]
+ test_display(&[0xfe, 0x08], "dec [eax]"); // TODO: dec byte [eax]
+ test_display(&[0xff, 0x00], "inc [eax]"); // TODO: inc dword [eax]
+ test_display(&[0xff, 0x08], "dec [eax]"); // TODO: inc qword [eax]
+ test_display(&[0xe4, 0x99], "in al, 0x99");
+ test_display(&[0xe5, 0x99], "in eax, 0x99");
+ test_display(&[0x67, 0xe5, 0x99], "in eax, 0x99");
+ test_display(&[0xe5, 0x99], "in eax, 0x99");
+ test_display(&[0xe6, 0x99], "out 0x99, al");
+ test_display(&[0xe7, 0x99], "out 0x99, eax");
+ test_display(&[0xec], "in al, dx");
+ test_display(&[0xed], "in eax, dx");
+ test_display(&[0xee], "out dx, al");
+ test_display(&[0xef], "out dx, eax");
+ test_display(&[0xcd, 0x00], "int 0x0");
+ test_display(&[0xcd, 0xff], "int 0xff");
+ test_display(&[0x9c], "pushf");
+ test_display(&[0x98], "cwde");
+ test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop cs:[eax + eax * 1]");
+ test_display(&[0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00], "nop [eax + eax * 1]");
+ test_display(&[0x8d, 0xa4, 0xc7, 0x20, 0x00, 0x00, 0x12], "lea esp, [edi + eax * 8 + 0x12000020]");
+ test_display(&[0x33, 0xc0], "xor eax, eax");
+ test_display(&[0x8d, 0x53, 0x08], "lea edx, [ebx + 0x8]");
+ test_display(&[0x31, 0xc9], "xor ecx, ecx");
+ test_display(&[0x29, 0xc8], "sub eax, ecx");
+ test_display(&[0x03, 0x0b], "add ecx, [ebx]");
+ test_display(&[0x8d, 0x0c, 0x12], "lea ecx, [edx + edx * 1]");
+ test_display(&[0xf6, 0xc2, 0x18], "test dl, 0x18");
+ test_display(&[0xf3, 0xab], "rep stos es:[edi], eax");
+ test_display(&[0xf3, 0xa5], "rep movs es:[edi], ds:[esi]");
+ test_display(&[0xf3, 0x0f, 0xbc, 0xd7], "tzcnt edx, edi");
+
+ // this is actually vmx
+ // test_invalid(&[0x66, 0x0f, 0xc7, 0x03]);
+ test_display(&[0x66, 0x0f, 0xc7, 0x33], "vmclear [ebx]");
+ test_display(&[0xf3, 0x0f, 0xc7, 0x33], "vmxon [ebx]");
+}
+
+#[test]
+#[ignore]
+// TODO also not supported at all
+fn evex() {
+ test_display(&[0x62, 0xf2, 0x7d, 0x48, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa zmm0, [eax + eax*2 + 0x40]");
+ test_display(&[0x62, 0xf2, 0x7d, 0x08, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa xmm0, [eax + eax*2 + 0x10]");
+}
+
+#[test]
+fn test_vex() {
+ fn test_instr(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_avx(), bytes, text);
+ test_display_under(&InstDecoder::default(), bytes, text);
+ test_invalid_under(&InstDecoder::minimal(), bytes);
+ }
+
+ fn test_valid(bytes: &[u8], text: &'static str) {
+ test_display_under(&InstDecoder::minimal().with_avx(), bytes, text);
+ test_display_under(&InstDecoder::default(), bytes, text);
+ test_display_under(&InstDecoder::minimal(), bytes, text);
+ }
+
+ fn test_instr_invalid(bytes: &[u8]) {
+ test_invalid_under(&InstDecoder::minimal().with_avx(), bytes);
+ test_invalid_under(&InstDecoder::default(), bytes);
+ }
+
+ test_instr(&[0xc5, 0xf8, 0x10, 0x00], "vmovups xmm0, [eax]");
+ test_instr(&[0xc5, 0xf8, 0x10, 0x01], "vmovups xmm0, [ecx]");
+ test_valid(&[0xc5, 0x78, 0x10], "lds edi, [eax + 0x10]");
+ test_instr(&[0xc5, 0xf8, 0x10, 0xcf], "vmovups xmm1, xmm7");
+ test_instr(&[0xc5, 0xf9, 0x10, 0x0f], "vmovupd xmm1, [edi]");
+ test_instr(&[0xc5, 0xfa, 0x7e, 0x10], "vmovq xmm2, [eax]");
+ test_instr(&[0xc5, 0xfc, 0x10, 0x0f], "vmovups ymm1, [edi]");
+ test_instr(&[0xc5, 0xfd, 0x10, 0x0f], "vmovupd ymm1, [edi]");
+ test_instr(&[0xc5, 0xfe, 0x10, 0x0f], "vmovss xmm1, [edi]");
+ test_instr(&[0xc5, 0xff, 0x10, 0xcf], "vmovsd xmm1, xmm0, xmm7");
+ test_instr(&[0xc5, 0xff, 0x10, 0x01], "vmovsd xmm0, [ecx]");
+ test_instr(&[0xc5, 0xf9, 0x6e, 0xc6], "vmovd xmm0, esi");
+ test_instr(&[0xc5, 0xf9, 0x6e, 0x13], "vmovd xmm2, [ebx]");
+ test_instr(&[0xc5, 0xf9, 0x7e, 0xc6], "vmovd esi, xmm0");
+ test_instr(&[0xc5, 0xf9, 0x7e, 0x13], "vmovd [ebx], xmm2");
+ test_instr_invalid(&[0xf0, 0xc5, 0xf8, 0x10, 0x00]);
+ test_valid(&[0xc4, 0x02], "les eax, [edx]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x00, 0x0f], "vpshufb xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x00, 0x0f], "vpshufb ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x00, 0xcd], "vpshufb xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x00, 0xcd], "vpshufb ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x01, 0x0f], "vphaddw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x01, 0x0f], "vphaddw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x01, 0xcd], "vphaddw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x01, 0xcd], "vphaddw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x02, 0x0f], "vphaddd xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x02, 0x0f], "vphaddd ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x02, 0xcd], "vphaddd xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x02, 0xcd], "vphaddd ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x03, 0x0f], "vphaddsw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x03, 0x0f], "vphaddsw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x03, 0xcd], "vphaddsw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x03, 0xcd], "vphaddsw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x04, 0x0f], "vphaddubsw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x04, 0x0f], "vphaddubsw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x04, 0xcd], "vphaddubsw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x04, 0xcd], "vphaddubsw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x05, 0x0f], "vphsubw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x05, 0x0f], "vphsubw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x05, 0xcd], "vphsubw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x05, 0xcd], "vphsubw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x06, 0x0f], "vphsubd xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x06, 0x0f], "vphsubd ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x06, 0xcd], "vphsubd xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x06, 0xcd], "vphsubd ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x07, 0x0f], "vphsubsw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x07, 0x0f], "vphsubsw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x07, 0xcd], "vphsubsw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x07, 0xcd], "vphsubsw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x08, 0x0f], "vpsignb xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x08, 0x0f], "vpsignb ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x08, 0xcd], "vpsignb xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x08, 0xcd], "vpsignb ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x09, 0x0f], "vpsignw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x09, 0x0f], "vpsignw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x09, 0xcd], "vpsignw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x09, 0xcd], "vpsignw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0a, 0x0f], "vpsignd xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0a, 0x0f], "vpsignd ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0a, 0xcd], "vpsignd xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0a, 0xcd], "vpsignd ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0b, 0x0f], "vpmulhrsw xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0b, 0x0f], "vpmulhrsw ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0b, 0xcd], "vpmulhrsw xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0b, 0xcd], "vpmulhrsw ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0c, 0x0f], "vpermilps xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0c, 0x0f], "vpermilps ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0c, 0xcd], "vpermilps xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0c, 0xcd], "vpermilps ymm1, ymm1, ymm5");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0d, 0x0f], "vpermilpd xmm1, xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0d, 0x0f], "vpermilpd ymm1, ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x71, 0x0d, 0xcd], "vpermilpd xmm1, xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x75, 0x0d, 0xcd], "vpermilpd ymm1, ymm1, ymm5");
+ test_instr_invalid(&[0xc4, 0xc2, 0x71, 0x0e, 0x00]);
+ test_instr(&[0xc4, 0xc2, 0x79, 0x0e, 0x0f], "vtestps xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x7d, 0x0e, 0x0f], "vtestps ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x79, 0x0e, 0xcd], "vtestps xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x7d, 0x0e, 0xcd], "vtestps ymm1, ymm5");
+ test_instr_invalid(&[0xc4, 0xc2, 0x71, 0x0f, 0x00]);
+ test_instr(&[0xc4, 0xc2, 0x79, 0x0f, 0x0f], "vtestpd xmm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x7d, 0x0f, 0x0f], "vtestpd ymm1, [edi]");
+ test_instr(&[0xc4, 0xc2, 0x79, 0x0f, 0xcd], "vtestpd xmm1, xmm5");
+ test_instr(&[0xc4, 0xc2, 0x7d, 0x0f, 0xcd], "vtestpd ymm1, ymm5");
+ test_instr(&[0xc4, 0xe2, 0x65, 0x90, 0x04, 0x51], "vpgatherdd ymm0, [ecx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xe2, 0xe5, 0x90, 0x04, 0x51], "vpgatherdq ymm0, [ecx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xe2, 0x65, 0x91, 0x04, 0x51], "vpgatherqd ymm0, [ecx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xe2, 0xe5, 0x91, 0x04, 0x51], "vpgatherqq ymm0, [ecx + ymm2 * 2], ymm3");
+ test_instr(&[0xc4, 0xc2, 0x09, 0x9d, 0xcd], "vfnmadd132ss xmm1, xmm6, xmm5"); // note xmm6, not xmm14!
+ test_instr(&[0xc4, 0xc2, 0x89, 0x9d, 0xcd], "vfnmadd132sd xmm1, xmm6, xmm5");
+// ...
+ test_instr(&[0xc4, 0xe3, 0x79, 0x14, 0xd0, 0x0a], "vpextrb eax, xmm2, 0xa");
+ test_instr(&[0xc4, 0xe3, 0x79, 0x14, 0x10, 0x0a], "vpextrb [eax], xmm2, 0xa");
+ test_instr_invalid(&[0xc4, 0xe3, 0xf9, 0x14, 0x00, 0xd0]);
+ test_instr_invalid(&[0xc4, 0xe3, 0xf9, 0x14, 0x00, 0x0a]);
+}
+
+#[test]
+fn strange_prefixing() {
+ test_display(&[0x66, 0x0f, 0x21, 0xc8], "mov eax, dr1");
+ test_display(&[0xf2, 0x0f, 0x21, 0xc8], "mov eax, dr1");
+ test_display(&[0xf3, 0x0f, 0x21, 0xc8], "mov eax, dr1");
+}
+
+#[test]
+fn prefixed_0f() {
+ test_display(&[0x0f, 0x02, 0xc0], "lar eax, ax");
+ test_display(&[0x0f, 0x03, 0xc0], "lsl eax, eax");
+ test_display(&[0x0f, 0x05], "syscall");
+ test_display(&[0x66, 0x0f, 0x05], "syscall");
+ test_display(&[0x0f, 0x06], "clts");
+ test_display(&[0xf2, 0x0f, 0x06], "clts");
+ test_display(&[0x0f, 0x07], "sysret");
+ test_display(&[0xf2, 0x0f, 0x07], "sysret");
+ test_display(&[0x0f, 0x12, 0x0f], "movlps xmm1, [edi]");
+ test_display(&[0x0f, 0x12, 0xcf], "movhlps xmm1, xmm7");
+ test_display(&[0x0f, 0x16, 0x0f], "movhps xmm1, [edi]");
+ test_display(&[0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
+ test_display(&[0x0f, 0x12, 0xc0], "movhlps xmm0, xmm0");
+ test_invalid(&[0x0f, 0x13, 0xc0]);
+ test_display(&[0x0f, 0x13, 0x00], "movlps [eax], xmm0");
+ test_display(&[0x0f, 0x14, 0x08], "unpcklps xmm1, [eax]");
+ test_display(&[0x0f, 0x15, 0x08], "unpckhps xmm1, [eax]");
+ test_display(&[0x0f, 0x16, 0x0f], "movhps xmm1, [edi]");
+ test_display(&[0x0f, 0x16, 0xc0], "movlhps xmm0, xmm0");
+ test_invalid(&[0x0f, 0x17, 0xc0]);
+ test_display(&[0x0f, 0x17, 0x00], "movhps [eax], xmm0");
+ test_invalid(&[0x0f, 0x18, 0xc0]);
+ test_display(&[0x0f, 0x18, 0x00], "prefetchnta [eax]");
+ test_display(&[0x0f, 0x18, 0x08], "prefetch0 [eax]");
+ test_display(&[0x0f, 0x18, 0x10], "prefetch1 [eax]");
+ test_display(&[0x0f, 0x18, 0x18], "prefetch2 [eax]");
+ test_display(&[0x0f, 0x18, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x19, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x1a, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x1b, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x1c, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x1d, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x1e, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x1f, 0x20], "nop [eax]");
+ test_display(&[0x0f, 0x20, 0xc8], "mov eax, cr1");
+ test_display(&[0x0f, 0x21, 0xc8], "mov eax, dr1");
+ test_display(&[0x0f, 0x22, 0xc8], "mov cr1, eax");
+ test_display(&[0x0f, 0x22, 0xcf], "mov cr1, edi");
+ test_display(&[0x0f, 0x23, 0xc8], "mov dr1, eax");
+ test_display(&[0x0f, 0x23, 0xcf], "mov dr1, edi");
+ test_display(&[0x0f, 0x30], "wrmsr");
+ test_display(&[0x0f, 0x31], "rdtsc");
+ test_display(&[0x0f, 0x32], "rdmsr");
+ test_display(&[0x0f, 0x33], "rdpmc");
+ test_display(&[0x0f, 0x34], "sysenter");
+ test_display(&[0x0f, 0x35], "sysexit");
+ test_invalid(&[0x0f, 0x36]);
+ test_display(&[0x0f, 0x37], "getsec");
+ test_display(&[0x0f, 0x60, 0x00], "punpcklbw mm0, [eax]");
+ test_display(&[0x0f, 0x60, 0xc2], "punpcklbw mm0, mm2");
+ test_display(&[0x0f, 0x61, 0x00], "punpcklwd mm0, [eax]");
+ test_display(&[0x0f, 0x61, 0xc2], "punpcklwd mm0, mm2");
+ test_display(&[0x0f, 0x62, 0x00], "punpckldq mm0, [eax]");
+ test_display(&[0x0f, 0x62, 0xc2], "punpckldq mm0, mm2");
+ test_display(&[0x0f, 0x63, 0x00], "packsswb mm0, [eax]");
+ test_display(&[0x0f, 0x63, 0xc2], "packsswb mm0, mm2");
+ test_display(&[0x0f, 0x64, 0x00], "pcmpgtb mm0, [eax]");
+ test_display(&[0x0f, 0x64, 0xc2], "pcmpgtb mm0, mm2");
+ test_display(&[0x0f, 0x65, 0x00], "pcmpgtw mm0, [eax]");
+ test_display(&[0x0f, 0x65, 0xc2], "pcmpgtw mm0, mm2");
+ test_display(&[0x0f, 0x66, 0x00], "pcmpgtd mm0, [eax]");
+ test_display(&[0x0f, 0x66, 0xc2], "pcmpgtd mm0, mm2");
+ test_display(&[0x0f, 0x67, 0x00], "packuswb mm0, [eax]");
+ test_display(&[0x0f, 0x67, 0xc2], "packuswb mm0, mm2");
+ test_display(&[0x0f, 0x68, 0x00], "punpckhbw mm0, [eax]");
+ test_display(&[0x0f, 0x68, 0xc2], "punpckhbw mm0, mm2");
+ test_display(&[0x0f, 0x69, 0x00], "punpckhwd mm0, [eax]");
+ test_display(&[0x0f, 0x69, 0xc2], "punpckhwd mm0, mm2");
+ test_display(&[0x0f, 0x6a, 0x00], "punpckhdq mm0, [eax]");
+ test_display(&[0x0f, 0x6a, 0xc2], "punpckhdq mm0, mm2");
+ test_display(&[0x0f, 0x6b, 0x00], "packssdw mm0, [eax]");
+ test_display(&[0x0f, 0x6b, 0xc2], "packssdw mm0, mm2");
+ test_invalid(&[0x0f, 0x6c]);
+ test_invalid(&[0x0f, 0x6d]);
+ test_display(&[0x0f, 0x6e, 0x00], "movd mm0, [eax]");
+ test_display(&[0x0f, 0x6e, 0xc2], "movd mm0, edx");
+ test_display(&[0x0f, 0x6f, 0x00], "movq mm0, [eax]");
+ test_display(&[0x0f, 0x6f, 0xc2], "movq mm0, mm2");
+ test_display(&[0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [eax], 0x7f");
+ test_invalid(&[0x0f, 0x71, 0x00, 0x7f]);
+ test_invalid(&[0x0f, 0x71, 0xc0, 0x7f]);
+ test_display(&[0x0f, 0x71, 0xd0, 0x7f], "psrlw mm0, 0x7f");
+ test_display(&[0x0f, 0x71, 0xe0, 0x7f], "psraw mm0, 0x7f");
+ test_display(&[0x0f, 0x71, 0xf0, 0x7f], "psllw mm0, 0x7f");
+ test_invalid(&[0x0f, 0x72, 0x00, 0x7f]);
+ test_invalid(&[0x0f, 0x72, 0xc0, 0x7f]);
+ test_display(&[0x0f, 0x72, 0xd0, 0x7f], "psrld mm0, 0x7f");
+ test_display(&[0x0f, 0x72, 0xe0, 0x7f], "psrad mm0, 0x7f");
+ test_display(&[0x0f, 0x72, 0xf0, 0x7f], "pslld mm0, 0x7f");
+ test_invalid(&[0x0f, 0x73, 0x00, 0x7f]);
+ test_invalid(&[0x0f, 0x73, 0xc0, 0x7f]);
+ test_display(&[0x0f, 0x73, 0xd0, 0x7f], "psrlq mm0, 0x7f");
+ test_invalid(&[0x0f, 0x73, 0xe0, 0x7f]);
+ test_display(&[0x0f, 0x73, 0xf0, 0x7f], "psllq mm0, 0x7f");
+ test_display(&[0x0f, 0xa0], "push fs");
+ test_display(&[0x0f, 0xa1], "pop fs");
+ test_display(&[0x0f, 0xa2], "cpuid");
+ test_display(&[0x0f, 0xa4, 0xc0, 0x11], "shld eax, eax, 0x11");
+ test_display(&[0x66, 0x0f, 0xa4, 0xcf, 0x11], "shld di, cx, 0x11");
+ test_display(&[0x0f, 0xa5, 0xc0], "shld eax, eax, cl");
+ test_display(&[0x0f, 0xa5, 0xc9], "shld ecx, ecx, cl");
+}
+
+#[test]
+fn prefixed_660f() {
+ test_display(&[0x66, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
+ test_display(&[0xf2, 0x66, 0x66, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
+}
+
+#[test]
+fn prefixed_f20f() {
+ test_display(&[0xf2, 0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
+ test_display(&[0x66, 0xf2, 0x66, 0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
+}
+
+#[test]
+fn prefixed_f30f() {
+ test_display(&[0xf3, 0x0f, 0x16, 0xcf], "movshdup xmm1, xmm7");
+}
+
+#[test]
+fn only_32bit() {
+ test_display(&[0x40], "inc eax");
+ test_display(&[0x41], "inc ecx");
+ test_display(&[0x47], "inc edi");
+ test_display(&[0x48], "dec eax");
+ test_display(&[0x4f], "dec edi");
+
+ test_display(&[0xa0, 0xc0, 0xb0, 0xa0, 0x90], "mov al, [0x90a0b0c0]");
+ test_display(&[0x67, 0xa0, 0xc0, 0xb0], "mov al, [0xb0c0]");
+ test_display(&[0x67, 0xa1, 0xc0, 0xb0], "mov eax, [0xb0c0]");
+ test_display(&[0x66, 0x67, 0xa1, 0xc0, 0xb0], "mov ax, [0xb0c0]");
+}
diff --git a/test/protected_mode/regspec.rs b/test/protected_mode/regspec.rs
new file mode 100644
index 0000000..bd996cc
--- /dev/null
+++ b/test/protected_mode/regspec.rs
@@ -0,0 +1,20 @@
+use yaxpeax_x86::protected_mode::RegSpec;
+use std::collections::{BTreeMap, HashMap};
+
+#[test]
+fn test_ord() {
+ let _: BTreeMap<RegSpec, u64> = BTreeMap::new();
+}
+
+#[test]
+fn test_hash() {
+ let _: HashMap<RegSpec, u64> = HashMap::new();
+}
+
+#[test]
+fn test_labels() {
+ assert_eq!(RegSpec::eip().name(), "eip");
+ assert_eq!(RegSpec::ebp().name(), "ebp");
+ assert_eq!(RegSpec::gs().name(), "gs");
+ assert_eq!(RegSpec::al().name(), "al");
+}
diff --git a/test/test.rs b/test/test.rs
index 2f7f779..f1a4129 100644
--- a/test/test.rs
+++ b/test/test.rs
@@ -1,1097 +1,5 @@
extern crate yaxpeax_arch;
extern crate yaxpeax_x86;
-mod regspec;
-
-use std::fmt::Write;
-
-use yaxpeax_arch::{Decoder, LengthedInstruction};
-use yaxpeax_x86::long_mode::{DecodeError, InstDecoder, Opcode};
-
-fn test_invalid(data: &[u8]) {
- test_invalid_under(&InstDecoder::default(), data);
-}
-
-fn test_invalid_under(decoder: &InstDecoder, data: &[u8]) {
- if let Ok(inst) = decoder.decode(data.into_iter().cloned()) {
- assert_eq!(inst.opcode, Opcode::Invalid, "decoded {:?} from {:02x?} under decoder {}", inst.opcode, data, decoder);
- } else {
- // this is fine
- }
-}
-
-fn test_display(data: &[u8], expected: &'static str) {
- test_display_under(&InstDecoder::default(), data, expected);
-}
-
-fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str) {
- let mut hex = String::new();
- for b in data {
- write!(hex, "{:02x}", b).unwrap();
- }
- match decoder.decode(data.into_iter().map(|x| *x)) {
- Ok(instr) => {
- let text = format!("{}", instr);
- assert!(
- text == expected,
- "display error for {}:\n decoded: {:?} under decoder {}\n displayed: {}\n expected: {}\n",
- hex,
- instr,
- decoder,
- text,
- expected
- );
- // while we're at it, test that the instruction is as long, and no longer, than its
- // input
- assert_eq!(instr.len() as usize, data.len(), "instruction length is incorrect, wanted instruction {}", expected);
- },
- Err(e) => {
- assert!(false, "decode error ({}) for {} under decoder {}:\n expected: {}\n", e, hex, decoder, expected);
- }
- }
-}
-
-#[test]
-fn test_mmx() {
- test_display(&[0x4f, 0x0f, 0x7e, 0xcf], "movd r15, mm1");
- test_display(&[0x41, 0x0f, 0x7e, 0xcf], "movd r15d, mm1");
- test_display(&[0x4f, 0x0f, 0x7f, 0xcf], "movq mm7, mm1");
- test_display(&[0x4f, 0x0f, 0x7f, 0x0f], "movq [r15], mm1");
- test_display(&[0x0f, 0xc4, 0xc0, 0x14], "pinsrw mm0, eax, 0x14");
- test_display(&[0x4f, 0x0f, 0xc4, 0xc0, 0x14], "pinsrw mm0, r8d, 0x14");
- test_display(&[0x4f, 0x0f, 0xc4, 0x00, 0x14], "pinsrw mm0, [r8], 0x14");
- test_display(&[0x4f, 0x0f, 0xd1, 0xcf], "psrlw mm1, mm7");
- test_display(&[0x4f, 0x0f, 0xd1, 0x00], "psrlw mm0, [r8]");
- test_invalid(&[0x4f, 0x0f, 0xd7, 0x00]);
- test_display(&[0x4f, 0x0f, 0xd7, 0xcf], "pmovmskb r9d, mm7");
-}
-
-#[test]
-fn test_cvt() {
- test_display(&[0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm7");
- test_display(&[0x48, 0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm7");
- test_display(&[0x4f, 0x0f, 0x2c, 0xcf], "cvttps2pi mm1, xmm15");
- test_display(&[0x4f, 0x0f, 0x2a, 0xcf], "cvtpi2ps xmm9, mm7");
- test_display(&[0x4f, 0x0f, 0x2a, 0x00], "cvtpi2ps xmm8, [r8]");
- test_display(&[0x4f, 0x66, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm1, mm7");
- test_display(&[0x66, 0x4f, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm9, mm7");
- test_display(&[0x4f, 0xf3, 0x0f, 0x2a, 0xcf], "cvtsi2ss xmm1, edi");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0xcf], "cvtsi2ss xmm9, r15");
- test_display(&[0x4f, 0xf2, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm1, edi");
- test_display(&[0xf2, 0x4f, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm9, r15");
- test_display(&[0x4f, 0xf2, 0x0f, 0x2a, 0x00], "cvtsi2sd xmm0, [rax]");
- test_display(&[0xf2, 0x4f, 0x0f, 0x2a, 0x00], "cvtsi2sd xmm8, [r8]");
- test_display(&[0x4f, 0xf3, 0x0f, 0x2a, 0x00], "cvtsi2ss xmm0, [rax]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0x00], "cvtsi2ss xmm8, [r8]");
- test_display(&[0x4f, 0x66, 0x0f, 0x2a, 0x00], "cvtpi2pd xmm0, [rax]");
- test_display(&[0x66, 0x4f, 0x0f, 0x2a, 0x00], "cvtpi2pd xmm8, [r8]");
-}
-
-#[test]
-fn test_aesni() {
- fn test_instr(bytes: &[u8], text: &'static str) {
- test_display_under(&InstDecoder::minimal().with_aesni(), bytes, text);
- test_display_under(&InstDecoder::default(), bytes, text);
- test_invalid_under(&InstDecoder::minimal(), bytes);
- }
-
- test_instr(&[0x66, 0x0f, 0x38, 0xdb, 0x0f], "aesimc xmm1, [rdi]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdb, 0xcf], "aesimc xmm9, xmm15");
-
- test_instr(&[0x66, 0x0f, 0x38, 0xdc, 0x0f], "aesenc xmm1, [rdi]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdc, 0xcf], "aesenc xmm9, xmm15");
-
- test_instr(&[0x66, 0x0f, 0x38, 0xdd, 0x0f], "aesenclast xmm1, [rdi]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdd, 0xcf], "aesenclast xmm9, xmm15");
-
- test_instr(&[0x66, 0x0f, 0x38, 0xde, 0x0f], "aesdec xmm1, [rdi]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xde, 0xcf], "aesdec xmm9, xmm15");
-
- test_instr(&[0x66, 0x0f, 0x38, 0xdf, 0x0f], "aesdeclast xmm1, [rdi]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x38, 0xdf, 0xcf], "aesdeclast xmm9, xmm15");
-
- test_instr(&[0x66, 0x0f, 0x3a, 0xdf, 0x0f, 0xaa], "aeskeygenassist xmm1, [rdi], 0xaa");
- test_instr(&[0x66, 0x4f, 0x0f, 0x3a, 0xdf, 0xcf, 0xaa], "aeskeygenassist xmm9, xmm15, 0xaa");
-}
-
-#[test]
-fn test_sse2() {
- fn test_instr(bytes: &[u8], text: &'static str) {
- // sse and sse2 are part of amd64, so x86_64, meaning even the minimal decoder must support
- // them.
- test_display_under(&InstDecoder::minimal(), bytes, text);
- }
-
- test_instr(&[0xf2, 0x0f, 0x10, 0x0c, 0xc7], "movsd xmm1, [rdi + rax * 8]");
- test_instr(&[0xf2, 0x0f, 0x11, 0x0c, 0xc7], "movsd [rdi + rax * 8], xmm1");
- test_instr(&[0x66, 0x0f, 0x11, 0x0c, 0xc7], "movupd [rdi + rax * 8], xmm1");
- test_instr(&[0x66, 0x4f, 0x0f, 0x12, 0xc3], "movhlps xmm8, xmm11"); // reg-reg form is movhlps
- test_instr(&[0x66, 0x4f, 0x0f, 0x12, 0x03], "movlpd xmm8, [r11]"); // reg-mem is movlpd
- test_instr(&[0x66, 0x4f, 0x0f, 0x13, 0x03], "movlpd [r11], xmm8");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x13, 0xc3]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x14, 0x03], "unpcklpd xmm8, [r11]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x14, 0xc3], "unpcklpd xmm8, xmm11");
- test_instr(&[0x66, 0x4f, 0x0f, 0x15, 0x03], "unpckhpd xmm8, [r11]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x15, 0xc3], "unpckhpd xmm8, xmm11");
- test_instr(&[0x66, 0x4f, 0x0f, 0x16, 0x03], "movhpd xmm8, [r11]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x16, 0xc3], "movlhps xmm8, xmm11");
- test_instr(&[0x66, 0x4f, 0x0f, 0x17, 0x03], "movhpd [r11], xmm8");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x17, 0xc3]);
-
- test_instr(&[0x66, 0x4f, 0x0f, 0x28, 0xd0], "movapd xmm10, xmm8");
- test_instr(&[0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8]");
-
- test_instr(&[0x66, 0x4f, 0x0f, 0x2a, 0xcf], "cvtpi2pd xmm9, mm7");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2a, 0x0f], "cvtpi2pd xmm9, [r15]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x2a, 0xcf], "cvtsi2sd xmm9, r15");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x2a, 0x0f], "cvtsi2sd xmm9, [r15]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2b, 0x0f], "movntpd [r15], xmm9");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2c, 0xcf], "cvttpd2pi mm1, xmm15");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2c, 0x0f], "cvttpd2pi mm1, [r15]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x2c, 0xcf], "cvttsd2si xmm9, xmm15");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x2c, 0x0f], "cvttsd2si xmm9, [r15]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2d, 0xcf], "cvtpd2pi mm1, xmm15");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2d, 0x0f], "cvtpd2pi mm1, [r15]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x2d, 0xcf], "cvtsd2si xmm9, xmm15");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x2d, 0x0f], "cvtsd2si xmm9, [r15]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2e, 0xcf], "ucomisd xmm9, xmm15");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2e, 0x0f], "ucomisd xmm9, [r15]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2f, 0xcf], "comisd xmm9, xmm15");
- test_instr(&[0x66, 0x4f, 0x0f, 0x2f, 0x0f], "comisd xmm9, [r15]");
-
- /*
- * .... 660f38
- * .... 660f7f
- */
-
- test_invalid(&[0x66, 0x4f, 0x0f, 0x50, 0x01]);
- 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_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]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x57, 0x01], "xorpd xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x58, 0x01], "addpd xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x58, 0x01], "addsd xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x59, 0x01], "mulpd xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x59, 0x01], "mulsd xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x5a, 0x01], "cvtpd2ps xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x5a, 0x01], "cvtsd2ss xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x5b, 0x01], "cvtps2dq xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x5c, 0x01], "subpd xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x5c, 0x01], "subsd xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x5d, 0x01], "minpd xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x5d, 0x01], "minsd xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x5e, 0x01], "divpd xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x5e, 0x01], "divsd xmm8, [r9]");
- test_instr(&[0x66, 0x4f, 0x0f, 0x5f, 0x01], "maxpd xmm8, [r9]");
- test_instr(&[0xf2, 0x4f, 0x0f, 0x5f, 0x01], "maxsd xmm8, [r9]");
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x60, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpcklbw xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x61, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpcklwd xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x62, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpckldq xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x63, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "packsswb xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x64, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "pcmpgtb xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x65, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "pcmpgtw xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x66, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "pcmpgtd xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x67, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "packuswb xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x68, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpckhbw xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x69, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpckhwd xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x6a, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpckhdq xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x6b, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "packssdw xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x6c, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpcklqdq xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x6d, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "punpckhqdq xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- // TODO: this needs to be clear that the operand is `dword`
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x6e, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "movq xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x6f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "movdqa xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
-
- test_instr(&[0x66, 0x48, 0x0f, 0x6e, 0xc0], "movq xmm0, rax");
- test_instr(&[0x66, 0x0f, 0x70, 0xc0, 0x4e], "pshufd xmm0, xmm0, 0x4e");
- test_instr(&[0xf2, 0x0f, 0x70, 0xc0, 0x4e], "pshuflw xmm0, xmm0, 0x4e");
- test_instr(&[0xf3, 0x0f, 0x70, 0xc0, 0x4e], "pshufhw xmm0, xmm0, 0x4e");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x71, 0x10, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x71, 0xd0, 0x8f], "psrlw xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x71, 0x20, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x71, 0xe0, 0x8f], "psraw xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x71, 0x30, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x71, 0xf0, 0x8f], "psllw xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x72, 0x10, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x72, 0xd0, 0x8f], "psrld xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x72, 0x20, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x72, 0xe0, 0x8f], "psrad xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x72, 0x30, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x72, 0xf0, 0x8f], "pslld xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x10, 0x8f]);
- test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x18, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xd0, 0x8f], "psrlq xmm0, 0x8f");
- test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xd8, 0x8f], "psrldq xmm0, 0x8f");
- test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x30, 0x8f]);
- test_invalid(&[0x66, 0x4f, 0x0f, 0x73, 0x38, 0x8f]);
- test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xf0, 0x8f], "psllq xmm0, 0x8f");
- test_instr(&[0x66, 0x4f, 0x0f, 0x73, 0xf8, 0x8f], "pslldq xmm0, 0x8f");
- test_instr(&[0x66, 0x0f, 0x7e, 0xc1], "movd ecx, xmm0");
- test_instr(&[0x66, 0x48, 0x0f, 0x7e, 0xc1], "movq rcx, xmm0");
- test_instr(&[0x66, 0x48, 0x0f, 0x7e, 0x01], "movd [rcx], xmm0");
- test_instr(&[0x66, 0x4f, 0x0f, 0x7e, 0xc1], "movq r9, xmm8");
- test_instr(
- &[0x66, 0x4f, 0x0f, 0x7f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "movdqa [r12 + r11 * 4 - 0x334455cc], xmm11"
- );
-
- test_instr(&[0x66, 0x0f, 0xc2, 0xc3, 0x08], "cmppd xmm0, xmm3, 0x8");
- test_instr(&[0x66, 0x4f, 0x0f, 0xc2, 0xc3, 0x08], "cmppd xmm8, xmm11, 0x8");
- test_instr(&[0x66, 0x4f, 0x0f, 0xc2, 0x03, 0x08], "cmppd xmm8, [r11], 0x8");
- test_instr(&[0xf2, 0x0f, 0xc2, 0xc3, 0x08], "cmpsd xmm0, xmm3, 0x8");
- test_instr(&[0xf2, 0x4f, 0x0f, 0xc2, 0xc3, 0x08], "cmpsd xmm8, xmm11, 0x8");
- test_instr(&[0xf2, 0x4f, 0x0f, 0xc2, 0x03, 0x08], "cmpsd xmm8, [r11], 0x8");
-
- test_instr(&[0x66, 0x0f, 0xc4, 0xc3, 0x08], "pinsrw xmm0, ebx, 0x8");
- test_instr(&[0x66, 0x4f, 0x0f, 0xc4, 0xc3, 0x08], "pinsrw xmm8, r11d, 0x8");
-
- test_instr(&[0x66, 0x0f, 0xc4, 0x03, 0x08], "pinsrw xmm0, [rbx], 0x8");
- test_instr(&[0x66, 0x4f, 0x0f, 0xc4, 0x03, 0x08], "pinsrw xmm8, [r11], 0x8");
-
-// test_instr(&[0x66, 0x0f, 0xc5, 0xc3, 0x08], "pextrw eax, xmm3, 0x8");
-// test_instr(&[0x66, 0x4f, 0x0f, 0xc5, 0xc3, 0x08], "pextrw r8d, xmm11, 0x8");
-// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x03, 0x08]);
-// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x40, 0x08]);
-// test_instr_invalid(&[0x66, 0x0f, 0xc5, 0x80, 0x08]);
-
- test_instr(&[0x66, 0x4f, 0x0f, 0xc6, 0x03, 0x08], "shufpd xmm8, [r11], 0x8");
- test_instr(&[0x66, 0x0f, 0xc6, 0x03, 0x08], "shufpd xmm0, [rbx], 0x8");
- test_instr(&[0x66, 0x0f, 0xc6, 0xc3, 0x08], "shufpd xmm0, xmm3, 0x8");
- test_instr(&[0x66, 0x0f, 0xd1, 0xc1], "psrlw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd1, 0x01], "psrlw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xd2, 0xc1], "psrld xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd2, 0x01], "psrld xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xd3, 0xc1], "psrlq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd3, 0x01], "psrlq xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xd4, 0xc1], "paddq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd4, 0x01], "paddq xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xd5, 0xc1], "pmullw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd5, 0x01], "pmullw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xd6, 0xc1], "movq xmm1, xmm0");
- test_instr(&[0x66, 0x0f, 0xd6, 0x01], "movq [rcx], xmm0");
- test_invalid(&[0xf3, 0x4f, 0x0f, 0xd6, 0x03]);
- test_instr(&[0xf3, 0x4f, 0x0f, 0xd6, 0xc3], "movq2dq xmm8, mm3");
- test_instr(&[0xf2, 0x4f, 0x0f, 0xd6, 0xc3], "movdq2q mm0, xmm11");
- test_instr(&[0x66, 0x0f, 0xd7, 0xc1], "pmovmskb eax, xmm1");
- test_instr(&[0x66, 0x4f, 0x0f, 0xd7, 0xc1], "pmovmskb r8d, xmm9");
- test_invalid(&[0x66, 0x0f, 0xd7, 0x01]);
- test_instr(&[0x66, 0x0f, 0xd8, 0xc1], "psubusb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd8, 0x01], "psubusb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xd9, 0xc1], "psubusw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xd9, 0x01], "psubusw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xda, 0xc1], "pminub xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xda, 0x01], "pminub xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xdb, 0xc1], "pand xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xdb, 0x01], "pand xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xdc, 0xc1], "paddusb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xdc, 0x01], "paddusb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xdd, 0xc1], "paddusw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xdd, 0x01], "paddusw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xde, 0xc1], "pmaxub xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xde, 0x01], "pmaxub xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xdf, 0xc1], "pandn xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xdf, 0x01], "pandn xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe0, 0xc1], "pavgb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe0, 0x01], "pavgb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe1, 0xc1], "psraw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe1, 0x01], "psraw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe2, 0xc1], "psrad xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe2, 0x01], "psrad xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe3, 0xc1], "pavgw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe3, 0x01], "pavgw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe4, 0xc1], "pmulhuw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe4, 0x01], "pmulhuw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe5, 0xc1], "pmulhw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe5, 0x01], "pmulhw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe6, 0xc1], "cvttpd2dq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe6, 0x01], "cvttpd2dq xmm0, [rcx]");
- test_invalid(&[0x66, 0x0f, 0xe7, 0xc1]);
- test_instr(&[0x66, 0x0f, 0xe7, 0x01], "movntdq [rcx], xmm0");
- test_instr(&[0x66, 0x0f, 0xe8, 0xc1], "psubsb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe8, 0x01], "psubsb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xe9, 0xc1], "psubsw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xe9, 0x01], "psubsw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xea, 0xc1], "pminsw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xea, 0x01], "pminsw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xeb, 0xc3], "por xmm0, xmm3");
- test_instr(&[0x66, 0x0f, 0xeb, 0xc4], "por xmm0, xmm4");
- test_instr(&[0x66, 0x0f, 0xeb, 0xd3], "por xmm2, xmm3");
- test_instr(&[0x66, 0x0f, 0xeb, 0x12], "por xmm2, [rdx]");
- test_instr(&[0x66, 0x0f, 0xeb, 0xc1], "por xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xeb, 0x01], "por xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xec, 0xc1], "paddsb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xec, 0x01], "paddsb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xed, 0xc1], "paddsw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xed, 0x01], "paddsw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xee, 0xc1], "pmaxsw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xee, 0x01], "pmaxsw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xef, 0xc1], "pxor xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xef, 0x01], "pxor xmm0, [rcx]");
- test_invalid(&[0x66, 0x0f, 0xf0, 0xc1]);
- test_invalid(&[0x66, 0x0f, 0xf0, 0x01]);
- test_instr(&[0x66, 0x0f, 0xf1, 0xc1], "psllw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf1, 0x01], "psllw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf2, 0xc1], "pslld xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf2, 0x01], "pslld xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf3, 0xc1], "psllq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf3, 0x01], "psllq xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf4, 0xc1], "pmuludq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf4, 0x01], "pmuludq xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf5, 0xc1], "pmaddwd xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf5, 0x01], "pmaddwd xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf6, 0xc1], "psadbw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf6, 0x01], "psadbw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf7, 0xc1], "maskmovdqu xmm0, xmm1");
- test_invalid(&[0x66, 0x0f, 0xf7, 0x01]);
- test_instr(&[0x66, 0x0f, 0xf8, 0xc1], "psubb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf8, 0x01], "psubb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xf9, 0xc1], "psubw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xf9, 0x01], "psubw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xfa, 0xc1], "psubd xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xfa, 0x01], "psubd xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xfb, 0xc1], "psubq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xfb, 0x01], "psubq xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xfc, 0xc1], "paddb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xfc, 0x01], "paddb xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xfd, 0xc1], "paddw xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xfd, 0x01], "paddw xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xfe, 0xc1], "paddd xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xfe, 0x01], "paddd xmm0, [rcx]");
- test_instr(&[0x66, 0x0f, 0xff, 0xc1], "paddq xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0xff, 0x01], "paddq xmm0, [rcx]");
-
- test_instr(&[0x66, 0x0f, 0x74, 0xc1], "pcmpeqb xmm0, xmm1");
- test_instr(&[0x66, 0x0f, 0x74, 0x12], "pcmpeqb xmm2, [rdx]");
- test_instr(&[0x66, 0x0f, 0xf8, 0xc8], "psubb xmm1, xmm0");
- test_instr(&[0x66, 0x0f, 0xf8, 0xd0], "psubb xmm2, xmm0");
- test_instr(&[0x66, 0x0f, 0xf8, 0x12], "psubb xmm2, [rdx]");
-}
-
-#[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"
- test_display(&[0x0f, 0x01, 0x38], "invlpg [rax]");
- test_display(&[0x0f, 0x01, 0x3f], "invlpg [rdi]");
- test_display(&[0x0f, 0x01, 0x40, 0xff], "sgdt [rax - 0x1]");
- test_display(&[0x0f, 0x01, 0x41, 0xff], "sgdt [rcx - 0x1]");
- test_display(&[0x0f, 0x01, 0x49, 0xff], "sidt [rcx - 0x1]");
- test_display(&[0x0f, 0x01, 0x51, 0xff], "lgdt [rcx - 0x1]");
- test_display(&[0x0f, 0x01, 0x59, 0xff], "lidt [rcx - 0x1]");
- test_display(&[0x0f, 0x01, 0x61, 0xff], "smsw [rcx - 0x1]");
- test_display(&[0x0f, 0x01, 0xc0], "enclv");
- test_display(&[0x0f, 0x01, 0xc1], "vmcall");
- test_display(&[0x0f, 0x01, 0xc2], "vmlaunch");
- test_display(&[0x0f, 0x01, 0xc3], "vmresume");
- test_display(&[0x0f, 0x01, 0xc4], "vmxoff");
- test_invalid(&[0x0f, 0x01, 0xc5]);
- test_invalid(&[0x0f, 0x01, 0xc6]);
- test_invalid(&[0x0f, 0x01, 0xc7]);
- test_display(&[0x0f, 0x01, 0xc8], "monitor");
- test_display(&[0x0f, 0x01, 0xc9], "mwait");
- test_display(&[0x0f, 0x01, 0xca], "clac");
- test_display(&[0x0f, 0x01, 0xcb], "stac");
- test_display(&[0x0f, 0x01, 0xcf], "encls");
- test_display(&[0x0f, 0x01, 0xd0], "xgetbv");
- test_display(&[0x0f, 0x01, 0xd1], "xsetbv");
- test_invalid(&[0x0f, 0x01, 0xd2]);
- test_invalid(&[0x0f, 0x01, 0xd3]);
- test_display(&[0x0f, 0x01, 0xd4], "vmfunc");
- test_display(&[0x0f, 0x01, 0xd5], "xend");
- test_display(&[0x0f, 0x01, 0xd6], "xtest");
- test_display(&[0x0f, 0x01, 0xd7], "enclu");
- test_invalid(&[0x0f, 0x01, 0xd8]);
- test_invalid(&[0x0f, 0x01, 0xd9]);
- test_invalid(&[0x0f, 0x01, 0xda]);
- test_invalid(&[0x0f, 0x01, 0xdb]);
- test_invalid(&[0x0f, 0x01, 0xdc]);
- test_invalid(&[0x0f, 0x01, 0xdd]);
- test_invalid(&[0x0f, 0x01, 0xde]);
- test_invalid(&[0x0f, 0x01, 0xdf]);
- test_display(&[0x0f, 0x01, 0xee], "rdpkru");
- test_display(&[0x0f, 0x01, 0xef], "wrpkru");
- test_display(&[0x0f, 0x01, 0xf8], "swapgs");
- test_display(&[0x0f, 0x01, 0xf9], "rdtscp");
-}
-
-#[test]
-fn test_0fae() {
- let intel = InstDecoder::minimal().with_intel_quirks();
- let amd = InstDecoder::minimal().with_amd_quirks();
- let default = InstDecoder::default();
- let minimal = InstDecoder::minimal();
- // drawn heavily from "Table A-6. Opcode Extensions for One- and Two-byte Opcodes by Group
- // Number"
- test_display(&[0x0f, 0xae, 0x04, 0x4f], "fxsave [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x0c, 0x4f], "fxrstor [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x14, 0x4f], "ldmxcsr [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x1c, 0x4f], "stmxcsr [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x24, 0x4f], "xsave [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x2c, 0x4f], "xrstor [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x34, 0x4f], "xsaveopt [rdi + rcx * 2]");
- test_display(&[0x0f, 0xae, 0x3c, 0x4f], "clflush [rdi + rcx * 2]");
-
- for (modrm, text) in &[(0xe8u8, "lfence"), (0xf0u8, "mfence"), (0xf8u8, "sfence")] {
- test_display_under(&intel, &[0x0f, 0xae, *modrm], text);
- test_display_under(&amd, &[0x0f, 0xae, *modrm], text);
- test_display_under(&default, &[0x0f, 0xae, *modrm], text);
- test_display_under(&minimal, &[0x0f, 0xae, *modrm], text);
- // it turns out intel and amd accept m != 0 for {l,m,s}fence:
- // from intel:
- // ```
- // Specification of the instruction's opcode above indicates a ModR/M byte of F0. For this
- // instruction, the processor ignores the r/m field of the ModR/M byte. Thus, MFENCE is encoded
- // by any opcode of the form 0F AE Fx, where x is in the range 0-7.
- // ```
- // whereas amd does not discuss the r/m field at all. at least as of zen, amd also accepts
- // these encodings.
- for m in 1u8..8u8 {
- test_display_under(&intel, &[0x0f, 0xae, modrm | m], text);
- test_display_under(&amd, &[0x0f, 0xae, modrm | m], text);
- test_display_under(&default, &[0x0f, 0xae, modrm | m], text);
- test_invalid_under(&minimal, &[0x0f, 0xae, modrm | m]);
- }
- }
-}
-
-#[test]
-fn test_system() {
- test_display(&[0x66, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8]");
- test_display(&[0x67, 0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8d]");
- test_display(&[0x4f, 0x0f, 0xb2, 0x00], "lss r8, [r8]");
- test_display(&[0x45, 0x0f, 0x22, 0xc8], "mov cr9, r8");
- test_display(&[0x45, 0x0f, 0x20, 0xc8], "mov r8, cr9");
- test_display(&[0x40, 0x0f, 0x22, 0xc8], "mov cr1, rax");
- test_display(&[0x0f, 0x22, 0xc8], "mov cr1, rax");
- test_display(&[0x44, 0x0f, 0x22, 0xcf], "mov cr9, rdi");
- test_display(&[0x0f, 0x22, 0xcf], "mov cr1, rdi");
- test_display(&[0x0f, 0x20, 0xc8], "mov rax, cr1");
-
- test_display(&[0x45, 0x0f, 0x23, 0xc8], "mov dr9, r8");
- test_display(&[0x45, 0x0f, 0x21, 0xc8], "mov r8, dr9");
- test_display(&[0x40, 0x0f, 0x23, 0xc8], "mov dr1, rax");
- test_display(&[0x0f, 0x23, 0xc8], "mov dr1, rax");
- test_display(&[0x0f, 0x21, 0xc8], "mov rax, dr1");
-}
-
-#[test]
-fn test_arithmetic() {
- test_display(&[0x81, 0xec, 0x10, 0x03, 0x00, 0x00], "sub esp, 0x310");
- test_display(&[0x0f, 0xaf, 0xc2], "imul eax, edx");
- test_display(&[0x4b, 0x69, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65], "imul rax, [r11 + 0x6f], 0x656c706d");
- test_display(&[0x66, 0x0f, 0xaf, 0xd1], "imul dx, cx");
- test_display(&[0x4b, 0x6b, 0x43, 0x6f, 0x6d], "imul al, [r11 + 0x6f], 0x6d");
- test_display(&[0x4f, 0x4e, 0x00, 0xcc], "add spl, r9b");
-}
-
-#[test]
-#[allow(non_snake_case)]
-fn test_E_decode() {
- test_display(&[0xff, 0x75, 0xb8], "push [rbp - 0x48]");
- test_display(&[0xff, 0x75, 0x08], "push [rbp + 0x8]");
-}
-
-#[test]
-fn test_sse() {
- test_display(&[0xf3, 0x0f, 0x10, 0x0c, 0xc7], "movss xmm1, [rdi + rax * 8]");
- test_display(&[0xf3, 0x0f, 0x11, 0x0c, 0xc7], "movss [rdi + rax * 8], xmm1");
- test_display(&[0x4f, 0x0f, 0x28, 0x00], "movaps xmm8, [r8]");
- test_display(&[0x4f, 0x0f, 0x29, 0x00], "movaps [r8], xmm8");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0xc1], "cvtsi2ss xmm8, r9");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2a, 0x01], "cvtsi2ss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x2b, 0x00], "movntps [r8], xmm8");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2c, 0xc1], "cvttss2si r8, xmm9");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2c, 0x01], "cvttss2si r8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2d, 0xc1], "cvtss2si r8, xmm9");
- test_display(&[0xf3, 0x4f, 0x0f, 0x2d, 0x01], "cvtss2si r8, [r9]");
- test_display(&[0x4f, 0x0f, 0x2e, 0x00], "ucomiss xmm8, [r8]");
- test_display(&[0x4f, 0x0f, 0x2f, 0x00], "comiss xmm8, [r8]");
- test_display(&[0x0f, 0x28, 0xd0], "movaps xmm2, xmm0");
- test_display(&[0x66, 0x0f, 0x28, 0xd0], "movapd xmm2, xmm0");
- test_display(&[0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [rax]");
- test_display(&[0x4f, 0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [rax]");
- test_display(&[0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8]");
- test_display(&[0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8]");
- test_display(&[0x67, 0x4f, 0x66, 0x0f, 0x28, 0x00], "movapd xmm0, [eax]");
- test_display(&[0x67, 0x66, 0x4f, 0x0f, 0x28, 0x00], "movapd xmm8, [r8d]");
- test_display(&[0x66, 0x0f, 0x29, 0x00], "movapd [rax], xmm0");
- test_invalid(&[0x4f, 0x0f, 0x50, 0x00]);
- test_display(&[0x4f, 0x0f, 0x50, 0xc1], "movmskps r8d, xmm9");
- test_display(&[0x4f, 0x0f, 0x51, 0x01], "sqrtps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x51, 0x01], "sqrtss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x52, 0x01], "rsqrtps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x52, 0x01], "rsqrtss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x53, 0x01], "rcpps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x53, 0x01], "rcpss xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x53, 0xc1], "rcpss xmm8, xmm9");
- test_display(&[0x4f, 0x0f, 0x54, 0x01], "andps xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x55, 0x01], "andnps xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x56, 0x01], "orps xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x57, 0x01], "xorps xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x58, 0x01], "addps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x58, 0x01], "addss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x59, 0x01], "mulps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x59, 0x01], "mulss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x5a, 0x01], "cvtps2pd xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x5a, 0x01], "cvtss2sd xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x5b, 0x01], "cvtdq2ps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x5b, 0x01], "cvttps2dq xmm8, [r9]");
- test_display(&[0x67, 0x4f, 0x0f, 0x5b, 0x01], "cvtdq2ps xmm8, [r9d]");
- test_display(&[0x4f, 0x0f, 0x5c, 0x01], "subps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x5c, 0x01], "subss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x5d, 0x01], "minps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x5d, 0x01], "minss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x5e, 0x01], "divps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x5e, 0x01], "divss xmm8, [r9]");
- test_display(&[0x4f, 0x0f, 0x5f, 0x01], "maxps xmm8, [r9]");
- test_display(&[0xf3, 0x4f, 0x0f, 0x5f, 0x01], "maxss xmm8, [r9]");
-
- test_display(&[0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [rax], 0x7f");
- test_display(&[0x4f, 0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [r8], 0x7f");
-
- test_display(&[0x66, 0x0f, 0xef, 0xc0], "pxor xmm0, xmm0");
- test_display(&[0x66, 0x4f, 0x0f, 0xef, 0xc0], "pxor xmm8, xmm8");
- test_display(&[0xf2, 0x0f, 0x10, 0x0c, 0xc6], "movsd xmm1, [rsi + rax * 8]");
- test_display(&[0xf3, 0x0f, 0x10, 0x04, 0x86], "movss xmm0, [rsi + rax * 4]");
- test_display(&[0xf2, 0x0f, 0x59, 0xc8], "mulsd xmm1, xmm0");
- test_display(&[0xf3, 0x0f, 0x59, 0xc8], "mulss xmm1, xmm0");
- test_display(&[0xf2, 0x4f, 0x0f, 0x59, 0xc8], "mulsd xmm9, xmm8");
-
- test_display(
- &[0xf3, 0x4f, 0x0f, 0x6f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "movdqu xmm11, [r12 + r11 * 4 - 0x334455cc]"
- );
- test_display(&[0xf3, 0x0f, 0x70, 0xc0, 0x4e], "pshufhw xmm0, xmm0, 0x4e");
- test_display(&[0xf3, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
- test_display(&[0xf3, 0x4f, 0x0f, 0x7e, 0xc1], "movd r9, mm0"); // use of rex.w demotes to movd r/mm
- test_display(&[0xf3, 0x40, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
- test_display(&[0xf3, 0x41, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm9");
- test_display(&[0xf3, 0x42, 0x0f, 0x7e, 0xc1], "movq xmm0, xmm1");
- test_display(&[0xf3, 0x44, 0x0f, 0x7e, 0xc1], "movq xmm8, xmm1");
- test_display(&[0xf3, 0x48, 0x0f, 0x7e, 0xc1], "movd rcx, mm0");
- test_display(
- &[0xf3, 0x4f, 0x0f, 0x7f, 0x9c, 0x9c, 0x34, 0xaa, 0xbb, 0xcc],
- "movdqu [r12 + r11 * 4 - 0x334455cc], xmm11"
- );
-
- test_display(&[0xf3, 0x0f, 0xc2, 0xc3, 0x08], "cmpss xmm0, xmm3, 0x8");
- test_display(&[0xf3, 0x4f, 0x0f, 0xc2, 0xc3, 0x08], "cmpss xmm8, xmm11, 0x8");
- test_display(&[0xf3, 0x4f, 0x0f, 0xc2, 0x03, 0x08], "cmpss xmm8, [r11], 0x8");
-}
-
-// SETLE, SETNG, ...
-
-#[test]
-fn test_mov() {
- // test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00, 0x12, 0x34, 0x12, 0x34], "mov eax, [0x3412341200c46293]");
- // RCT.exe 32bit version, TODO: FIX
- test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00], "mov eax, [0xc46293]");
- test_display(&[0xba, 0x01, 0x00, 0x00, 0x00], "mov edx, 0x1");
- test_display(&[0x48, 0xc7, 0x04, 0x24, 0x00, 0x00, 0x00, 0x00], "mov [rsp], 0x0");
- test_display(&[0x48, 0x89, 0x44, 0x24, 0x08], "mov [rsp + 0x8], rax");
- test_display(&[0x48, 0x89, 0x43, 0x18], "mov [rbx + 0x18], rax");
- test_display(&[0x48, 0xc7, 0x43, 0x10, 0x00, 0x00, 0x00, 0x00], "mov [rbx + 0x10], 0x0");
- test_display(&[0x49, 0x89, 0x4e, 0x08], "mov [r14 + 0x8], rcx");
- test_display(&[0x48, 0x8b, 0x32], "mov rsi, [rdx]");
- test_display(&[0x4d, 0x8b, 0x4c, 0x10, 0xf8], "mov r9, [r8 + rdx * 1 - 0x8]");
- test_display(&[0x49, 0x89, 0x46, 0x10], "mov [r14 + 0x10], rax");
- test_display(&[0x4d, 0x0f, 0x43, 0xec], "cmovnb r13, r12");
- test_display(&[0x0f, 0xb6, 0x06], "movzx eax, byte [rsi]");
- test_display(&[0x0f, 0xb7, 0x06], "movzx eax, word [rsi]");
- test_display(&[0x89, 0x55, 0x94], "mov [rbp - 0x6c], edx");
- test_display(&[0x65, 0x4c, 0x89, 0x04, 0x25, 0xa8, 0x01, 0x00, 0x00], "mov gs:[0x1a8], r8");
- test_display(&[0x0f, 0xbe, 0x83, 0xb4, 0x00, 0x00, 0x00], "movsx eax, byte [rbx + 0xb4]");
- test_display(&[0x46, 0x63, 0xc1], "movsxd r8, ecx");
- test_display(&[0x48, 0x63, 0x04, 0xba], "movsxd rax, [rdx + rdi * 4]");
- test_display(&[0xf3, 0x0f, 0x6f, 0x07], "movdqu xmm0, [rdi]");
- test_display(&[0xf3, 0x0f, 0x7f, 0x45, 0x00], "movdqu [rbp], xmm0");
-}
-
-#[test]
-fn test_stack() {
- test_display(&[0x66, 0x41, 0x50], "push r8w");
-}
-
-#[test]
-fn test_prefixes() {
- test_display(&[0x66, 0x41, 0x31, 0xc0], "xor r8w, ax");
- test_display(&[0x66, 0x41, 0x32, 0xc0], "xor al, r8b");
- test_display(&[0x40, 0x32, 0xc5], "xor al, bpl");
-
- // test that WAIT doesn't blow up, at least...
- assert_eq!(InstDecoder::default().decode([0x9b, 0xf8].iter().cloned()).err(), Some(DecodeError::IncompleteDecoder));
-}
-
-#[test]
-fn test_control_flow() {
- test_display(&[0x73, 0x31], "jnb 0x31");
- test_display(&[0x72, 0x5a], "jb 0x5a");
- test_display(&[0x0f, 0x86, 0x8b, 0x01, 0x00, 0x00], "jna 0x18b");
- test_display(&[0x74, 0x47], "jz 0x47");
- test_display(&[0xff, 0x15, 0x7e, 0x72, 0x24, 0x00], "call [rip + 0x24727e]");
- test_display(&[0xff, 0x24, 0xcd, 0x70, 0xa0, 0xbc, 0x01], "jmp [rcx * 8 + 0x1bca070]");
- test_display(&[0xff, 0xe0], "jmp rax");
- test_display(&[0x66, 0xff, 0xe0], "jmp rax");
- test_display(&[0x67, 0xff, 0xe0], "jmp rax");
- test_invalid(&[0xff, 0xd8]);
- test_display(&[0xff, 0x18], "callf [rax]");
- test_display(&[0xc3], "ret");
-}
-
-#[test]
-fn test_test_cmp() {
- test_display(&[0xf6, 0x05, 0x2c, 0x9b, 0xff, 0xff, 0x01], "test [rip - 0x64d4], 0x1");
- test_display(&[0x48, 0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp rax, -0xfff");
- test_display(&[0x3d, 0x01, 0xf0, 0xff, 0xff], "cmp eax, -0xfff");
- test_display(&[0x48, 0x83, 0xf8, 0xff], "cmp rax, -0x1");
- test_display(&[0x48, 0x39, 0xc6], "cmp rsi, rax");
-}
-
-#[test]
-fn test_push_pop() {
- test_display(&[0x5b], "pop rbx");
- test_display(&[0x41, 0x5e], "pop r14");
- test_display(&[0x68, 0x7f, 0x63, 0xc4, 0x00], "push 0xc4637f");
-}
-
-#[test]
-fn test_bmi1() {
- let bmi1 = InstDecoder::minimal().with_bmi1();
- let no_bmi1 = InstDecoder::minimal();
- test_display_under(&bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "tzcnt edx, r11d");
- test_display_under(&no_bmi1, &[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
-
- test_display_under(&bmi1, &[0xf3, 0x0f, 0xb8, 0xc1], "popcnt eax, ecx");
- test_display_under(&bmi1, &[0xf3, 0x4f, 0x0f, 0xb8, 0xc1], "popcnt r8, r9");
-}
-
-#[test]
-fn test_bitwise() {
- test_display_under(&InstDecoder::minimal(), &[0x41, 0x0f, 0xbc, 0xd3], "bsf edx, r11d");
- test_display(&[0x48, 0x0f, 0xa3, 0xd0], "bt rax, rdx");
- test_display(&[0x48, 0x0f, 0xab, 0xd0], "bts rax, rdx");
-}
-
-#[test]
-fn test_misc() {
- // TODO
-// test_display(&[0xf2, 0x0f, 0x38, 0xf0, 0xc1], "crc32 eax, cl");
-// test_display(&[0xf2, 0x0f, 0x38, 0xf1, 0xc1], "crc32 eax, ecx");
- test_display(&[0xfe, 0x00], "inc [rax]"); // TODO: inc byte [rax]
- test_display(&[0xfe, 0x08], "dec [rax]"); // TODO: dec byte [rax]
- test_display(&[0xff, 0x00], "inc [rax]"); // TODO: inc dword [rax]
- test_display(&[0x48, 0xff, 0x00], "inc [rax]"); // TODO: inc qword [rax]
- test_display(&[0xe4, 0x99], "in al, 0x99");
- test_display(&[0xe5, 0x99], "in eax, 0x99");
- test_display(&[0x67, 0xe5, 0x99], "in eax, 0x99");
- test_display(&[0x4f, 0xe5, 0x99], "in eax, 0x99");
- test_display(&[0xe6, 0x99], "out 0x99, al");
- test_display(&[0x4f, 0xe7, 0x99], "out 0x99, eax");
- test_display(&[0xec], "in al, dx");
- test_display(&[0xed], "in eax, dx");
- test_display(&[0xee], "out dx, al");
- test_display(&[0xef], "out dx, eax");
- test_display(&[0xcd, 0x00], "int 0x0");
- test_display(&[0xcd, 0xff], "int 0xff");
- test_display(&[0x9c], "pushf");
- test_display(&[0x48, 0x98], "cdqe");
- test_display(&[0x66, 0x2e, 0x0f, 0x1f, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00], "nop cs:[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");
- test_display(&[0x48, 0x8d, 0x53, 0x08], "lea rdx, [rbx + 0x8]");
- test_display(&[0x31, 0xc9], "xor ecx, ecx");
- test_display(&[0x48, 0x29, 0xc8], "sub rax, rcx");
- test_display(&[0x48, 0x03, 0x0b], "add rcx, [rbx]");
- test_display(&[0x48, 0x8d, 0x0c, 0x12], "lea rcx, [rdx + rdx * 1]");
- test_display(&[0xf6, 0xc2, 0x18], "test dl, 0x18");
- test_display(&[0xf3, 0x48, 0xab], "rep stos es:[rdi], rax");
- test_display(&[0xf3, 0x48, 0xa5], "rep movs es:[rdi], ds:[rsi]");
- test_display(&[0xf3, 0x45, 0x0f, 0xbc, 0xd7], "tzcnt r10d, r15d");
-
- // this is actually vmx
- // test_invalid(&[0x66, 0x0f, 0xc7, 0x03]);
- test_display(&[0x66, 0x4f, 0x0f, 0xc7, 0x33], "vmclear [r11]");
- test_display(&[0x66, 0x0f, 0xc7, 0x33], "vmclear [rbx]");
- test_display(&[0xf3, 0x4f, 0x0f, 0xc7, 0x33], "vmxon [r11]");
- test_display(&[0xf3, 0x0f, 0xc7, 0x33], "vmxon [rbx]");
-}
-
-#[test]
-#[ignore]
-// TODO also not supported at all
-fn evex() {
- test_display(&[0x62, 0xf2, 0x7d, 0x48, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa zmm0, [rax + rax*2 + 0x40]");
- test_display(&[0x62, 0xf2, 0x7d, 0x08, 0x2a, 0x44, 0x40, 0x01], "vmovntdqa xmm0, [rax + rax*2 + 0x10]");
-}
-
-#[test]
-fn test_vex() {
- fn test_instr(bytes: &[u8], text: &'static str) {
- test_display_under(&InstDecoder::minimal().with_avx(), bytes, text);
- test_display_under(&InstDecoder::default(), bytes, text);
- test_invalid_under(&InstDecoder::minimal(), bytes);
- }
-
- fn test_instr_invalid(bytes: &[u8]) {
- test_invalid_under(&InstDecoder::minimal().with_avx(), bytes);
- test_invalid_under(&InstDecoder::default(), bytes);
- }
-
- test_instr(&[0xc5, 0xf8, 0x10, 0x00], "vmovups xmm0, [rax]");
- test_instr(&[0xc5, 0xf8, 0x10, 0x01], "vmovups xmm0, [rcx]");
- test_instr(&[0xc5, 0x78, 0x10, 0x0f], "vmovups xmm9, [rdi]");
- test_instr(&[0xc5, 0xf8, 0x10, 0xcf], "vmovups xmm1, xmm7");
- test_instr(&[0xc5, 0xf9, 0x10, 0x0f], "vmovupd xmm1, [rdi]");
- test_instr(&[0xc5, 0xfa, 0x7e, 0x10], "vmovq xmm2, [rax]");
- test_instr(&[0xc5, 0xfc, 0x10, 0x0f], "vmovups ymm1, [rdi]");
- test_instr(&[0xc5, 0xfd, 0x10, 0x0f], "vmovupd ymm1, [rdi]");
- test_instr(&[0xc5, 0xfe, 0x10, 0x0f], "vmovss xmm1, [rdi]");
- test_instr(&[0xc5, 0xff, 0x10, 0xcf], "vmovsd xmm1, xmm0, xmm7");
- test_instr(&[0xc5, 0xff, 0x10, 0x01], "vmovsd xmm0, [rcx]");
- test_instr(&[0xc5, 0xf9, 0x6e, 0xc6], "vmovd xmm0, esi");
- test_instr(&[0xc5, 0xf9, 0x6e, 0x13], "vmovd xmm2, [rbx]");
- test_instr(&[0xc5, 0xf9, 0x7e, 0xc6], "vmovd esi, xmm0");
- test_instr(&[0xc5, 0xf9, 0x7e, 0x13], "vmovd [rbx], xmm2");
- test_instr_invalid(&[0x4f, 0xc5, 0xf8, 0x10, 0x00]);
- test_instr_invalid(&[0xf0, 0xc5, 0xf8, 0x10, 0x00]);
- test_instr(&[0xc4, 0x02, 0x71, 0x00, 0x0f], "vpshufb xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x00, 0x0f], "vpshufb ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x00, 0xcd], "vpshufb xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x00, 0xcd], "vpshufb ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x01, 0x0f], "vphaddw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x01, 0x0f], "vphaddw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x01, 0xcd], "vphaddw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x01, 0xcd], "vphaddw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x02, 0x0f], "vphaddd xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x02, 0x0f], "vphaddd ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x02, 0xcd], "vphaddd xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x02, 0xcd], "vphaddd ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x03, 0x0f], "vphaddsw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x03, 0x0f], "vphaddsw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x03, 0xcd], "vphaddsw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x03, 0xcd], "vphaddsw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x04, 0x0f], "vphaddubsw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x04, 0x0f], "vphaddubsw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x04, 0xcd], "vphaddubsw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x04, 0xcd], "vphaddubsw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x05, 0x0f], "vphsubw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x05, 0x0f], "vphsubw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x05, 0xcd], "vphsubw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x05, 0xcd], "vphsubw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x06, 0x0f], "vphsubd xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x06, 0x0f], "vphsubd ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x06, 0xcd], "vphsubd xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x06, 0xcd], "vphsubd ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x07, 0x0f], "vphsubsw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x07, 0x0f], "vphsubsw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x07, 0xcd], "vphsubsw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x07, 0xcd], "vphsubsw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x08, 0x0f], "vpsignb xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x08, 0x0f], "vpsignb ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x08, 0xcd], "vpsignb xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x08, 0xcd], "vpsignb ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x09, 0x0f], "vpsignw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x09, 0x0f], "vpsignw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x09, 0xcd], "vpsignw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x09, 0xcd], "vpsignw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x0a, 0x0f], "vpsignd xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x0a, 0x0f], "vpsignd ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x0a, 0xcd], "vpsignd xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x0a, 0xcd], "vpsignd ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x0b, 0x0f], "vpmulhrsw xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x0b, 0x0f], "vpmulhrsw ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x0b, 0xcd], "vpmulhrsw xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x0b, 0xcd], "vpmulhrsw ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x0c, 0x0f], "vpermilps xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x0c, 0x0f], "vpermilps ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x0c, 0xcd], "vpermilps xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x0c, 0xcd], "vpermilps ymm9, ymm1, ymm13");
- test_instr(&[0xc4, 0x02, 0x71, 0x0d, 0x0f], "vpermilpd xmm9, xmm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x75, 0x0d, 0x0f], "vpermilpd ymm9, ymm1, [r15]");
- test_instr(&[0xc4, 0x02, 0x71, 0x0d, 0xcd], "vpermilpd xmm9, xmm1, xmm13");
- test_instr(&[0xc4, 0x02, 0x75, 0x0d, 0xcd], "vpermilpd ymm9, ymm1, ymm13");
- test_instr_invalid(&[0xc4, 0x02, 0x71, 0x0e, 0x00]);
- test_instr(&[0xc4, 0x02, 0x79, 0x0e, 0x0f], "vtestps xmm9, [r15]");
- test_instr(&[0xc4, 0x02, 0x7d, 0x0e, 0x0f], "vtestps ymm9, [r15]");
- test_instr(&[0xc4, 0x02, 0x79, 0x0e, 0xcd], "vtestps xmm9, xmm13");
- test_instr(&[0xc4, 0x02, 0x7d, 0x0e, 0xcd], "vtestps ymm9, ymm13");
- test_instr_invalid(&[0xc4, 0x02, 0x71, 0x0f, 0x00]);
- test_instr(&[0xc4, 0x02, 0x79, 0x0f, 0x0f], "vtestpd xmm9, [r15]");
- test_instr(&[0xc4, 0x02, 0x7d, 0x0f, 0x0f], "vtestpd ymm9, [r15]");
- test_instr(&[0xc4, 0x02, 0x79, 0x0f, 0xcd], "vtestpd xmm9, xmm13");
- test_instr(&[0xc4, 0x02, 0x7d, 0x0f, 0xcd], "vtestpd ymm9, ymm13");
- test_instr(&[0xc4, 0xe2, 0x65, 0x90, 0x04, 0x51], "vpgatherdd ymm0, [rcx + ymm2 * 2], ymm3");
- test_instr(&[0xc4, 0xe2, 0xe5, 0x90, 0x04, 0x51], "vpgatherdq ymm0, [rcx + ymm2 * 2], ymm3");
- test_instr(&[0xc4, 0xe2, 0x65, 0x91, 0x04, 0x51], "vpgatherqd ymm0, [rcx + ymm2 * 2], ymm3");
- test_instr(&[0xc4, 0xe2, 0xe5, 0x91, 0x04, 0x51], "vpgatherqq ymm0, [rcx + ymm2 * 2], ymm3");
- test_instr(&[0xc4, 0x02, 0x09, 0x9d, 0xcd], "vfnmadd132ss xmm9, xmm14, xmm13");
- test_instr(&[0xc4, 0x02, 0x89, 0x9d, 0xcd], "vfnmadd132sd xmm9, xmm14, xmm13");
-// ...
- test_instr(&[0xc4, 0xe3, 0x79, 0x14, 0xd0, 0x0a], "vpextrb rax, xmm2, 0xa");
- test_instr(&[0xc4, 0xe3, 0x79, 0x14, 0x10, 0x0a], "vpextrb [rax], xmm2, 0xa");
- test_instr_invalid(&[0xc4, 0xe3, 0xf9, 0x14, 0x00, 0xd0]);
- test_instr_invalid(&[0xc4, 0xe3, 0xf9, 0x14, 0x00, 0x0a]);
-}
-
-#[test]
-fn strange_prefixing() {
- test_display(&[0x45, 0x66, 0x0f, 0x21, 0xc8], "mov rax, dr1");
- test_display(&[0x45, 0xf2, 0x0f, 0x21, 0xc8], "mov rax, dr1");
- test_display(&[0x45, 0xf3, 0x0f, 0x21, 0xc8], "mov rax, dr1");
-}
-
-#[test]
-fn prefixed_0f() {
- test_display(&[0x0f, 0x02, 0xc0], "lar eax, ax");
- test_display(&[0x48, 0x0f, 0x02, 0xc0], "lar rax, ax");
- test_display(&[0x0f, 0x03, 0xc0], "lsl eax, eax");
- test_display(&[0x48, 0x0f, 0x03, 0xc0], "lsl rax, rax");
- test_display(&[0x0f, 0x05], "syscall");
- test_display(&[0x48, 0x0f, 0x05], "syscall");
- test_display(&[0x66, 0x0f, 0x05], "syscall");
- test_display(&[0x0f, 0x06], "clts");
- test_display(&[0xf2, 0x0f, 0x06], "clts");
- test_display(&[0x0f, 0x07], "sysret");
- test_display(&[0xf2, 0x0f, 0x07], "sysret");
- test_display(&[0x0f, 0x12, 0x0f], "movlps xmm1, [rdi]");
- test_display(&[0x0f, 0x12, 0xcf], "movhlps xmm1, xmm7");
- test_display(&[0x0f, 0x16, 0x0f], "movhps xmm1, [rdi]");
- test_display(&[0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
- test_display(&[0x0f, 0x12, 0xc0], "movhlps xmm0, xmm0");
- test_invalid(&[0x0f, 0x13, 0xc0]);
- test_display(&[0x0f, 0x13, 0x00], "movlps [rax], xmm0");
- test_display(&[0x0f, 0x14, 0x08], "unpcklps xmm1, [rax]");
- test_display(&[0x0f, 0x15, 0x08], "unpckhps xmm1, [rax]");
- test_display(&[0x0f, 0x16, 0x0f], "movhps xmm1, [rdi]");
- test_display(&[0x0f, 0x16, 0xc0], "movlhps xmm0, xmm0");
- test_invalid(&[0x0f, 0x17, 0xc0]);
- test_display(&[0x0f, 0x17, 0x00], "movhps [rax], xmm0");
- test_invalid(&[0x0f, 0x18, 0xc0]);
- test_display(&[0x0f, 0x18, 0x00], "prefetchnta [rax]");
- test_display(&[0x0f, 0x18, 0x08], "prefetch0 [rax]");
- test_display(&[0x0f, 0x18, 0x10], "prefetch1 [rax]");
- test_display(&[0x0f, 0x18, 0x18], "prefetch2 [rax]");
- test_display(&[0x0f, 0x18, 0x20], "nop [rax]");
- test_display(&[0x4f, 0x0f, 0x18, 0x20], "nop [r8]");
- test_display(&[0x0f, 0x19, 0x20], "nop [rax]");
- test_display(&[0x0f, 0x1a, 0x20], "nop [rax]");
- test_display(&[0x0f, 0x1b, 0x20], "nop [rax]");
- test_display(&[0x0f, 0x1c, 0x20], "nop [rax]");
- test_display(&[0x0f, 0x1d, 0x20], "nop [rax]");
- test_display(&[0x0f, 0x1e, 0x20], "nop [rax]");
- test_display(&[0x0f, 0x1f, 0x20], "nop [rax]");
- test_display(&[0x45, 0x0f, 0x20, 0xc8], "mov r8, cr9");
- test_display(&[0x0f, 0x20, 0xc8], "mov rax, cr1");
- test_display(&[0x45, 0x0f, 0x21, 0xc8], "mov r8, dr9");
- test_display(&[0x0f, 0x21, 0xc8], "mov rax, dr1");
- test_display(&[0x45, 0x0f, 0x22, 0xc8], "mov cr9, r8");
- test_display(&[0x40, 0x0f, 0x22, 0xc8], "mov cr1, rax");
- test_display(&[0x0f, 0x22, 0xc8], "mov cr1, rax");
- test_display(&[0x44, 0x0f, 0x22, 0xcf], "mov cr9, rdi");
- test_display(&[0x0f, 0x22, 0xcf], "mov cr1, rdi");
- test_display(&[0x45, 0x0f, 0x23, 0xc8], "mov dr9, r8");
- test_display(&[0x40, 0x0f, 0x23, 0xc8], "mov dr1, rax");
- test_display(&[0x0f, 0x23, 0xc8], "mov dr1, rax");
- test_display(&[0x44, 0x0f, 0x23, 0xcf], "mov dr9, rdi");
- test_display(&[0x0f, 0x23, 0xcf], "mov dr1, rdi");
- test_display(&[0x0f, 0x30], "wrmsr");
- test_display(&[0x0f, 0x31], "rdtsc");
- test_display(&[0x0f, 0x32], "rdmsr");
- test_display(&[0x0f, 0x33], "rdpmc");
- test_display(&[0x0f, 0x34], "sysenter");
- test_display(&[0x0f, 0x35], "sysexit");
- test_invalid(&[0x0f, 0x36]);
- test_display(&[0x0f, 0x37], "getsec");
- test_display(&[0x0f, 0x60, 0x00], "punpcklbw mm0, [rax]");
- test_display(&[0x0f, 0x60, 0xc2], "punpcklbw mm0, mm2");
- test_display(&[0x0f, 0x61, 0x00], "punpcklwd mm0, [rax]");
- test_display(&[0x0f, 0x61, 0xc2], "punpcklwd mm0, mm2");
- test_display(&[0x0f, 0x62, 0x00], "punpckldq mm0, [rax]");
- test_display(&[0x0f, 0x62, 0xc2], "punpckldq mm0, mm2");
- test_display(&[0x0f, 0x63, 0x00], "packsswb mm0, [rax]");
- test_display(&[0x0f, 0x63, 0xc2], "packsswb mm0, mm2");
- test_display(&[0x0f, 0x64, 0x00], "pcmpgtb mm0, [rax]");
- test_display(&[0x0f, 0x64, 0xc2], "pcmpgtb mm0, mm2");
- test_display(&[0x0f, 0x65, 0x00], "pcmpgtw mm0, [rax]");
- test_display(&[0x0f, 0x65, 0xc2], "pcmpgtw mm0, mm2");
- test_display(&[0x0f, 0x66, 0x00], "pcmpgtd mm0, [rax]");
- test_display(&[0x0f, 0x66, 0xc2], "pcmpgtd mm0, mm2");
- test_display(&[0x0f, 0x67, 0x00], "packuswb mm0, [rax]");
- test_display(&[0x0f, 0x67, 0xc2], "packuswb mm0, mm2");
- test_display(&[0x0f, 0x68, 0x00], "punpckhbw mm0, [rax]");
- test_display(&[0x0f, 0x68, 0xc2], "punpckhbw mm0, mm2");
- test_display(&[0x0f, 0x69, 0x00], "punpckhwd mm0, [rax]");
- test_display(&[0x0f, 0x69, 0xc2], "punpckhwd mm0, mm2");
- test_display(&[0x0f, 0x6a, 0x00], "punpckhdq mm0, [rax]");
- test_display(&[0x0f, 0x6a, 0xc2], "punpckhdq mm0, mm2");
- test_display(&[0x0f, 0x6b, 0x00], "packssdw mm0, [rax]");
- test_display(&[0x0f, 0x6b, 0xc2], "packssdw mm0, mm2");
- test_invalid(&[0x0f, 0x6c]);
- test_invalid(&[0x0f, 0x6d]);
- test_display(&[0x0f, 0x6e, 0x00], "movd mm0, [rax]");
- test_display(&[0x0f, 0x6e, 0xc2], "movd mm0, edx");
- test_display(&[0x0f, 0x6f, 0x00], "movq mm0, [rax]");
- test_display(&[0x0f, 0x6f, 0xc2], "movq mm0, mm2");
- test_display(&[0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [rax], 0x7f");
- test_display(&[0x4f, 0x0f, 0x70, 0x00, 0x7f], "pshufw mm0, [r8], 0x7f");
- test_invalid(&[0x0f, 0x71, 0x00, 0x7f]);
- test_invalid(&[0x0f, 0x71, 0xc0, 0x7f]);
- test_display(&[0x0f, 0x71, 0xd0, 0x7f], "psrlw mm0, 0x7f");
- test_display(&[0x0f, 0x71, 0xe0, 0x7f], "psraw mm0, 0x7f");
- test_display(&[0x0f, 0x71, 0xf0, 0x7f], "psllw mm0, 0x7f");
- test_invalid(&[0x0f, 0x72, 0x00, 0x7f]);
- test_invalid(&[0x0f, 0x72, 0xc0, 0x7f]);
- test_display(&[0x0f, 0x72, 0xd0, 0x7f], "psrld mm0, 0x7f");
- test_display(&[0x0f, 0x72, 0xe0, 0x7f], "psrad mm0, 0x7f");
- test_display(&[0x0f, 0x72, 0xf0, 0x7f], "pslld mm0, 0x7f");
- test_invalid(&[0x0f, 0x73, 0x00, 0x7f]);
- test_invalid(&[0x0f, 0x73, 0xc0, 0x7f]);
- test_display(&[0x0f, 0x73, 0xd0, 0x7f], "psrlq mm0, 0x7f");
- test_invalid(&[0x0f, 0x73, 0xe0, 0x7f]);
- test_display(&[0x0f, 0x73, 0xf0, 0x7f], "psllq mm0, 0x7f");
- test_display(&[0x0f, 0xa0], "push fs");
- test_display(&[0x0f, 0xa1], "pop fs");
- test_display(&[0x0f, 0xa2], "cpuid");
- test_display(&[0x0f, 0xa4, 0xc0, 0x11], "shld eax, eax, 0x11");
- test_display(&[0x66, 0x0f, 0xa4, 0xcf, 0x11], "shld di, cx, 0x11");
- test_display(&[0x66, 0x45, 0x0f, 0xa4, 0xcf, 0x11], "shld r15w, r9w, 0x11");
- test_display(&[0x0f, 0xa5, 0xc0], "shld eax, eax, cl");
- test_display(&[0x0f, 0xa5, 0xc9], "shld ecx, ecx, cl");
-}
-
-#[test]
-fn prefixed_660f() {
- test_display(&[0x66, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
- test_display(&[0x66, 0x48, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
- test_display(&[0x66, 0x4a, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm0");
- test_display(&[0x66, 0x4b, 0x0f, 0x10, 0xc0], "movupd xmm0, xmm8");
- test_display(&[0x66, 0x4c, 0x0f, 0x10, 0xc0], "movupd xmm8, xmm0");
- test_display(&[0x66, 0x4d, 0x0f, 0x10, 0xc0], "movupd xmm8, xmm8");
- test_display(&[0xf2, 0x66, 0x66, 0x4d, 0x0f, 0x10, 0xc0], "movupd xmm8, xmm8");
-}
-
-#[test]
-fn prefixed_f20f() {
- test_display(&[0xf2, 0x0f, 0x16, 0xcf], "movlhps xmm1, xmm7");
- test_display(&[0xf2, 0x4d, 0x0f, 0x16, 0xcf], "movlhps xmm9, xmm15");
- test_display(&[0x40, 0x66, 0xf2, 0x66, 0x4d, 0x0f, 0x16, 0xcf], "movlhps xmm9, xmm15");
-}
-
-#[test]
-fn prefixed_f30f() {
- test_display(&[0xf3, 0x0f, 0x16, 0xcf], "movshdup xmm1, xmm7");
- test_display(&[0xf3, 0x4d, 0x0f, 0x16, 0xcf], "movshdup xmm9, xmm15");
-}
+mod long_mode;
+mod protected_mode;