From 80219e974d78af59afb4250498554ad8eb63274c Mon Sep 17 00:00:00 2001 From: iximeow Date: Sun, 9 Aug 2020 18:32:48 -0700 Subject: port updates to protected-mode decoder --- src/protected_mode/display.rs | 2187 +++++++++++++++------------- src/protected_mode/mod.rs | 3128 ++++++++++++++++++++++++++++------------- src/protected_mode/vex.rs | 265 ++-- test/protected_mode/mod.rs | 199 ++- 4 files changed, 3636 insertions(+), 2143 deletions(-) diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs index 77d39ff..6f73df1 100644 --- a/src/protected_mode/display.rs +++ b/src/protected_mode/display.rs @@ -5,7 +5,7 @@ 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}; +use crate::protected_mode::{RegSpec, Opcode, Operand, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec, DecodeError}; impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -97,7 +97,7 @@ impl fmt::Display for PrefixVex { if self.b() { "b" } else { "-" }, ) } else { - write!(f, "rex:none") + write!(f, "vex:none") } } } @@ -115,52 +115,34 @@ impl fmt::Display for Segment { } } +// register names are grouped by indices scaled by 16. +// xmm, ymm, zmm all get two indices. +const REG_NAMES: &[&'static str] = &[ + "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", + "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", + "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh", + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7", + "cs", "ds", "es", "fs", "gs", "ss", "", "", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", + "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15", + "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", + "ymm0", "ymm1", "ymm2", "ymm3", "ymm4", "ymm5", "ymm6", "ymm7", "ymm8", "ymm9", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15", + "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", + "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", + "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", + "eip", "k1", "k2", "k3", "k4", "k5", "k6", "k7", + "eflags", "k1", "k2", "k3", "k4", "k5", "k6", "k7", +]; + 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] - } - } + unsafe { REG_NAMES.get_unchecked((spec.num as u16 + ((spec.bank as u16) << 3)) as usize) } } impl fmt::Display for RegSpec { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", regspec_label(self)) + f.write_str(regspec_label(self)) } } @@ -195,61 +177,64 @@ impl > Colorize { - write!(f, "{}", colors.register(spec)) + f.write_str(regspec_label(spec)) } &Operand::DisplacementU16(imm) => { - write!(f, "[{}]", colors.address(u32_hex(imm as u32))) + write!(f, "[{}]", colors.address(u16_hex(imm))) } &Operand::DisplacementU32(imm) => { write!(f, "[{}]", colors.address(u32_hex(imm))) } &Operand::RegDisp(ref spec, disp) => { - write!(f, "[{} ", colors.register(spec))?; + write!(f, "[{} ", regspec_label(spec))?; format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; write!(f, "]") }, &Operand::RegDeref(ref spec) => { - write!(f, "[{}]", colors.register(spec)) + f.write_str("[")?; + f.write_str(regspec_label(spec))?; + f.write_str("]") }, &Operand::RegScale(ref spec, scale) => { write!(f, "[{} * {}]", - colors.register(spec), + regspec_label(spec), colors.number(scale) ) }, &Operand::RegScaleDisp(ref spec, scale, disp) => { write!(f, "[{} * {} ", - colors.register(spec), + regspec_label(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) - ) + f.write_str("[")?; + f.write_str(regspec_label(base))?; + f.write_str(" + ")?; + f.write_str(regspec_label(index))?; + f.write_str("]") } &Operand::RegIndexBaseDisp(ref base, ref index, disp) => { write!(f, "[{} + {} ", - colors.register(base), - colors.register(index), + regspec_label(base), + regspec_label(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), + regspec_label(base), + regspec_label(index), colors.number(scale) ) } &Operand::RegIndexBaseScaleDisp(ref base, ref index, scale, disp) => { write!(f, "[{} + {} * {} ", - colors.register(base), - colors.register(index), + regspec_label(base), + regspec_label(index), colors.number(scale), )?; format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; @@ -262,853 +247,979 @@ impl > Colorize 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::BZHI => write!(f, "bzhi"), - &Opcode::PDEP => write!(f, "pdep"), - &Opcode::PEXT => write!(f, "pext"), - &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::RDPID => write!(f, "rdpid"), - &Opcode::RDFSBASE => write!(f, "rdfsbase"), - &Opcode::RDGSBASE => write!(f, "rdgsbase"), - &Opcode::WRFSBASE => write!(f, "wrfsbase"), - &Opcode::WRGSBASE => write!(f, "wrgsbase"), - &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::XSAVEC => write!(f, "xsavec"), - &Opcode::XSAVES => write!(f, "xsaves"), - &Opcode::XRSTOR => write!(f, "xrstor"), - &Opcode::XRSTORS => write!(f, "xrstors"), - &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::CLFLUSHOPT => write!(f, "clflushopt"), - &Opcode::CLWB => write!(f, "clwb"), - &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::SARX => write!(f, "sarx"), - &Opcode::SHLX => write!(f, "shlx"), - &Opcode::SHRX => write!(f, "shrx"), - &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::RORX => write!(f, "rorx"), - &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::MULX => write!(f, "mulx"), - &Opcode::DIV => write!(f, "div"), - &Opcode::IDIV => write!(f, "idiv"), - &Opcode::CMPXCHG => write!(f, "cmpxchg"), - &Opcode::CMPXCHG8B => write!(f, "cmpxchg8b"), - &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::CWD => write!(f, "cwd"), - &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::VMPTRLD => write!(f, "vmptrld"), - &Opcode::VMPTRST => write!(f, "vmptrst"), - &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::XABORT => write!(f, "xabort"), - &Opcode::XBEGIN => write!(f, "xbegin"), - &Opcode::RDSEED => write!(f, "rdseed"), - &Opcode::LZCNT => write!(f, "lzcnt"), - &Opcode::CLGI => write!(f, "clgi"), - &Opcode::STGI => write!(f, "stgi"), - &Opcode::SKINIT => write!(f, "skinit"), - &Opcode::VMLOAD => write!(f, "vmload"), - &Opcode::VMMCALL => write!(f, "vmmcall"), - &Opcode::VMSAVE => write!(f, "vmsave"), - &Opcode::VMRUN => write!(f, "vmrun"), - &Opcode::INVLPGA => write!(f, "invlpga"), - &Opcode::MOVBE => write!(f, "movbe"), - &Opcode::ADCX => write!(f, "adcx"), - &Opcode::ADOX => write!(f, "adox"), - &Opcode::PREFETCHW => write!(f, "prefetchw"), - &Opcode::RDRAND => write!(f, "rdrand"), - &Opcode::SHA1RNDS4 => write!(f, "sha1rnds4"), - &Opcode::SHA1NEXTE => write!(f, "sha1nexte"), - &Opcode::SHA1MSG1 => write!(f, "sha1msg1"), - &Opcode::SHA1MSG2 => write!(f, "sha1msg2"), - &Opcode::SHA256RNDS2 => write!(f, "sha256rnds2"), - &Opcode::SHA256MSG1 => write!(f, "sha256msg1"), - &Opcode::SHA256MSG2 => write!(f, "sha256msg2"), - &Opcode::Invalid => write!(f, "invalid"), + f.write_str(self.name()) + } +} + +const MNEMONICS: &[&'static str] = &[ + "invalid", + "add", + "or", + "adc", + "sbb", + "and", + "xor", + "sub", + "cmp", + "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", + "movsx", + "movzx", + "movzx", + "movsx", + "movsxd", + "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", + "iretd", + "iretq", + "retf", + "enter", + "leave", + "mov", + "ret", + "pushf", + "wait", + "cbw", + "cwde", + "cdqe", + "cwd", + "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", + "clflushopt", + "clwb", + "wrmsr", + "rdtsc", + "rdmsr", + "rdpmc", + "sldt", + "str", + "lldt", + "ltr", + "verr", + "verw", + "cmc", + "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", + "xabort", + "xbegin", + "xend", + "xtest", + "enclu", + "rdpkru", + "wrpkru", + "rdseed", + "rdrand", + "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", + "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", + "vpmaxub", + "vpmaxud", + "vpminsw", + "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", + "dpps", + "dppd", + "mpsadbw", + "pmovzxdq", + "pmovsxdq", + "pmovzxbd", + "pmovsxbd", + "pmovzxwq", + "pmovsxwq", + "pmovzxbq", + "pmovsxbq", + "pmovsxwd", + "pmovzxwd", + "pextrq", + "pextrd", + "pextrw", + "pextrb", + "pmovsxbw", + "pmovzxbw", + "pinsrq", + "pinsrd", + "pinsrb", + "extractps", + "insertps", + "roundss", + "roundsd", + "roundps", + "roundpd", + "pmaxsb", + "pmaxsd", + "pmaxuw", + "pmaxud", + "pminsd", + "pminsb", + "pminud", + "pminuw", + "blendw", + "pblendvb", + "pblendw", + "blendvps", + "blendvpd", + "blendps", + "blendpd", + "pmuldq", + "movntdqa", + "pmulld", + "palignr", + "psignw", + "psignd", + "psignb", + "pshufb", + "pmulhrsw", + "pmaddubsw", + "pabsd", + "pabsw", + "pabsb", + "phsubsw", + "phsubw", + "phsubd", + "phaddd", + "phaddsw", + "phaddw", + "hsubpd", + "haddpd", + "sha1rnds4", + "sha1nexte", + "sha1msg1", + "sha1msg2", + "sha256rnds2", + "sha256msg1", + "sha256msg2", + "lzcnt", + "clgi", + "stgi", + "skinit", + "vmload", + "vmmcall", + "vmsave", + "vmrun", + "invlpga", + "movbe", + "adcx", + "adox", + "prefetchw", + "rdpid", + "cmpxchg8b", + "cmpxchg16b", + "vmptrld", + "vmptrst", + "bzhi", + "mulx", + "shlx", + "shrx", + "sarx", + "pdep", + "pext", + "rorx", + "xrstors", + "xrstors64", + "xsavec", + "xsavec64", + "xsaves", + "xsaves64", + "rdfsbase", + "rdgsbase", + "wrfsbase", + "wrgsbase", + "crc32", + "xlat", + + "f2xm1", + "fabs", + "fadd", + "faddp", + "fbld", + "fbstp", + "fchs", + "fcmovb", + "fcmovbe", + "fcmove", + "fcmovnb", + "fcmovnbe", + "fcmovne", + "fcmovnu", + "fcmovu", + "fcom", + "fcomi", + "fcomip", + "fcomp", + "fcompp", + "fcos", + "fdecstp", + "fdisi8087_nop", + "fdiv", + "fdivp", + "fdivr", + "fdivrp", + "feni8087_nop", + "ffree", + "ffreep", + "fiadd", + "ficom", + "ficomp", + "fidiv", + "fidivr", + "fild", + "fimul", + "fincstp", + "fist", + "fistp", + "fisttp", + "fisub", + "fisubr", + "fld", + "fld1", + "fldcw", + "fldenv", + "fldl2e", + "fldl2t", + "fldlg2", + "fldln2", + "fldpi", + "fldz", + "fmul", + "fmulp", + "fnclex", + "fninit", + "fnop", + "fnsave", + "fnstcw", + "fnstenv", + "fnstor", + "fnstsw", + "fpatan", + "fprem", + "fprem1", + "fptan", + "frndint", + "frstor", + "fscale", + "fsetpm287_nop", + "fsin", + "fsincos", + "fsqrt", + "fst", + "fstp", + "fstpnce", + "fsub", + "fsubp", + "fsubr", + "fsubrp", + "ftst", + "fucom", + "fucomi", + "fucomip", + "fucomp", + "fucompp", + "fxam", + "fxch", + "fxtract", + "fyl2x", + "fyl2xp1", + "loopnz", + "loopz", + "loop", + "jrcxz", + "pusha", + "popa", + "arpl", +]; + +impl Opcode { + fn name(&self) -> &'static str { + unsafe { + MNEMONICS.get_unchecked(*self as usize) } } } @@ -1227,7 +1338,7 @@ impl > Colorize> Colorize> Colorize { write!(out, "{}", colors.arithmetic_op(self)) } Opcode::POPF | Opcode::PUSHF | Opcode::ENTER | Opcode::LEAVE | + Opcode::PUSHA | + Opcode::POPA | Opcode::PUSH | Opcode::POP => { write!(out, "{}", colors.stack_op(self)) } Opcode::WAIT | + Opcode::FNOP | + Opcode::FDISI8087_NOP | + Opcode::FENI8087_NOP | + Opcode::FSETPM287_NOP | Opcode::PREFETCHNTA | Opcode::PREFETCH0 | Opcode::PREFETCH1 | @@ -1450,8 +1605,14 @@ impl > Colorize { write!(out, "{}", colors.stop_op(self)) } + Opcode::LOOPNZ | + Opcode::LOOPZ | + Opcode::LOOP | + Opcode::JRCXZ | Opcode::CALL | Opcode::CALLF | Opcode::JMP | @@ -1498,7 +1659,8 @@ impl > Colorize> Colorize> Colorize> Colorize> Colorize> Colorize> Colorize> Colorize { write!(out, "{}", colors.comparison_op(self)) } Opcode::WRMSR | @@ -1867,8 +2085,11 @@ impl > Colorize> Colorize> Colorize> Colorize { write!(out, "{}", colors.platform_op(self)) } + Opcode::CRC32 | Opcode::RDSEED | Opcode::RDRAND | Opcode::SHA1RNDS4 | @@ -1956,6 +2178,10 @@ impl > Colorize> Colorize(&self, out: &mut T) -> fmt::Result { + self.contextualize(&NoColors, 0, Some(&NoContext), out) + } +} + impl > ShowContextual 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 ")?; + if self.prefixes.rep_any() { + 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)?; + out.write_str(self.opcode.name())?; if self.opcode == Opcode::XBEGIN { return write!(out, " $+{}", colors.number(signed_i32_hex(self.imm as i32))); } - match self.operands[0] { - OperandSpec::Nothing => { - return Ok(()); - }, - _ => { - write!(out, " ")?; - if let Some(prefix) = self.segment_override_for_op(0) { - write!(out, "{}:", prefix)?; - } + if self.operand_count > 0 { + out.write_str(" ")?; + + 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[0]); + x.colorize(colors, out)?; + + for i in 1..self.operand_count { + match self.opcode { + Opcode::MOVSX_b | + Opcode::MOVZX_b => { + match &self.operands[i as usize] { + &OperandSpec::Nothing => { + return Ok(()); + }, + &OperandSpec::RegMMM => { + out.write_str(", ")?; + } + _ => { + out.write_str(", byte ")?; + if let Some(prefix) = self.segment_override_for_op(i) { + 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 as usize]); + x.colorize(colors, out)? + }, + Opcode::MOVSX_w | + Opcode::MOVZX_w => { + match &self.operands[i as usize] { + &OperandSpec::Nothing => { + return Ok(()); + }, + &OperandSpec::RegMMM => { + out.write_str(", ")?; + } + _ => { + out.write_str(", 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 as usize]); + x.colorize(colors, out)? + }, + _ => { + match &self.operands[i as usize] { + &OperandSpec::Nothing => { + return Ok(()); + }, + _ => { + out.write_str(", ")?; + if let Some(prefix) = self.segment_override_for_op(1) { + write!(out, "{}:", prefix)?; + } + let x = Operand::from_spec(self, self.operands[i as usize]); + x.colorize(colors, out)? } - let x = Operand::from_spec(self, self.operands[i]); - x.colorize(colors, out)? } } } diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 2fe3b3e..82484df 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -65,18 +65,22 @@ impl RegSpec { } #[inline] - fn from_parts(num: u8, bank: RegisterBank) -> RegSpec { + fn st(num: u8) -> RegSpec { + if num >= 8 { + panic!("invalid x87 reg st({})", num); + } + RegSpec { - num: num, - bank: bank + num, + bank: RegisterBank::ST } } #[inline] - fn gp_from_parts(num: u8, width: u8) -> RegSpec { + fn from_parts(num: u8, bank: RegisterBank) -> RegSpec { RegSpec { num: num, - bank: width_to_gp_reg_bank(width) + bank: bank } } @@ -97,35 +101,13 @@ impl RegSpec { } #[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 - } + RegSpec { bank: RegisterBank::D, num: 4 } } #[inline] - pub fn sp() -> RegSpec { - RegSpec { - num: 4, - bank: RegisterBank::W - } + pub fn ebp() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 5 } } #[inline] @@ -159,38 +141,53 @@ impl RegSpec { } #[inline] - pub fn bx() -> RegSpec { - RegSpec { bank: RegisterBank::W, num: 3 } + pub fn esi() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 6 } } #[inline] - pub fn si() -> RegSpec { - RegSpec { bank: RegisterBank::W, num: 6 } + pub fn edi() -> RegSpec { + RegSpec { bank: RegisterBank::D, num: 7 } } #[inline] - pub fn esi() -> RegSpec { - RegSpec { bank: RegisterBank::D, num: 6 } + pub fn ax() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 0 } } #[inline] - pub fn di() -> RegSpec { - RegSpec { bank: RegisterBank::W, num: 7 } + pub fn cx() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 1 } } #[inline] - pub fn edi() -> RegSpec { - RegSpec { bank: RegisterBank::D, num: 7 } + pub fn dx() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 2 } } #[inline] - pub fn ax() -> RegSpec { - RegSpec { bank: RegisterBank::W, num: 0 } + pub fn bx() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 3 } } #[inline] - pub fn dx() -> RegSpec { - RegSpec { bank: RegisterBank::W, num: 2 } + pub fn sp() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 4 } + } + + #[inline] + pub fn bp() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 5 } + } + + #[inline] + pub fn si() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 6 } + } + + #[inline] + pub fn di() -> RegSpec { + RegSpec { bank: RegisterBank::W, num: 7 } } #[inline] @@ -204,6 +201,11 @@ impl RegSpec { } #[inline] + pub fn dl() -> RegSpec { + RegSpec { bank: RegisterBank::B, num: 2 } + } + + #[inline] pub fn ah() -> RegSpec { RegSpec { bank: RegisterBank::B, num: 4 } } @@ -270,8 +272,8 @@ pub enum Operand { ImmediateU32(u32), ImmediateI32(i32), Register(RegSpec), - DisplacementU32(u32), DisplacementU16(u16), + DisplacementU32(u32), RegDeref(RegSpec), RegDisp(RegSpec, i32), RegScale(RegSpec, u8), @@ -286,8 +288,8 @@ pub enum Operand { impl OperandSpec { pub fn is_memory(&self) -> bool { match self { - OperandSpec::DispU32 | OperandSpec::DispU16 | + OperandSpec::DispU32 | OperandSpec::Deref | OperandSpec::Deref_esi | OperandSpec::Deref_edi | @@ -309,8 +311,8 @@ impl OperandSpec { OperandSpec::RegRRR | OperandSpec::RegMMM | OperandSpec::RegVex | - OperandSpec::AL | - OperandSpec::CL | + OperandSpec::Reg4 | + OperandSpec::EnterFrameSize | OperandSpec::Nothing => { false } @@ -334,11 +336,8 @@ impl Operand { OperandSpec::RegVex => { Operand::Register(inst.vex_reg) } - OperandSpec::AL => { - Operand::Register(RegSpec::al()) - } - OperandSpec::CL => { - Operand::Register(RegSpec::cl()) + OperandSpec::Reg4 => { + Operand::Register(RegSpec { num: inst.imm as u8, bank: inst.vex_reg.bank }) } OperandSpec::ImmI8 => Operand::ImmediateI8(inst.imm as i8), OperandSpec::ImmU8 => Operand::ImmediateU8(inst.imm as u8), @@ -346,8 +345,9 @@ impl Operand { 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::EnterFrameSize => Operand::ImmediateU16(inst.disp as u16), OperandSpec::DispU16 => Operand::DisplacementU16(inst.disp as u16), + OperandSpec::DispU32 => Operand::DisplacementU32(inst.disp), OperandSpec::Deref => { Operand::RegDeref(inst.modrm_mmm) } @@ -447,21 +447,21 @@ fn operand_size() { #[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 + D = 0, W = 1, B = 2, // Dword, Word, Byte + CR = 3, DR = 4, S = 5, EIP = 21, EFlags = 22, // Control reg, Debug reg, Selector, ... + X = 6, Y = 10, Z = 14, // XMM, YMM, ZMM + ST = 18, MM = 19, // ST, MM regs (x87, mmx) + K = 20, // 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 + D = 0, W = 1, B = 2, // Dword, Word, Byte + CR = 3, DR = 4, S = 5, EIP = 21, EFlags = 22, // Control reg, Debug reg, Selector, ... + X = 6, Y = 10, Z = 14, // XMM, YMM, ZMM + ST = 18, MM = 19, // ST, MM regs (x87, mmx) + K = 20, // AVX512 mask registers } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -490,14 +490,16 @@ const BMI2: [Opcode; 8] = [ ]; #[allow(dead_code)] -const XSAVE: [Opcode; 8] = [ +const XSAVE: [Opcode; 10] = [ Opcode::XGETBV, Opcode::XRSTOR, Opcode::XRSTORS, Opcode::XSAVE, Opcode::XSAVEC, + Opcode::XSAVEC64, Opcode::XSAVEOPT, Opcode::XSAVES, + Opcode::XSAVES64, Opcode::XSETBV, ]; @@ -509,15 +511,15 @@ const XSAVE: [Opcode; 8] = [ #[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, + ADD, + OR, + ADC, + SBB, + AND, + XOR, + SUB, + CMP, XADD, BT, BTS, @@ -568,7 +570,7 @@ pub enum Opcode { MOVZX_b, MOVZX_w, MOVSX, - ARPL, + MOVSXD, SAR, SAL, SHR, @@ -598,6 +600,8 @@ pub enum Opcode { INT, INTO, IRET, + IRETD, + IRETQ, RETF, ENTER, LEAVE, @@ -721,6 +725,7 @@ pub enum Opcode { LTR, VERR, VERW, + CMC, CLC, STC, CLI, @@ -852,7 +857,6 @@ pub enum Opcode { PCMPGTB, PCMPGTD, PCMPGTW, - PEXTRW, PINSRW, PMADDWD, PMAXSW, @@ -1157,7 +1161,9 @@ pub enum Opcode { VPMAXSB, VPMAXSD, VPMAXSW, + VPMAXUB, VPMAXUD, + VPMINSW, VPMINSD, VPMINUD, VPMOVMSKB, @@ -1264,6 +1270,8 @@ pub enum Opcode { PCMPEQQ, PTEST, PHMINPOSUW, + DPPS, + DPPD, MPSADBW, PMOVZXDQ, PMOVSXDQ, @@ -1276,6 +1284,8 @@ pub enum Opcode { PMOVSXWD, PMOVZXWD, PEXTRQ, + PEXTRD, + PEXTRW, PEXTRB, PMOVSXBW, PMOVZXBW, @@ -1289,6 +1299,7 @@ pub enum Opcode { ROUNDPS, ROUNDPD, PMAXSB, + PMAXSD, PMAXUW, PMAXUD, PMINSD, @@ -1296,7 +1307,8 @@ pub enum Opcode { PMINUD, PMINUW, BLENDW, - BLENDDVB, + PBLENDVB, + PBLENDW, BLENDVPS, BLENDVPD, BLENDPS, @@ -1309,7 +1321,7 @@ pub enum Opcode { PSIGND, PSIGNB, PSHUFB, - PMULHRSU, + PMULHRSW, PMADDUBSW, PABSD, PABSW, @@ -1350,6 +1362,7 @@ pub enum Opcode { RDPID, CMPXCHG8B, + CMPXCHG16B, VMPTRLD, VMPTRST, @@ -1362,13 +1375,121 @@ pub enum Opcode { PEXT, RORX, XRSTORS, + XRSTORS64, XSAVEC, + XSAVEC64, XSAVES, + XSAVES64, RDFSBASE, RDGSBASE, WRFSBASE, WRGSBASE, + + CRC32, + XLAT, + + F2XM1, + FABS, + FADD, + FADDP, + FBLD, + FBSTP, + FCHS, + FCMOVB, + FCMOVBE, + FCMOVE, + FCMOVNB, + FCMOVNBE, + FCMOVNE, + FCMOVNU, + FCMOVU, + FCOM, + FCOMI, + FCOMIP, + FCOMP, + FCOMPP, + FCOS, + FDECSTP, + FDISI8087_NOP, + FDIV, + FDIVP, + FDIVR, + FDIVRP, + FENI8087_NOP, + FFREE, + FFREEP, + FIADD, + FICOM, + FICOMP, + FIDIV, + FIDIVR, + FILD, + FIMUL, + FINCSTP, + FIST, + FISTP, + FISTTP, + FISUB, + FISUBR, + FLD, + FLD1, + FLDCW, + FLDENV, + FLDL2E, + FLDL2T, + FLDLG2, + FLDLN2, + FLDPI, + FLDZ, + FMUL, + FMULP, + FNCLEX, + FNINIT, + FNOP, + FNSAVE, + FNSTCW, + FNSTENV, + FNSTOR, + FNSTSW, + FPATAN, + FPREM, + FPREM1, + FPTAN, + FRNDINT, + FRSTOR, + FSCALE, + FSETPM287_NOP, + FSIN, + FSINCOS, + FSQRT, + FST, + FSTP, + FSTPNCE, + FSUB, + FSUBP, + FSUBR, + FSUBRP, + FTST, + FUCOM, + FUCOMI, + FUCOMIP, + FUCOMP, + FUCOMPP, + FXAM, + FXCH, + FXTRACT, + FYL2X, + FYL2XP1, + + LOOPNZ, + LOOPZ, + LOOP, + JRCXZ, + + PUSHA, + POPA, + ARPL, } #[derive(Debug)] @@ -1420,16 +1541,18 @@ enum OperandSpec { 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, + // the register selected by a handful of avx2 vex-coded instructions, + // stuffed in imm4. + Reg4, ImmI8, ImmI16, ImmI32, ImmU8, ImmU16, ImmU32, + // ENTER is a two-immediate instruction, where the first immediate is stored in the disp field. + // for this case, a second immediate-style operand is needed. + EnterFrameSize, DispU16, DispU32, Deref, @@ -1446,7 +1569,7 @@ enum OperandSpec { // the Hash, Eq, and PartialEq impls here are possibly misleading. // They exist because downstream some structs are spelled like -// Foo for T == x86 This is only to access associated types +// Foo for T == x86. This is only to access associated types // which themselves are bounded, but their #[derive] require T to // implement these traits. #[cfg(feature="use-serde")] @@ -1469,9 +1592,11 @@ impl yaxpeax_arch::Arch for Arch { impl LengthedInstruction for Instruction { type Unit = AddressDiff; + #[inline] fn len(&self) -> Self::Unit { AddressDiff::from_const(self.length.into()) } + #[inline] fn min_size() -> Self::Unit { AddressDiff::from_const(1) } @@ -1710,7 +1835,7 @@ impl InstDecoder { } /// `bmi2` indicates support for the `BZHI`, `MULX`, `PDEP`, `PEXT`, `RORX`, `SARX`, `SHRX`, - /// and `SHLX` instructions. `bmi2` is implemented in all x86_64 chips that implement `bmi`, + /// and `SHLX` instructions. `bmi2` is implemented in all x86 chips that implement `bmi`, /// except the amd `piledriver` and `steamroller` microarchitectures. pub fn bmi2(&self) -> bool { self.flags & (1 << 16) != 0 @@ -2199,7 +2324,7 @@ impl InstDecoder { Opcode::PABSW | Opcode::PABSD | Opcode::PMADDUBSW | - Opcode::PMULHRSU | + Opcode::PMULHRSW | Opcode::PSHUFB | Opcode::PSIGNB | Opcode::PSIGNW | @@ -2218,7 +2343,7 @@ impl InstDecoder { Opcode::BLENDPS | Opcode::BLENDVPD | Opcode::BLENDVPS | - Opcode::BLENDDVB | + Opcode::PBLENDVB | Opcode::BLENDW | Opcode::PMINUW | Opcode::PMINUD | @@ -2227,18 +2352,17 @@ impl InstDecoder { Opcode::PMAXUW | Opcode::PMAXUD | Opcode::PMAXSB | + Opcode::PMAXSD | Opcode::ROUNDPS | Opcode::ROUNDPD | Opcode::ROUNDSS | Opcode::ROUNDSD | + Opcode::PBLENDW | Opcode::EXTRACTPS | Opcode::INSERTPS | Opcode::PINSRB | Opcode::PINSRD | Opcode::PINSRQ | - Opcode::PEXTRB | - Opcode::PEXTRW | - Opcode::PEXTRQ | Opcode::PMOVSXBW | Opcode::PMOVZXBW | Opcode::PMOVSXBD | @@ -2251,10 +2375,16 @@ impl InstDecoder { Opcode::PMOVZXWQ | Opcode::PMOVSXDQ | Opcode::PMOVZXDQ | + Opcode::DPPS | + Opcode::DPPD | Opcode::MPSADBW | Opcode::PHMINPOSUW | Opcode::PTEST | Opcode::PCMPEQQ | + Opcode::PEXTRB | + Opcode::PEXTRW | + Opcode::PEXTRD | + Opcode::PEXTRQ | Opcode::PACKUSDW => { // via Intel section 5.10, SSE4.1 Instructions if !self.sse4_1() { @@ -2262,6 +2392,7 @@ impl InstDecoder { return Err(DecodeError::InvalidOpcode); } } + Opcode::CRC32 | Opcode::PCMPESTRI | Opcode::PCMPESTRM | Opcode::PCMPISTRI | @@ -2321,6 +2452,7 @@ impl InstDecoder { return Err(DecodeError::InvalidOpcode); } } + // AVX... Opcode::VMOVDDUP | Opcode::VPSHUFLW | Opcode::VHADDPS | @@ -2553,7 +2685,9 @@ impl InstDecoder { Opcode::VPMAXSB | Opcode::VPMAXSD | Opcode::VPMAXSW | + Opcode::VPMAXUB | Opcode::VPMAXUD | + Opcode::VPMINSW | Opcode::VPMINSD | Opcode::VPMINUD | Opcode::VPMOVMSKB | @@ -2985,6 +3119,7 @@ pub struct Prefixes { bits: u8, vex: PrefixVex, segment: Segment, + _pad: u8, } #[derive(Debug, Copy, Clone)] @@ -3013,10 +3148,9 @@ impl Prefixes { fn new(bits: u8) -> Prefixes { Prefixes { bits: bits, - vex: PrefixVex { - bits: 0, - }, + vex: PrefixVex { bits: 0 }, segment: Segment::DS, + _pad: 0, } } fn vex_from(&mut self, bits: u8) { @@ -3037,6 +3171,8 @@ impl Prefixes { #[inline] fn set_repnz(&mut self) { self.bits = (self.bits & 0xcf) | 0x30 } #[inline] + pub fn rep_any(&self) -> bool { self.bits & 0x30 != 0x00 } + #[inline] fn operand_size(&self) -> bool { self.bits & 0x1 == 1 } #[inline] fn set_operand_size(&mut self) { self.bits = self.bits | 0x1 } @@ -3096,189 +3232,518 @@ impl Prefixes { } } +#[derive(Debug)] +struct OperandCodeBuilder { + bits: u16 +} + +#[allow(non_camel_case_types)] +enum ZOperandCategory { + Zv_R = 0, + Zv_AX = 1, + Zb_Ib_R = 2, + Zv_Iv_R = 3, +} + +struct ZOperandInstructions { + bits: u16 +} + +impl ZOperandInstructions { + fn category(&self) -> u8 { + (self.bits >> 4) as u8 & 0b11 + } + fn reg(&self) -> u8 { + (self.bits & 0b111) as u8 + } +} + +struct EmbeddedOperandInstructions { + bits: u16 +} + +impl EmbeddedOperandInstructions { + #[allow(unused)] + fn bits(&self) -> u16 { + self.bits + } +} + +#[allow(non_snake_case)] +impl OperandCodeBuilder { + const fn new() -> Self { + OperandCodeBuilder { bits: 0 } + } + + const fn bits(&self) -> u16 { + self.bits + } + + const fn from_bits(bits: u16) -> Self { + Self { bits } + } + + const fn read_modrm(mut self) -> Self { + self.bits |= 0x8000; + self + } + + const fn op0_is_rrr_and_embedded_instructions(mut self) -> Self { + self = self.set_embedded_instructions(); + self.bits |= 0x2000; + self + } + + const fn set_embedded_instructions(mut self) -> Self { + self.bits |= 0x4000; + self + } + + #[allow(unused)] + const fn op0_is_rrr(&self) -> bool { + self.bits & 0x2000 != 0 + } + + fn has_embedded_instructions(&self) -> bool { + self.bits & 0x4000 != 0 + } + + fn get_embedded_instructions(&self) -> Result { + // 0x4000 indicates embedded instructions + // 0x3fff > 0x0080 indicates the embedded instructions are a Z-style operand + if self.bits & 0x7f80 <= 0x407f { + Ok(ZOperandInstructions { bits: self.bits }) + } else { + Err(EmbeddedOperandInstructions { bits: self.bits }) + } + } + + #[allow(unused)] + fn special_case_handler_index(&self) -> u16 { + self.bits & 0xff + } + + const fn special_case(mut self, case: u16) -> Self { + // leave 0x4000 unset + self.bits |= case & 0xff; + self + } + + const fn operand_case(mut self, case: u16) -> Self { + // leave 0x4000 unset + self.bits |= case & 0xff; + self + } + + const fn op0_is_rrr_and_Z_operand(mut self, category: ZOperandCategory, reg_num: u8) -> Self { + self = self.set_embedded_instructions(); + // if op0 is rrr, 0x2000 unset indicates the operand category written in bits 11:10 + // further, reg number is bits 0:2 + // + // when 0x2000 is unset: + // 0x1cf8 are all unused bits, so far + // + // if you're counting, that's 8 bits remaining. + // it also means one of those (0x0400?) can be used to pick some other interpretation + // scheme. + self.bits |= (category as u8 as u16) << 4; + self.bits |= reg_num as u16 & 0b111; + self + } + + const fn read_E(mut self) -> Self { + self.bits |= 0x1000; + self + } + + const fn has_read_E(&self) -> bool { + self.bits & 0x1000 != 0 + } + + const fn byte_operands(mut self) -> Self { + self.bits |= 0x0800; + self + } + + const fn mem_reg(mut self) -> Self { + self.bits |= 0x0400; + self + } + + const fn reg_mem(self) -> Self { + // 0x0400 unset + self + } + + const fn has_byte_operands(&self) -> bool { + (self.bits & 0x0800) != 0 + } + + #[allow(unused)] + const fn has_mem_reg(&self) -> bool { + (self.bits & 0x0400) != 0 + } + + const fn has_reg_mem(&self) -> bool { + (self.bits & 0x0400) == 0 + } + + const fn only_modrm_operands(mut self) -> Self { + self.bits |= 0x0200; + self + } + + const fn is_only_modrm_operands(&self) -> bool { + self.bits & 0x0200 != 0 + } + + // WHEN AN IMMEDIATE IS PRESENT, THERE ARE ONLY 0x3F ALLOWED SPECIAL CASES. + // WHEN NO IMMEDIATE IS PRESENT, THERE ARE 0xFF ALLOWED SPECIAL CASES. + // SIZE IS DECIDED BY THE FOLLOWING TABLE: + // 0: 1 BYTE + // 1: 4 BYTES + const fn with_imm(mut self, only_imm: bool, size: u8) -> Self { + self.bits |= 0x100; + self.bits |= (size as u16) << 6; + self.bits |= (only_imm as u16) << 7; + self + } + + fn has_imm(&self) -> Option<(bool, u8)> { + if self.bits & 0x100 != 0 { + Some(((self.bits & 0x80) != 0, (self.bits as u8 >> 6) & 1)) + } else { + None + } + } +} + #[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. +// +// bit 15 is "read modrm?" +// 0bMxxx_xxxx_xxxx_xxxx +// | +// | +// | +// | +// | +// | +// ---------------------------> read modr/m? #[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq)] pub enum OperandCode { - ModRM_0x0f00, - ModRM_0x0f01, - ModRM_0x0f0d, - ModRM_0x0fae, - ModRM_0x0fba, - ModRM_0xf238, - ModRM_0xf30fae, - ModRM_0x660fae, - ModRM_0xf30fc7, - ModRM_0x660f38, - ModRM_0xf30f38, - 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, + Ivs = OperandCodeBuilder::new().special_case(25).bits(), + I_3 = OperandCodeBuilder::new().special_case(27).bits(), + Nothing = OperandCodeBuilder::new().special_case(28).bits(), + Ib = OperandCodeBuilder::new().with_imm(false, 0).special_case(32).bits(), + Ibs = OperandCodeBuilder::new().with_imm(true, 0).special_case(33).bits(), + Jvds = OperandCodeBuilder::new().with_imm(true, 1).special_case(32).bits(), + Yv_Xv = OperandCodeBuilder::new().special_case(50).bits(), + + x87_d8 = OperandCodeBuilder::new().special_case(32).bits(), + x87_d9 = OperandCodeBuilder::new().special_case(33).bits(), + x87_da = OperandCodeBuilder::new().special_case(34).bits(), + x87_db = OperandCodeBuilder::new().special_case(35).bits(), + x87_dc = OperandCodeBuilder::new().special_case(36).bits(), + x87_dd = OperandCodeBuilder::new().special_case(37).bits(), + x87_de = OperandCodeBuilder::new().special_case(38).bits(), + x87_df = OperandCodeBuilder::new().special_case(39).bits(), + + Eb_R0 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(0) + .bits(), + AL_Ib = OperandCodeBuilder::new().special_case(33).with_imm(false, 0).bits(), + AX_Ib = OperandCodeBuilder::new().special_case(34).with_imm(false, 0).bits(), + Ib_AL = OperandCodeBuilder::new().special_case(35).with_imm(false, 0).bits(), + Ib_AX = OperandCodeBuilder::new().special_case(36).with_imm(false, 0).bits(), + AX_DX = OperandCodeBuilder::new().special_case(44).bits(), + AL_DX = OperandCodeBuilder::new().special_case(45).bits(), + DX_AX = OperandCodeBuilder::new().special_case(46).bits(), + DX_AL = OperandCodeBuilder::new().special_case(47).bits(), + MOVQ_f30f = OperandCodeBuilder::new().special_case(48).bits(), + + Unsupported = OperandCodeBuilder::new().special_case(49).bits(), + + ModRM_0x0f00 = OperandCodeBuilder::new().read_modrm().special_case(40).bits(), + ModRM_0x0f01 = OperandCodeBuilder::new().read_modrm().special_case(41).bits(), + ModRM_0x0f0d = OperandCodeBuilder::new().read_modrm().special_case(42).bits(), + ModRM_0x0fae = OperandCodeBuilder::new().read_modrm().special_case(43).bits(), + ModRM_0x0fba = OperandCodeBuilder::new().read_modrm().special_case(44).bits(), + ModRM_0xf30fae = OperandCodeBuilder::new().read_modrm().special_case(46).bits(), + ModRM_0x660fae = OperandCodeBuilder::new().read_modrm().special_case(47).bits(), + ModRM_0xf30fc7 = OperandCodeBuilder::new().read_modrm().special_case(48).bits(), + ModRM_0x660f38 = OperandCodeBuilder::new().read_modrm().special_case(49).bits(), + ModRM_0xf20f38 = OperandCodeBuilder::new().read_modrm().special_case(50).bits(), + ModRM_0xf30f38 = OperandCodeBuilder::new().read_modrm().special_case(51).bits(), + ModRM_0x660f3a = OperandCodeBuilder::new().read_modrm().special_case(52).bits(), + ModRM_0x0f38 = OperandCodeBuilder::new().read_modrm().special_case(53).bits(), + ModRM_0x0f3a = OperandCodeBuilder::new().read_modrm().special_case(54).bits(), + ModRM_0x0f71 = OperandCodeBuilder::new().read_modrm().special_case(55).bits(), + ModRM_0x0f72 = OperandCodeBuilder::new().read_modrm().special_case(56).bits(), + ModRM_0x0f73 = OperandCodeBuilder::new().read_modrm().special_case(57).bits(), + ModRM_0x660f12 = OperandCodeBuilder::new().read_modrm().special_case(58).bits(), + ModRM_0x660f16 = OperandCodeBuilder::new().read_modrm().special_case(59).bits(), + ModRM_0x660f71 = OperandCodeBuilder::new().read_modrm().special_case(60).bits(), + ModRM_0x660f72 = OperandCodeBuilder::new().read_modrm().special_case(61).bits(), + ModRM_0x660f73 = OperandCodeBuilder::new().read_modrm().special_case(62).bits(), + ModRM_0x660fc7 = OperandCodeBuilder::new().read_modrm().special_case(63).bits(), + ModRM_0x0fc7 = OperandCodeBuilder::new().read_modrm().special_case(64).bits(), + ModRM_0xc4 = OperandCodeBuilder::new().read_modrm().special_case(65).bits(), + ModRM_0xc5 = OperandCodeBuilder::new().read_modrm().special_case(66).bits(), + // xmmword? + ModRM_0x0f12 = OperandCodeBuilder::new() + .read_modrm() + .op0_is_rrr_and_embedded_instructions() + .read_E() + .reg_mem() + .operand_case(65) + .bits(), + // xmmword? + ModRM_0x0f16 = OperandCodeBuilder::new() + .read_modrm() + .op0_is_rrr_and_embedded_instructions() + .read_E() + .reg_mem() + .operand_case(66) + .bits(), + // encode immediates? + ModRM_0xc0_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(5) + .bits(), + ModRM_0xc1_Ev_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(6) + .bits(), + ModRM_0xd0_Eb_1 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(7) + .bits(), + ModRM_0xd1_Ev_1 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(8) + .bits(), + ModRM_0xd2_Eb_CL = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(9) + .bits(), + ModRM_0xd3_Ev_CL = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(10) + .bits(), + ModRM_0x80_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .with_imm(false, 0) + .byte_operands() + .operand_case(1) + .bits(), + ModRM_0x83_Ev_Ibs = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .with_imm(false, 0) + .operand_case(26) + .bits(), // 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, + ModRM_0x81_Ev_Ivs = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(2) + .bits(), + ModRM_0xc6_Eb_Ib = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(3) + .bits(), + ModRM_0xc7_Ev_Iv = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(4) + .bits(), + ModRM_0xfe_Eb = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(13) + .bits(), + ModRM_0x8f_Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(30) + .bits(), // gap, 0x94 - ModRM_0xff_Ev = 0x95, - ModRM_0xf6 = 0x96, - ModRM_0xf7 = 0x97, - Eb_R0 = 0x98, - Ev = 0x99, - ModRM_0x0f18 = 0x9b, + ModRM_0xff_Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(14) + .bits(), + ModRM_0x0f18 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(58) + .bits(), + ModRM_0xf6 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .byte_operands() + .operand_case(11) + .bits(), + ModRM_0xf7 = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(12) + .bits(), + Ev = OperandCodeBuilder::new() + .read_modrm() + .set_embedded_instructions() + .read_E() + .operand_case(18) + .bits(), + Zv_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 0).bits(), + Zv_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 1).bits(), + Zv_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 2).bits(), + Zv_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 3).bits(), + Zv_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 4).bits(), + Zv_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 5).bits(), + Zv_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 6).bits(), + Zv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_R, 7).bits(), + // Zv_AX_R0 = 0x48, + Zv_AX_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 1).bits(), + Zv_AX_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 2).bits(), + Zv_AX_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 3).bits(), + Zv_AX_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 4).bits(), + Zv_AX_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 5).bits(), + Zv_AX_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 6).bits(), + Zv_AX_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_AX, 7).bits(), + Zb_Ib_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 0).bits(), + Zb_Ib_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 1).bits(), + Zb_Ib_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 2).bits(), + Zb_Ib_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 3).bits(), + Zb_Ib_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 4).bits(), + Zb_Ib_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 5).bits(), + Zb_Ib_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 6).bits(), + Zb_Ib_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zb_Ib_R, 7).bits(), + Zv_Iv_R0 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 0).bits(), + Zv_Iv_R1 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 1).bits(), + Zv_Iv_R2 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 2).bits(), + Zv_Iv_R3 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 3).bits(), + Zv_Iv_R4 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 4).bits(), + Zv_Iv_R5 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 5).bits(), + Zv_Iv_R6 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 6).bits(), + Zv_Iv_R7 = OperandCodeBuilder::new().op0_is_rrr_and_Z_operand(ZOperandCategory::Zv_Iv_R, 7).bits(), + Gv_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(15).bits(), + Gv_Ew = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(16).bits(), + Gv_Ew_LSL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(37).bits(), +// Gdq_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(17).bits(), + Gd_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(40).bits(), + Md_Gd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(51).bits(), + G_E_mm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().with_imm(false, 0).reg_mem().operand_case(29).bits(), + G_E_xmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(22).bits(), + AL_Ob = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(50).bits(), + AL_Xb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(52).bits(), + AX_Ov = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(53).bits(), + AL_Ibs = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().with_imm(false, 0).byte_operands().operand_case(23).bits(), + AX_Ivd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(24).bits(), + + Eb_Gb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().mem_reg().bits(), + Ev_Gv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().mem_reg().bits(), + Gb_Eb = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().byte_operands().only_modrm_operands().reg_mem().bits(), + Gv_Ev = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().bits(), + Gv_M = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().only_modrm_operands().reg_mem().operand_case(25).bits(), + Gb_Eb_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().with_imm(false, 0).byte_operands().reg_mem().operand_case(40).bits(), + Gv_Ev_Iv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(41).bits(), + Rv_Gmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_modrm().read_E().reg_mem().operand_case(55).bits(), // 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, + G_xmm_E_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(53).bits(), + G_xmm_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(54).bits(), + U_mm_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(55).bits(), + G_xmm_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(57).bits(), + G_mm_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(58).bits(), + Gd_U_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(59).bits(), + Gv_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(60).bits(), + //= 0x816f, // mirror G_xmm_Edq, but also read an immediate + G_xmm_Ed_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(61).bits(), + G_U_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(62).bits(), + G_M_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(20).bits(), + G_E_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(21).bits(), + E_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(19).bits(), + M_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(63).bits(), + G_E_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(64).bits(), + G_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(65).bits(), + E_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(66).bits(), + Edq_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(67).bits(), + Edq_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(68).bits(), + G_mm_Edq = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(69).bits(), + G_mm_E = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(70).bits(), + Ev_Gv_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(71).bits(), + Ev_Gv_CL = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(72).bits(), + G_mm_U_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(73).bits(), + G_Md_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(74).bits(), + G_mm_Ew_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(75).bits(), + G_E_d = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(76).bits(), + E_G_d = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(77).bits(), + CVT_AA = OperandCodeBuilder::new().special_case(77).bits(), + CVT_DA = OperandCodeBuilder::new().special_case(78).bits(), + Rq_Cq_0 = OperandCodeBuilder::new().special_case(79).bits(), + Rq_Dq_0 = OperandCodeBuilder::new().special_case(80).bits(), + Cq_Rq_0 = OperandCodeBuilder::new().special_case(81).bits(), + Dq_Rq_0 = OperandCodeBuilder::new().special_case(82).bits(), + FS = OperandCodeBuilder::new().special_case(83).bits(), + GS = OperandCodeBuilder::new().special_case(84).bits(), + Yb_DX = OperandCodeBuilder::new().special_case(85).bits(), + Yv_DX = OperandCodeBuilder::new().special_case(86).bits(), + DX_Xb = OperandCodeBuilder::new().special_case(87).bits(), + DX_Xv = OperandCodeBuilder::new().special_case(88).bits(), + AH = OperandCodeBuilder::new().special_case(89).bits(), + AX_Xv = OperandCodeBuilder::new().special_case(90).bits(), + Ew_Sw = OperandCodeBuilder::new().special_case(91).bits(), + Fw = OperandCodeBuilder::new().special_case(92).bits(), + I_1 = OperandCodeBuilder::new().special_case(93).bits(), + Iw = OperandCodeBuilder::new().special_case(94).bits(), + Iw_Ib = OperandCodeBuilder::new().special_case(95).bits(), + Ob_AL = OperandCodeBuilder::new().special_case(96).bits(), + Ov_AX = OperandCodeBuilder::new().special_case(97).bits(), + Sw_Ew = OperandCodeBuilder::new().special_case(98).bits(), + Yb_AL = OperandCodeBuilder::new().special_case(99).bits(), + Yb_Xb = OperandCodeBuilder::new().special_case(100).bits(), + Yv_AX = OperandCodeBuilder::new().special_case(101).bits(), + Ew_Gw = OperandCodeBuilder::new().special_case(102).bits(), } fn base_opcode_map(v: u8) -> Opcode { @@ -3580,13 +4045,6 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_xmm), ]; -fn read_opcode_660f_map>(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), @@ -3632,7 +4090,7 @@ const OPCODE_F20F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), - OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SD), OperandCode::G_xmm_Edq), + OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SD), OperandCode::G_xmm_Ed), 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), @@ -3647,7 +4105,7 @@ const OPCODE_F20F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf238), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf20f38), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -3861,13 +4319,6 @@ const OPCODE_F20F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), ]; -fn read_opcode_f20f_map>(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), @@ -3913,7 +4364,7 @@ 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::CVTSI2SS), OperandCode::G_xmm_Edq), + OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SS), OperandCode::G_xmm_Ed), 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), @@ -4142,47 +4593,11 @@ const OPCODE_F30F_MAP: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), ]; -fn read_opcode_f30f_map>(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::LSL), OperandCode::Gv_Ew_LSL), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), @@ -4307,12 +4722,12 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ 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::PCMPEQB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_mm), 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::VMREAD), OperandCode::E_G_d), + OpcodeRecord(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_d), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), @@ -4378,7 +4793,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ 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::BTR), OperandCode::Ev_Gv), 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), @@ -4396,7 +4811,7 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ 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::MOVNTI), OperandCode::Md_Gd), 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), @@ -4420,56 +4835,50 @@ const OPCODE_0F_MAP: [OpcodeRecord; 256] = [ 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), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::G_E_mm), // 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::PAVGB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTQ), OperandCode::G_Md_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::G_E_mm), 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::PSLLW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVQ), OperandCode::G_mm_U_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_mm), + OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_mm), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), ]; -fn read_opcode_0f_map>(bytes_iter: &mut T, length: &mut u8) -> Result { - 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 { @@ -4587,8 +4996,8 @@ const OPCODES: [OpcodeRecord; 256] = [ 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::PUSHA), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::POPA), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::ARPL), OperandCode::Ew_Gw), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), @@ -4648,7 +5057,7 @@ const OPCODES: [OpcodeRecord; 256] = [ 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::WAIT), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::PUSHF), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::POPF), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::SAHF), OperandCode::AH), @@ -4701,7 +5110,7 @@ const OPCODES: [OpcodeRecord; 256] = [ 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::INTO), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::IRET), OperandCode::Fw), // 0xd0 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd0_Eb_1), @@ -4712,32 +5121,28 @@ const OPCODES: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // XLAT - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::XLAT), OperandCode::Nothing), // x86 d8 - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d8), // x86 d9 - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d9), // x86 da - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_da), // x86 db - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_db), // x86 dc - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dc), // x86 dd - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dd), // x86 de - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_de), // x86 df - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Unsupported), + OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_df), // 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::LOOPNZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::LOOPZ), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::LOOP), OperandCode::Ibs), + OpcodeRecord(Interpretation::Instruction(Opcode::JRCXZ), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AL_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AX_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AL), @@ -4754,13 +5159,13 @@ const OPCODES: [OpcodeRecord; 256] = [ // 0xf0 OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), // ICEBP? - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::I_1), 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::CMC), 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), @@ -4784,6 +5189,14 @@ pub(self) fn read_E>(bytes_iter: &mut T, instr: &mut Instru } } #[allow(non_snake_case)] +pub(self) fn read_E_st>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, RegisterBank::ST) + } else { + read_M(bytes_iter, instr, modrm, length) + } +} +#[allow(non_snake_case)] pub(self) fn read_E_xmm>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, RegisterBank::X) @@ -4809,42 +5222,42 @@ fn read_modrm_reg(instr: &mut Instruction, modrm: u8, reg_bank: RegisterBank) -> #[allow(non_snake_case)] fn read_sib>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result { 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 { + let disp = if modbits == 0b00 { + if (sibbyte & 7) == 0b101 { *length += 4; - read_num(bytes_iter, 4)? as i32 - } else if modbits == 0b01 { - *length += 1; - read_num(bytes_iter, 1)? as i8 as i32 + read_num(bytes_iter, 4)? as i32 as u32 } else { - *length += 4; - read_num(bytes_iter, 4)? as i32 - }; + 0 + } + } else if modbits == 0b01 { + *length += 1; + read_num(bytes_iter, 1)? as i8 as i32 as u32 + } else { + *length += 4; + read_num(bytes_iter, 4)? as i32 as u32 + }; + instr.disp = disp; + let op_spec = if (sibbyte & 7) == 0b101 { 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; + instr.modrm_mmm.num |= 0b101; 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.modrm_mmm.num |= 0b101; + instr.sib_index.num |= (sibbyte >> 3) & 7; - instr.sib_index = RegSpec::from_parts((sibbyte >> 3) & 7, addr_width); let scale = 1u8 << (sibbyte >> 6); instr.scale = scale; @@ -4855,7 +5268,6 @@ fn read_sib>(bytes_iter: &mut T, instr: &mut Instruction, m OperandSpec::RegIndexBaseScale } } else { - instr.disp = disp as i32 as u32; if modbits == 0 { OperandSpec::RegScaleDisp } else { @@ -4864,33 +5276,22 @@ fn read_sib>(bytes_iter: &mut T, instr: &mut Instruction, m } } } 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 - }; + instr.modrm_mmm.num |= sibbyte & 7; 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); + instr.sib_index.num |= (sibbyte >> 3) & 7; + let scale = 1u8 << (sibbyte >> 6); instr.scale = scale; if disp == 0 { OperandSpec::RegIndexBaseScale } else { - instr.disp = disp as i32 as u32; OperandSpec::RegIndexBaseScaleDisp } } @@ -4973,17 +5374,17 @@ fn read_M>(bytes_iter: &mut T, instr: &mut Instruction, mod if instr.prefixes.address_size() { return read_M_16bit(bytes_iter, instr, modrm, length); } - let addr_width = RegisterBank::D; + instr.modrm_mmm.bank = 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; + instr.disp = read_num(bytes_iter, 4)?; OperandSpec::DispU32 } else { - instr.modrm_mmm = RegSpec::from_parts(mmm, addr_width); + instr.modrm_mmm.num |= mmm; if modbits == 0b00 { OperandSpec::Deref @@ -5012,8 +5413,7 @@ fn width_to_gp_reg_bank(width: u8) -> RegisterBank { 1 => return RegisterBank::B, 2 => return RegisterBank::W, 4 => return RegisterBank::D, - o => { unreachable!("impossible width: {}", o); } -// _ => unsafe { unreachable_unchecked() } + _ => unsafe { unreachable_unchecked(); } } } @@ -5044,30 +5444,35 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in match bytes_iter.next() { Some(b) => { length += 1; + if length >= 15 { + return Err(DecodeError::TooLong); + } let record = OPCODES[b as usize]; if b == 0x0f { + let b = bytes_iter.next().ok_or(DecodeError::ExhaustedInput)?; + length += 1; let record = match alternate_opcode_map { Some(opcode_map) => { - let (rec, opcode_byte) = match opcode_map { + let rec = match opcode_map { OpcodeMap::Map66 => { - read_opcode_660f_map(&mut bytes_iter, &mut length)? + OPCODE_660F_MAP[b as usize] }, OpcodeMap::MapF2 => { - read_opcode_f20f_map(&mut bytes_iter, &mut length)? + OPCODE_F20F_MAP[b as usize] }, OpcodeMap::MapF3 => { - read_opcode_f30f_map(&mut bytes_iter, &mut length)? + OPCODE_F30F_MAP[b as usize] }, }; 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] + OPCODE_0F_MAP[b as usize] } else { rec } }, None => { - read_opcode_0f_map(&mut bytes_iter, &mut length)? + OPCODE_0F_MAP[b as usize] } }; @@ -5102,10 +5507,6 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in 0x67 => { prefixes.set_address_size(); }, - 0x9b => { - // TODO: WAIT prefix - return Err(DecodeError::IncompleteDecoder); - }, 0xf0 => { prefixes.set_lock(); }, @@ -5115,10 +5516,7 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in 0xf3 => { alternate_opcode_map = Some(OpcodeMap::MapF3); }, -// _ => { unsafe { unreachable_unchecked(); } } - o => { - unreachable!("invalid prefix {:#02x}", o); - } + _ => { unsafe { unreachable_unchecked(); } } } } }, @@ -5127,14 +5525,19 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in } } }; + if record == OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing) { + return Err(DecodeError::InvalidOpcode); + } 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); + unsafe { unreachable_unchecked(); } } instruction.prefixes = prefixes; read_operands(decoder, bytes_iter, instruction, record.1, &mut length)?; + if length > 15 { + return Err(DecodeError::TooLong); + } instruction.length = length; if decoder != &InstDecoder::default() { @@ -5144,289 +5547,213 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in } Ok(()) } +/* likely cases + OperandCode::Eb_R0 => 0 + _op @ OperandCode::ModRM_0x80_Eb_Ib => 1 + _op @ OperandCode::ModRM_0x81_Ev_Ivs => 2 + op @ OperandCode::ModRM_0xc6_Eb_Ib => 3 + op @ OperandCode::ModRM_0xc7_Ev_Iv => 4 + op @ OperandCode::ModRM_0xc0_Eb_Ib => 5 + op @ OperandCode::ModRM_0xc1_Ev_Ib => 6 + op @ OperandCode::ModRM_0xd0_Eb_1 => 7 + op @ OperandCode::ModRM_0xd1_Ev_1 => 8 + op @ OperandCode::ModRM_0xd2_Eb_CL => 9 + op @ OperandCode::ModRM_0xd3_Ev_CL => 10 + _op @ OperandCode::ModRM_0xf6 => 11 + _op @ OperandCode::ModRM_0xf7 => 12 + OperandCode::ModRM_0xfe_Eb => 13 + OperandCode::ModRM_0xff_Ev => 14 + OperandCode::Gv_Eb => 15 + OperandCode::Gv_Ew => 16 + OperandCode::Ev => 18 + OperandCode::E_G_xmm => 19 + op @ OperandCode::G_M_xmm => 20 + op @ OperandCode::G_E_xmm => 21 + OperandCode::G_E_xmm_Ib => 22 + OperandCode::AL_Ibs => 23 + OperandCode::AX_Ivd => 24 + OperandCode::Ivs => 25 + OperandCode::ModRM_0x83_Ev_Ibs => 26 + OperandCode::I_3 => 27 + OperandCode::Nothing => 28 + OperandCode::G_E_mm_Ib => 29 + OperandCode::ModRM_0x8f_Ev => 30 + + */ +#[inline(always)] fn read_operands>(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 => { unreachable!("impossibe op width {}", o) } - }; - instruction.operand_count = 2; + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operand_count = 2; + let operand_code = OperandCodeBuilder::from_bits(operand_code as u16); + if operand_code.has_embedded_instructions() { + match operand_code.get_embedded_instructions() { + Ok(z_operand_code) => { + let reg = z_operand_code.reg(); + match z_operand_code.category() { + 0 => { + // these are Zv_R + let bank = if !instruction.prefixes.operand_size() { + RegisterBank::D + } else { + RegisterBank::W + }; + instruction.modrm_rrr = + RegSpec::from_parts(reg, bank); + instruction.operand_count = 1; + } + 1 => { + // Zv_AX + } + 2 => { + // these are Zb_Ib_R + instruction.modrm_rrr = + RegSpec::from_parts(reg, RegisterBank::B); + instruction.imm = + read_imm_unsigned(&mut bytes_iter, 1, length)?; + instruction.operands[1] = OperandSpec::ImmU8; + } + 3 => { + // category == 3, Zv_Iv_R + if !instruction.prefixes.operand_size() { + instruction.modrm_rrr = + RegSpec::from_parts(reg, RegisterBank::D); + instruction.imm = + read_imm_unsigned(&mut bytes_iter, 4, length)?; + instruction.operands[1] = OperandSpec::ImmI32; + } else { + instruction.modrm_rrr = + RegSpec::from_parts(reg, RegisterBank::W); + instruction.imm = + read_imm_unsigned(&mut bytes_iter, 2, length)?; + instruction.operands[1] = OperandSpec::ImmI16; + } + } + _ => { + unreachable!("bad category"); + } + } + return Ok(()); + }, + // EmbeddedOperandInstructions but those are entirely handled in the fall-through + // below. one day this may grow to be an `Err(the_operand_instructions)` though, so for + // a simpler diff the above is pre-`match`/`Ok`'d. + _ => {} } - return Ok(()); } let mut modrm = 0; - let mut opwidth = 0; + let bank: RegisterBank; let mut mem_oper = OperandSpec::Nothing; - let mut bank = RegisterBank::D; - let code_int = operand_code as u8; - if ((code_int) & 0x80) == 0x80 { + if operand_code.has_read_E() { // cool! we can precompute opwidth and know we need to read_E. - if (code_int & 1) == 1 { + if !operand_code.has_byte_operands() { // further, this is an vd E - opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); - if opwidth == 4 { + if !instruction.prefixes.operand_size() { bank = RegisterBank::D; - } else if opwidth == 2 { + } else { 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); + instruction.modrm_rrr.bank = bank; + instruction.modrm_rrr.num = (modrm >> 3) & 7; - 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) + mem_oper = if modrm >= 0b11000000 { + if operand_code.bits() == (OperandCode::Gv_M as u16) { + return Err(DecodeError::InvalidOperand); + } + read_modrm_reg(instruction, modrm, bank)? } else { - (0, 1) + read_M(&mut bytes_iter, instruction, modrm, length)? }; - instruction.operands[mmm] = mem_oper; - instruction.operands[rrr] = OperandSpec::RegRRR; - instruction.operand_count = 2; - } else if operand_code == OperandCode::Ibs { + instruction.operands[1] = mem_oper; + } + + if let Some((only_imm, immsz)) = operand_code.has_imm() { 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()); + read_imm_signed(&mut bytes_iter, 1 << (immsz * 2), length)? as u32; + if only_imm { + if immsz == 0 { + instruction.operands[0] = OperandSpec::ImmI8; + } else { + instruction.operands[0] = OperandSpec::ImmI32; } + instruction.operand_count = 1; + return Ok(()); + } + } + + if operand_code.is_only_modrm_operands() { + if !operand_code.has_reg_mem() { + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::RegRRR; + }; + } else { +// match operand_code { + match operand_code.special_case_handler_index() { + 0 => { + // turns out xed cand capstone both permit nonzero rrr bits here. + // if (modrm & 0b00111000) != 0 { + // instruction.opcode = Opcode::Invalid; + // return Err(DecodeError::InvalidOperand); + //} 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; - }; + 1 => { + instruction.operands[0] = mem_oper; + instruction.operands[1] = OperandSpec::ImmI8; 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 + 2 => { + instruction.operands[0] = mem_oper; + let numwidth = if instruction.prefixes.operand_size() { + 2 } else { - OperandSpec::DispU16 + 4 }; - 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, + instruction.operands[1] = match numwidth { 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)?; + 3 => { // ModRM_0xc6_Eb_Ib + if modrm == 0xf8 { + instruction.opcode = Opcode::XABORT; + instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32; + instruction.operands[0] = OperandSpec::ImmI8; + instruction.operand_count = 1; + return Ok(()); } - }, - 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)?; + if (modrm & 0b00111000) != 0 { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string()); } - }, - op @ OperandCode::ModRM_0xc6_Eb_Ib | - op @ OperandCode::ModRM_0xc7_Ev_Iv => { + + instruction.operands[0] = mem_oper; + instruction.opcode = Opcode::MOV; + instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32; + instruction.operands[1] = OperandSpec::ImmI8; + instruction.operand_count = 2; + } + 4 => { // ModRM_0xc7_Ev_Iv if modrm == 0xf8 { - if op == OperandCode::ModRM_0xc6_Eb_Ib { - instruction.opcode = Opcode::XABORT; - instruction.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32; - instruction.operands[0] = OperandSpec::ImmI8; - instruction.operand_count = 1; - return Ok(()); + instruction.opcode = Opcode::XBEGIN; + instruction.imm = if instruction.prefixes.operand_size() { + read_imm_signed(&mut bytes_iter, 2, length)? as i16 as i32 as u32 } else { - instruction.opcode = Opcode::XBEGIN; - instruction.imm = if opwidth == 2 { - read_imm_signed(&mut bytes_iter, 2, length)? as i16 as i32 as u32 - } else { - read_imm_signed(&mut bytes_iter, 4, length)? as i32 as u32 - }; - instruction.operands[0] = OperandSpec::ImmI32; - instruction.operand_count = 1; - return Ok(()); - } + read_imm_signed(&mut bytes_iter, 4, length)? as i32 as u32 + }; + instruction.operands[0] = OperandSpec::ImmI32; + instruction.operand_count = 1; + return Ok(()); } if (modrm & 0b00111000) != 0 { instruction.opcode = Opcode::Invalid; @@ -5435,30 +5762,32 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, instruction.operands[0] = mem_oper; instruction.opcode = Opcode::MOV; - let numwidth = if opwidth == 8 { 4 } else { opwidth }; - instruction.imm = read_imm_signed(&mut bytes_iter, numwidth, length)? as u32; - instruction.operands[1] = match opwidth { - 1 => OperandSpec::ImmI8, - 2 => OperandSpec::ImmI16, - 4 => OperandSpec::ImmI32, - _ => unsafe { unreachable_unchecked() } - }; - instruction.operand_count = 2; + if instruction.prefixes.operand_size() { + instruction.imm = read_imm_signed(&mut bytes_iter, 2, length)? as u32; + instruction.operands[1] = OperandSpec::ImmI16; + } else { + instruction.imm = read_imm_signed(&mut bytes_iter, 4, length)? as u32; + instruction.operands[1] = OperandSpec::ImmI32; + } }, - 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 => { + op @ 5 | + op @ 6 | + op @ 7 | + op @ 8 | + op @ 9 | + op @ 10 => { instruction.operands[0] = mem_oper; instruction.opcode = BITWISE_OPCODE_MAP[((modrm >> 3) & 7) as usize].clone(); - if let OperandCode::ModRM_0xd3_Ev_CL = op { + if op == 10 { + instruction.modrm_rrr = RegSpec::cl(); + instruction.operands[1] = OperandSpec::RegRRR; + } else if op == 9 { 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 => { + 5 | + 6 => { *length += 1; read_num(&mut bytes_iter, 1)? } @@ -5472,8 +5801,17 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, } instruction.operand_count = 2; }, - _op @ OperandCode::ModRM_0xf6 | - _op @ OperandCode::ModRM_0xf7 => { + op @ 11 | + op @ 12 => { + let opwidth = if op == 11 { + 1 + } else { + if instruction.prefixes.operand_size() { + 2 + } else { + 4 + } + }; instruction.operands[0] = mem_oper; instruction.operand_count = 1; match (modrm >> 3) & 7 { @@ -5511,22 +5849,24 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, } } }, - OperandCode::ModRM_0xfe_Eb => { + 13 => { instruction.operands[0] = mem_oper; + let r = (modrm >> 3) & 7; + if r >= 2 { + return Err(DecodeError::InvalidOpcode); + } instruction.opcode = [ Opcode::INC, Opcode::DEC, - Opcode::Invalid, - Opcode::Invalid, - Opcode::Invalid, - Opcode::Invalid, - Opcode::Invalid, - Opcode::Invalid - ][((modrm >> 3) & 7) as usize]; + ][r as usize]; instruction.operand_count = 1; } - OperandCode::ModRM_0xff_Ev => { + 14 => { instruction.operands[0] = mem_oper; + let r = (modrm >> 3) & 7; + if r == 7 { + return Err(DecodeError::InvalidOpcode); + } let opcode = [ Opcode::INC, Opcode::DEC, @@ -5535,8 +5875,7 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, Opcode::JMP, Opcode::JMPF, Opcode::PUSH, - Opcode::Invalid - ][((modrm >> 3) & 7) as usize]; + ][r as usize]; if instruction.operands[0] == OperandSpec::RegMMM { if opcode == Opcode::CALL || opcode == Opcode::JMP { instruction.modrm_mmm.bank = RegisterBank::D; @@ -5547,92 +5886,48 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, instruction.opcode = opcode; instruction.operand_count = 1; } - OperandCode::Gv_Eb => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + 15 => { 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.modrm_rrr = if instruction.prefixes.operand_size() { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W) + } else { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D) + }; instruction.operand_count = 2; }, - OperandCode::Gv_Ew => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + 16 => { 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.modrm_rrr = if instruction.prefixes.operand_size() { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W) + } else { + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D) + }; instruction.operand_count = 2; }, - OperandCode::Ev => { + 18 => { 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); + 19 => { + instruction.modrm_rrr.bank = RegisterBank::X; + instruction.operands[0] = mem_oper; 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; + if instruction.operands[0] == OperandSpec::RegMMM { + // fix the register to XMM + instruction.modrm_mmm.bank = RegisterBank::X; } - 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; + op @ 20 | + op @ 21 => { 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 { + if op == 20 { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); } else { @@ -5641,64 +5936,34 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, } } }, - OperandCode::G_E_xmm_Ib => { + 22 => { 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; - if instruction.operands[1] == OperandSpec::RegMMM { - instruction.modrm_mmm.bank = RegisterBank::MM; - } - 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 => { + 23 => { 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); + 24 => { + let opwidth = if instruction.prefixes.operand_size() { + instruction.modrm_rrr = + RegSpec::from_parts(0, RegisterBank::W); + 2 + } else { + instruction.modrm_rrr = + RegSpec::from_parts(0, RegisterBank::D); + 4 + }; instruction.imm = read_imm_signed(&mut bytes_iter, opwidth, length)? as u32; instruction.operands[1] = match opwidth { @@ -5708,8 +5973,12 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, }; instruction.operand_count = 2; } - OperandCode::Ivs => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + 25 => { + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; instruction.imm = read_imm_unsigned(&mut bytes_iter, opwidth, length)?; instruction.operands[0] = match opwidth { @@ -5719,40 +5988,124 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, }; instruction.operand_count = 1; }, - OperandCode::ModRM_0x83_Ev_Ibs => { + 26 => { 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; + 27 => { + instruction.imm = 3; + instruction.operands[0] = OperandSpec::ImmU8; instruction.operand_count = 1; - instruction.operands[0] = OperandSpec::ImmI32; } + 28 => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + return Ok(()); + }, + 29 => { + instruction.modrm_rrr = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 }; + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.modrm_mmm.bank = RegisterBank::MM; + } + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + }, + 30 => { + instruction.operands[0] = mem_oper; + let r = (modrm >> 3) & 7; + if r >= 1 { + return Err(DecodeError::InvalidOpcode); + } + instruction.opcode = [ + Opcode::POP, + ][r as usize]; + instruction.operand_count = 1; + } + _ => { + let operand_code: OperandCode = unsafe { core::mem::transmute(operand_code.bits()) }; + unlikely_operands(decoder, bytes_iter, instruction, operand_code, mem_oper, length)?; + } + }; + } + + Ok(()) +} +fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, length: &mut u8) -> Result<(), DecodeError> { + match operand_code { + 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::from_parts((modrm >> 3) & 7, if instruction.prefixes.operand_size() { RegisterBank::W } else { RegisterBank::D }); + 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::from_parts((modrm >> 3) & 7, if instruction.prefixes.operand_size() { RegisterBank::W } else { RegisterBank::D }); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_M(&mut bytes_iter, instruction, modrm, length)?; + } + }, + OperandCode::G_U_xmm => { + 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; + }, 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; + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; instruction.imm = - read_imm_signed(&mut bytes_iter, numwidth, length)? as u32; + read_imm_signed(&mut bytes_iter, opwidth, length)? as u32; instruction.operands[2] = match opwidth { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, - o => { unreachable!("impossible opwidth: {}", o); } -// _ => unsafe { unreachable_unchecked() } + _ => unsafe { unreachable_unchecked() } }; instruction.operand_count = 3; } @@ -5767,38 +6120,228 @@ fn read_operands>(decoder: &InstDecoder, mut bytes_iter: T, OperandCode::Ev_Gv_CL => { instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; - instruction.operands[2] = OperandSpec::CL; + instruction.operands[2] = OperandSpec::RegVex; + instruction.vex_reg = RegSpec::cl(); instruction.operand_count = 3; } - OperandCode::Nothing => { - instruction.operand_count = 0; - } - _ => { - unlikely_operands(decoder, bytes_iter, instruction, operand_code, mem_oper, length)?; + 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); + 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::G_E_mm => { + 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.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::Gv_Ew_LSL => { + let modrm = read_modrm(&mut bytes_iter, length)?; + if instruction.prefixes.operand_size() { + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W); + } else { + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + }; - Ok(()) -} -fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec, length: &mut u8) -> Result<(), DecodeError> { - match operand_code { + instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?; + // lsl is weird. the full register width is written, but only the low 16 bits are used. + if instruction.operands[1] == OperandSpec::RegMMM { + instruction.modrm_mmm.bank = RegisterBank::D; + } + instruction.operand_count = 2; + }, + OperandCode::Gd_Ev => { + let modrm = read_modrm(&mut bytes_iter, length)?; + +// println!("mod_bits: {:2b}, r: {:3b}, m: {:3b}", mod_bits, r, m); + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; + instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operand_count = 2; + }, + op @ OperandCode::AL_Ob | + op @ OperandCode::AX_Ov => { + instruction.modrm_rrr = match op { + OperandCode::AL_Ob => RegSpec::al(), + OperandCode::AX_Ov => { + if instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() + } + } + _ => { + unsafe { unreachable_unchecked() } + } + }; + 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; + 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 => { + instruction.modrm_rrr = match op { + OperandCode::Ob_AL => RegSpec::al(), + OperandCode::Ov_AX => { + if instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() + } + } + _ => { + unsafe { unreachable_unchecked() } + } + }; + 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::DispU16 + } else { + OperandSpec::DispU32 + }; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::I_1 => { + instruction.imm = 1; + instruction.operands[0] = OperandSpec::ImmU8; + instruction.operand_count = 1; + } OperandCode::Unsupported => { return Err(DecodeError::IncompleteDecoder); } + OperandCode::Iw_Ib => { + instruction.disp = read_num(&mut bytes_iter, 2)?; + instruction.imm = read_num(&mut bytes_iter, 1)?; + instruction.operands[0] = OperandSpec::EnterFrameSize; + instruction.operands[1] = OperandSpec::ImmU8; + instruction.operand_count = 2; + *length += 3; + } + OperandCode::Fw => { + if instruction.prefixes.operand_size() { + instruction.opcode = Opcode::IRET; + } else { + instruction.opcode = Opcode::IRETD; + } + instruction.operand_count = 0; + } + OperandCode::Md_Gd => { + let opwidth = 4; + let modrm = read_modrm(&mut bytes_iter, length)?; + + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operand_count = 2; + + } + OperandCode::G_mm_U_mm => { + instruction.modrm_rrr.bank = RegisterBank::MM; + if mem_oper != OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.modrm_mmm.bank = RegisterBank::MM; + instruction.modrm_mmm.num &= 0b111; + instruction.modrm_rrr.num &= 0b111; + instruction.operand_count = 2; + }, + OperandCode::E_G_d => { + if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOpcode); + } + + let modrm = read_modrm(&mut bytes_iter, length)?; + + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operand_count = 2; + } + OperandCode::G_E_d => { + if instruction.prefixes.operand_size() { + return Err(DecodeError::InvalidOpcode); + } + + let modrm = read_modrm(&mut bytes_iter, length)?; + + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); + instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?; + instruction.operand_count = 2; + } + OperandCode::G_Md_mm => { + instruction.operands[1] = instruction.operands[0]; + instruction.operands[0] = mem_oper; + instruction.modrm_rrr.bank = RegisterBank::MM; + if mem_oper == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.modrm_rrr.num &= 0b111; + instruction.operand_count = 2; + }, 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_0x0f0d => { let modrm = read_modrm(&mut bytes_iter, length)?; let r = (modrm >> 3) & 0b111; - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; match r { 1 => { @@ -5820,7 +6363,12 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter let operands = match high { 0 => { // PqQq - OperandCode::G_E_mm + if low != 0x0f { + OperandCode::G_E_mm + } else { + // PALIGNR + OperandCode::G_E_mm_Ib + } }, 1 => { // PqQq @@ -5846,6 +6394,25 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } }; instruction.opcode = match opcode { + 0x00 => Opcode::PSHUFB, + 0x01 => Opcode::PHADDW, + 0x02 => Opcode::PHADDD, + 0x03 => Opcode::PHADDSW, + 0x04 => Opcode::PMADDUBSW, + 0x05 => Opcode::PHSUBW, + 0x06 => Opcode::PHSUBD, + 0x07 => Opcode::PHSUBSW, + 0x08 => Opcode::PSIGNB, + 0x09 => Opcode::PSIGNW, + 0x0a => Opcode::PSIGND, + 0x0b => Opcode::PMULHRSW, + + 0x0f => Opcode::PALIGNR, + + 0x1c => Opcode::PABSB, + 0x1d => Opcode::PABSW, + 0x1e => Opcode::PABSD, + 0xc8 => Opcode::SHA1NEXTE, 0xc9 => Opcode::SHA1MSG1, 0xca => Opcode::SHA1MSG2, @@ -5932,7 +6499,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = opcode; instruction.operand_count = 1; - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?; }, OperandCode::ModRM_0x0f71 => { @@ -6030,7 +6601,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } 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; } @@ -6045,10 +6615,26 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } 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_0xf20f38 => { + let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?; + match op { + 0xf0 => { + instruction.opcode = Opcode::CRC32; + return read_operands(decoder, bytes_iter, instruction, OperandCode::Gv_Eb, length); + } + 0xf1 => { + instruction.opcode = Opcode::CRC32; + return read_operands(decoder, bytes_iter, instruction, OperandCode::Gd_Ev, length); + } + _ => { + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidOpcode); + } + }; + } OperandCode::ModRM_0xf30f38 => { let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?; match op { @@ -6065,6 +6651,64 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter OperandCode::ModRM_0x660f38 => { let op = bytes_iter.next().ok_or(DecodeError::ExhaustedInput).map(|b| { *length += 1; b })?; match op { + 0x00 => { instruction.opcode = Opcode::PSHUFB; } + 0x01 => { instruction.opcode = Opcode::PHADDW; } + 0x02 => { instruction.opcode = Opcode::PHADDD; } + 0x03 => { instruction.opcode = Opcode::PHADDSW; } + 0x04 => { instruction.opcode = Opcode::PMADDUBSW; } + 0x05 => { instruction.opcode = Opcode::PHSUBW; } + 0x06 => { instruction.opcode = Opcode::PHSUBD; } + 0x07 => { instruction.opcode = Opcode::PHSUBSW; } + 0x08 => { instruction.opcode = Opcode::PSIGNB; } + 0x09 => { instruction.opcode = Opcode::PSIGNW; } + 0x0a => { instruction.opcode = Opcode::PSIGND; } + 0x0b => { instruction.opcode = Opcode::PMULHRSW; } + 0x0c => { instruction.opcode = Opcode::BLENDPS; } + 0x0d => { instruction.opcode = Opcode::BLENDPD; } + + 0x10 => { instruction.opcode = Opcode::PBLENDVB; } + + 0x14 => { instruction.opcode = Opcode::BLENDVPS; } + 0x15 => { instruction.opcode = Opcode::BLENDVPD; } + + 0x17 => { instruction.opcode = Opcode::PTEST; } + + 0x1c => { instruction.opcode = Opcode::PABSB; } + 0x1d => { instruction.opcode = Opcode::PABSW; } + 0x1e => { instruction.opcode = Opcode::PABSD; } + + 0x20 => { instruction.opcode = Opcode::PMOVSXBW; } + 0x21 => { instruction.opcode = Opcode::PMOVSXBD; } + 0x22 => { instruction.opcode = Opcode::PMOVSXBQ; } + 0x23 => { instruction.opcode = Opcode::PMOVSXWD; } + 0x24 => { instruction.opcode = Opcode::PMOVSXWQ; } + 0x25 => { instruction.opcode = Opcode::PMOVSXDQ; } + + 0x28 => { instruction.opcode = Opcode::PMULDQ; } + 0x29 => { instruction.opcode = Opcode::PCMPEQQ; } + 0x2a => { instruction.opcode = Opcode::MOVNTDQA; } + 0x2b => { instruction.opcode = Opcode::PACKUSDW; } + + 0x30 => { instruction.opcode = Opcode::PMOVZXBW; } + 0x31 => { instruction.opcode = Opcode::PMOVZXBD; } + 0x32 => { instruction.opcode = Opcode::PMOVZXBQ; } + 0x33 => { instruction.opcode = Opcode::PMOVZXWD; } + 0x34 => { instruction.opcode = Opcode::PMOVZXWQ; } + 0x35 => { instruction.opcode = Opcode::PMOVZXDQ; } + + 0x37 => { instruction.opcode = Opcode::PCMPGTQ; } + 0x38 => { instruction.opcode = Opcode::PMINSB; } + 0x39 => { instruction.opcode = Opcode::PMINSD; } + 0x3a => { instruction.opcode = Opcode::PMINUW; } + 0x3b => { instruction.opcode = Opcode::PMINUD; } + 0x3c => { instruction.opcode = Opcode::PMAXSB; } + 0x3d => { instruction.opcode = Opcode::PMAXSD; } + 0x3e => { instruction.opcode = Opcode::PMAXUW; } + 0x3f => { instruction.opcode = Opcode::PMAXUD; } + + 0x40 => { instruction.opcode = Opcode::PMULLD; } + 0x41 => { instruction.opcode = Opcode::PHMINPOSUW; } + 0xdb => { instruction.opcode = Opcode::AESIMC; } 0xdc => { instruction.opcode = Opcode::AESENC; } 0xdd => { instruction.opcode = Opcode::AESENCLAST; } @@ -6085,13 +6729,93 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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 { + 0x08 => { + instruction.opcode = Opcode::ROUNDPS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x09 => { + instruction.opcode = Opcode::ROUNDPD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x0a => { + instruction.opcode = Opcode::ROUNDSS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x0b => { + instruction.opcode = Opcode::ROUNDSD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x0e => { + instruction.opcode = Opcode::PBLENDW; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x0f => { + instruction.opcode = Opcode::PALIGNR; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x14 => { + instruction.opcode = Opcode::PEXTRB; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x15 => { + instruction.opcode = Opcode::PEXTRW; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x16 => { + instruction.opcode = Opcode::PEXTRD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x17 => { + instruction.opcode = Opcode::EXTRACTPS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x20 => { + instruction.opcode = Opcode::PINSRB; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x21 => { + instruction.opcode = Opcode::INSERTPS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x22 => { + instruction.opcode = Opcode::PINSRD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x40 => { + instruction.opcode = Opcode::DPPS; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x41 => { + instruction.opcode = Opcode::DPPD; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x42 => { + instruction.opcode = Opcode::MPSADBW; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + + 0x60 => { + instruction.opcode = Opcode::PCMPESTRM; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x61 => { + instruction.opcode = Opcode::PCMPESTRI; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x62 => { + instruction.opcode = Opcode::PCMPISTRM; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } + 0x63 => { + instruction.opcode = Opcode::PCMPISTRI; + return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length); + } 0xcc => { instruction.opcode = Opcode::SHA1RNDS4; @@ -6100,7 +6824,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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)?; @@ -6116,7 +6839,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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)?; @@ -6220,7 +6942,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[1] = OperandSpec::ImmU8; }, OperandCode::ModRM_0x660fc7 => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; let modrm = read_modrm(&mut bytes_iter, length)?; let r = (modrm >> 3) & 7; @@ -6318,7 +7044,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } } OperandCode::ModRM_0xf30fc7 => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; let modrm = read_modrm(&mut bytes_iter, length)?; let r = (modrm >> 3) & 7; @@ -6347,7 +7077,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } }, 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 { @@ -6355,7 +7084,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } } 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 { @@ -6390,25 +7118,9 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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.operand_count = 3; instruction.imm = read_num(&mut bytes_iter, 1)?; *length += 1; @@ -6418,14 +7130,12 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } }, 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 { @@ -6434,7 +7144,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter }, 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; @@ -6445,8 +7154,21 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } } }, + OperandCode::Rv_Gmm_Ib => { + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + instruction.imm = + read_num(&mut bytes_iter, 1)?; + *length += 1; + instruction.modrm_rrr.bank = RegisterBank::D; + if mem_oper == OperandSpec::RegMMM { + instruction.modrm_mmm.bank = RegisterBank::MM; + instruction.modrm_mmm.num &= 0b111; + } else { + 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; @@ -6457,35 +7179,39 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } // sure hope these aren't backwards huh OperandCode::AL_Xb => { - instruction.operands[0] = OperandSpec::AL; - instruction.operands[1] = OperandSpec::Deref_esi; + instruction.modrm_rrr = RegSpec::al(); + instruction.modrm_mmm = RegSpec::esi(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::Deref; + instruction.operand_count = 2; } // TODO: two memory operands! this is wrong!!! OperandCode::Yb_Xb => { instruction.operands[0] = OperandSpec::Deref_edi; instruction.operands[1] = OperandSpec::Deref_esi; + instruction.operand_count = 2; } OperandCode::Yb_AL => { - instruction.operands[0] = OperandSpec::Deref_edi; - instruction.operands[1] = OperandSpec::AL; + instruction.modrm_rrr = RegSpec::al(); + instruction.modrm_mmm = RegSpec::esi(); + instruction.operands[0] = OperandSpec::Deref; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; } 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_rrr = if instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() }; 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_rrr = if instruction.prefixes.operand_size() { + RegSpec::ax() + } else { + RegSpec::eax() }; instruction.modrm_mmm = RegSpec::edi(); instruction.operands[0] = OperandSpec::Deref; @@ -6522,6 +7248,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } let rrr = instruction.modrm_rrr.num & 0b111; instruction.operands[0] = mem_oper; + instruction.operand_count = 1; instruction.opcode = match rrr { 0 => Opcode::PREFETCHNTA, 1 => Opcode::PREFETCH0, @@ -6531,7 +7258,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter }; } OperandCode::Gd_U_xmm => { - instruction.operands[1] = mem_oper; if instruction.operands[1] != OperandSpec::RegMMM { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOperand); @@ -6540,7 +7266,6 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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; } @@ -6554,6 +7279,15 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } instruction.modrm_rrr.bank = RegisterBank::X; } + OperandCode::Ew_Gw => { + let modrm = read_modrm(&mut bytes_iter, length)?; + + instruction.modrm_rrr = + RegSpec { bank: RegisterBank::W, num: (modrm >> 3) & 7 }; + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + }, OperandCode::Ew_Sw => { let opwidth = 2; let modrm = read_modrm(&mut bytes_iter, length)?; @@ -6602,24 +7336,24 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } }, 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"); }, - } + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + instruction.opcode = if !instruction.prefixes.operand_size() { + Opcode::CWDE + } else { + Opcode::CBW + }; } OperandCode::CVT_DA => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); - instruction.opcode = match opwidth { - 2 => { Opcode::CWD }, - 4 => { Opcode::CDQ }, - _ => { unreachable!("invalid operation width"); }, - } + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + instruction.opcode = if !instruction.prefixes.operand_size() { + Opcode::CDQ + } else { + Opcode::CWD + }; } OperandCode::Ib => { - instruction.imm = - read_imm_unsigned(&mut bytes_iter, 1, length)?; instruction.operands[0] = OperandSpec::ImmU8; instruction.operand_count = 1; } @@ -6647,10 +7381,12 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.opcode = Opcode::VERW; } else if r == 6 { instruction.opcode = Opcode::JMPE; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Ok(()); } else if r == 7 { instruction.opcode = Opcode::Invalid; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOperand); } else { @@ -6659,13 +7395,18 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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 opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; 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.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; match m { 0b000 => { @@ -6697,6 +7438,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; match m { 0b000 => { @@ -6728,6 +7470,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; match m { 0b000 => { @@ -6771,6 +7514,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter }, 0b001 => { instruction.opcode = Opcode::VMMCALL; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; }, 0b010 => { @@ -6787,10 +7531,12 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter }, 0b100 => { instruction.opcode = Opcode::STGI; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; }, 0b101 => { instruction.opcode = Opcode::CLGI; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; }, 0b110 => { @@ -6809,6 +7555,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter }, _ => { instruction.opcode = Opcode::Invalid; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOperand); } @@ -6820,7 +7567,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } } else if r == 4 { // TODO: this permits storing only to word-size registers - // spec suggets this might do something different for f.ex edi? + // spec suggets this might do something different for f.ex rdi? instruction.opcode = Opcode::SMSW; instruction.operand_count = 1; instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?; @@ -6829,14 +7576,17 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter match m { 0b110 => { instruction.opcode = Opcode::RDPKRU; - instruction.operand_count = 1; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; } 0b111 => { instruction.opcode = Opcode::WRPKRU; - instruction.operand_count = 1; + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; } _ => { instruction.opcode = Opcode::Invalid; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOpcode); } @@ -6851,9 +7601,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter if mod_bits == 0b11 { if m == 0 { instruction.opcode = Opcode::SWAPGS; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else if m == 1 { instruction.opcode = Opcode::RDTSCP; + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else { instruction.opcode = Opcode::Invalid; @@ -6875,6 +7627,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter // all the 0b11 instructions are err or no-operands if mod_bits == 0b11 { + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; let m = modrm & 7; match r { @@ -6933,7 +7686,11 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter } } OperandCode::ModRM_0x0fba => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); + let opwidth = if instruction.prefixes.operand_size() { + 2 + } else { + 4 + }; let modrm = read_modrm(&mut bytes_iter, length)?; let r = (modrm >> 3) & 7; match r { @@ -6960,7 +7717,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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.imm = read_imm_signed(&mut bytes_iter, 1, length)? as u32; instruction.operands[1] = OperandSpec::ImmI8; instruction.operand_count = 2; } @@ -7004,31 +7761,19 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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 { + instruction.modrm_rrr = if !instruction.prefixes.operand_size() { 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; @@ -7036,30 +7781,22 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter 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 { + instruction.modrm_rrr = if !instruction.prefixes.operand_size() { 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 { + instruction.modrm_rrr = if !instruction.prefixes.operand_size() { RegSpec::eax() } else { RegSpec::ax() @@ -7077,8 +7814,7 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operand_count = 2; } OperandCode::DX_AX => { - let opwidth = imm_width_from_prefixes(SizeCode::vd, instruction.prefixes); - instruction.modrm_rrr = if opwidth == 4 { + instruction.modrm_rrr = if !instruction.prefixes.operand_size() { RegSpec::eax() } else { RegSpec::ax() @@ -7095,16 +7831,470 @@ fn unlikely_operands>(decoder: &InstDecoder, mut bytes_iter instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } + OperandCode::Yb_DX => { + instruction.modrm_rrr = RegSpec::dl(); + instruction.modrm_mmm = RegSpec::edi(); + instruction.operands[0] = OperandSpec::Deref; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::Yv_DX => { + instruction.modrm_rrr = RegSpec::dx(); + instruction.modrm_mmm = RegSpec::edi(); + instruction.operands[0] = OperandSpec::Deref; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; + } + OperandCode::DX_Xb => { + instruction.modrm_rrr = RegSpec::dl(); + instruction.modrm_mmm = RegSpec::esi(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::Deref; + instruction.operand_count = 2; + } + OperandCode::AH => { + instruction.operands[0] = OperandSpec::Nothing; + instruction.operand_count = 0; + } + OperandCode::DX_Xv => { + instruction.modrm_rrr = RegSpec::dx(); + instruction.modrm_mmm = RegSpec::esi(); + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = OperandSpec::Deref; + instruction.operand_count = 2; + } + OperandCode::x87_d8 | + OperandCode::x87_d9 | + OperandCode::x87_da | + OperandCode::x87_db | + OperandCode::x87_dc | + OperandCode::x87_dd | + OperandCode::x87_de | + OperandCode::x87_df => { + return decode_x87(decoder, bytes_iter, instruction, operand_code, length); + } _ => { + // TODO: this should be unreachable - safe to panic now? + // can't simply delete this arm because the non-unlikely operands are handled outside + // here, and some operands are entirely decoded before reaching match in the first + // place. + // perhaps fully-decoded operands could be a return here? they would be jump table + // entries anyway, so no extra space for the dead arms. + instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; instruction.opcode = Opcode::Invalid; -// return Err(()); // Err(format!("unsupported operand code: {:?}", operand_code)); return Err(DecodeError::InvalidOperand); } }; Ok(()) } +fn decode_x87>(_decoder: &InstDecoder, mut bytes_iter: T, instruction: &mut Instruction, operand_code: OperandCode, length: &mut u8) -> Result<(), DecodeError> { + #[allow(non_camel_case_types)] + enum OperandCodeX87 { + Est, + St_Est, + St_Ew, + St_Md, + Md, + Ew, + Est_St, + Ed_St, + Md_St, + Ex87S, + Nothing, + } + + // every x87 instruction is conditional on rrr bits + let modrm = read_modrm(&mut bytes_iter, length)?; + let r = (modrm >> 3) & 0b111; + + let (opcode, x87_operands) = match operand_code { + OperandCode::x87_d8 => { + match r { + 0 => (Opcode::FADD, OperandCodeX87::St_Est), + 1 => (Opcode::FMUL, OperandCodeX87::St_Est), + 2 => (Opcode::FCOM, OperandCodeX87::St_Est), + 3 => (Opcode::FCOMP, OperandCodeX87::St_Est), + 4 => (Opcode::FSUB, OperandCodeX87::St_Est), + 5 => (Opcode::FSUBR, OperandCodeX87::St_Est), + 6 => (Opcode::FDIV, OperandCodeX87::St_Est), + 7 => (Opcode::FDIVR, OperandCodeX87::St_Est), + _ => { unreachable!("impossible r"); } + } + } + OperandCode::x87_d9 => { + match r { + 0 => (Opcode::FLD, OperandCodeX87::St_Est), + 1 => { + if modrm >= 0xc0 { + (Opcode::FXCH, OperandCodeX87::St_Est) + } else { + return Err(DecodeError::InvalidOpcode); + } + }, + 2 => { + if modrm >= 0xc0 { + if modrm == 0xd0 { + (Opcode::FNOP, OperandCodeX87::Nothing) + } else { + return Err(DecodeError::InvalidOpcode); + } + } else { + (Opcode::FST, OperandCodeX87::Ed_St) + } + } + 3 => { + if modrm >= 0xc0 { + (Opcode::FSTPNCE, OperandCodeX87::Est_St) + } else { + (Opcode::FSTP, OperandCodeX87::Est_St) + } + }, + 4 => { + if modrm >= 0xc0 { + match modrm { + 0xe0 => (Opcode::FCHS, OperandCodeX87::Nothing), + 0xe1 => (Opcode::FABS, OperandCodeX87::Nothing), + 0xe2 => { return Err(DecodeError::InvalidOpcode); }, + 0xe3 => { return Err(DecodeError::InvalidOpcode); }, + 0xe4 => (Opcode::FTST, OperandCodeX87::Nothing), + 0xe5 => (Opcode::FXAM, OperandCodeX87::Nothing), + 0xe6 => { return Err(DecodeError::InvalidOpcode); }, + 0xe7 => { return Err(DecodeError::InvalidOpcode); }, + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FLDENV, OperandCodeX87::Ex87S) // x87 state + } + }, + 5 => { + if modrm >= 0xc0 { + match modrm { + 0xe8 => (Opcode::FLD1, OperandCodeX87::Nothing), + 0xe9 => (Opcode::FLDL2T, OperandCodeX87::Nothing), + 0xea => (Opcode::FLDL2E, OperandCodeX87::Nothing), + 0xeb => (Opcode::FLDPI, OperandCodeX87::Nothing), + 0xec => (Opcode::FLDLG2, OperandCodeX87::Nothing), + 0xed => (Opcode::FLDLN2, OperandCodeX87::Nothing), + 0xee => (Opcode::FLDZ, OperandCodeX87::Nothing), + 0xef => (Opcode::Invalid, OperandCodeX87::Nothing), + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FLDCW, OperandCodeX87::Ew) + } + } + 6 => { + if modrm >= 0xc0 { + match modrm { + 0xf0 => (Opcode::F2XM1, OperandCodeX87::Nothing), + 0xf1 => (Opcode::FYL2X, OperandCodeX87::Nothing), + 0xf2 => (Opcode::FPTAN, OperandCodeX87::Nothing), + 0xf3 => (Opcode::FPATAN, OperandCodeX87::Nothing), + 0xf4 => (Opcode::FXTRACT, OperandCodeX87::Nothing), + 0xf5 => (Opcode::FPREM1, OperandCodeX87::Nothing), + 0xf6 => (Opcode::FDECSTP, OperandCodeX87::Nothing), + 0xf7 => (Opcode::FINCSTP, OperandCodeX87::Nothing), + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FNSTENV, OperandCodeX87::Ex87S) // x87 state + } + } + 7 => { + if modrm >= 0xc0 { + match modrm { + 0xf8 => (Opcode::FPREM, OperandCodeX87::Nothing), + 0xf9 => (Opcode::FYL2XP1, OperandCodeX87::Nothing), + 0xfa => (Opcode::FSQRT, OperandCodeX87::Nothing), + 0xfb => (Opcode::FSINCOS, OperandCodeX87::Nothing), + 0xfc => (Opcode::FRNDINT, OperandCodeX87::Nothing), + 0xfd => (Opcode::FSCALE, OperandCodeX87::Nothing), + 0xfe => (Opcode::FSIN, OperandCodeX87::Nothing), + 0xff => (Opcode::FCOS, OperandCodeX87::Nothing), + _ => { unreachable!("invalid modrm"); } + } + } else { + (Opcode::FNSTCW, OperandCodeX87::Ew) + } + } + _ => { unreachable!("impossible r"); } + } + } + OperandCode::x87_da => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FCMOVB, OperandCodeX87::St_Est), + 1 => (Opcode::FCMOVE, OperandCodeX87::St_Est), + 2 => (Opcode::FCMOVBE, OperandCodeX87::St_Est), + 3 => (Opcode::FCMOVU, OperandCodeX87::St_Est), + _ => { + if modrm == 0xe9 { + (Opcode::FUCOMPP, OperandCodeX87::Nothing) + } else { + return Err(DecodeError::InvalidOpcode); + } + } + } + } else { + match r { + 0 => (Opcode::FIADD, OperandCodeX87::St_Md), // 0xd9d0 -> fnop + 1 => (Opcode::FIMUL, OperandCodeX87::St_Md), + 2 => (Opcode::FICOM, OperandCodeX87::St_Md), // FCMOVE + 3 => (Opcode::FICOMP, OperandCodeX87::St_Md), // FCMOVBE + 4 => (Opcode::FISUB, OperandCodeX87::St_Md), + 5 => (Opcode::FISUBR, OperandCodeX87::St_Md), // FUCOMPP + 6 => (Opcode::FIDIV, OperandCodeX87::St_Md), + 7 => (Opcode::FIDIVR, OperandCodeX87::St_Md), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_db => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FCMOVNB, OperandCodeX87::St_Est), + 1 => (Opcode::FCMOVNE, OperandCodeX87::St_Est), + 2 => (Opcode::FCMOVNBE, OperandCodeX87::St_Est), + 3 => (Opcode::FCMOVNU, OperandCodeX87::St_Est), + 4 => { + match modrm { + 0xe0 => (Opcode::FENI8087_NOP, OperandCodeX87::Nothing), + 0xe1 => (Opcode::FDISI8087_NOP, OperandCodeX87::Nothing), + 0xe2 => (Opcode::FNCLEX, OperandCodeX87::Nothing), + 0xe3 => (Opcode::FNINIT, OperandCodeX87::Nothing), + 0xe4 => (Opcode::FSETPM287_NOP, OperandCodeX87::Nothing), + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + 5 => (Opcode::FUCOMI, OperandCodeX87::St_Est), + 6 => (Opcode::FCOMI, OperandCodeX87::St_Est), + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } else { + match r { + 0 => (Opcode::FILD, OperandCodeX87::St_Md), + 1 => (Opcode::FISTTP, OperandCodeX87::Md_St), + 2 => (Opcode::FIST, OperandCodeX87::Md_St), + 3 => (Opcode::FISTP, OperandCodeX87::Md_St), + 5 => (Opcode::FLD, OperandCodeX87::St_Md), // 80bit + 7 => (Opcode::FSTP, OperandCodeX87::Md_St), // 80bit + _ => { + return Err(DecodeError::InvalidOpcode); + } + } + } + + } + OperandCode::x87_dc => { + // mod=11 swaps operand order for some instructions + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FADD, OperandCodeX87::Est_St), + 1 => (Opcode::FMUL, OperandCodeX87::Est_St), + 2 => (Opcode::FCOM, OperandCodeX87::St_Est), + 3 => (Opcode::FCOMP, OperandCodeX87::St_Est), + 4 => (Opcode::FSUBR, OperandCodeX87::Est_St), + 5 => (Opcode::FSUB, OperandCodeX87::Est_St), + 6 => (Opcode::FDIVR, OperandCodeX87::Est_St), + 7 => (Opcode::FDIV, OperandCodeX87::Est_St), + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FADD, OperandCodeX87::St_Est), + 1 => (Opcode::FMUL, OperandCodeX87::St_Est), + 2 => (Opcode::FCOM, OperandCodeX87::St_Est), + 3 => (Opcode::FCOMP, OperandCodeX87::St_Est), + 4 => (Opcode::FSUB, OperandCodeX87::St_Est), + 5 => (Opcode::FSUBR, OperandCodeX87::St_Est), + 6 => (Opcode::FDIV, OperandCodeX87::St_Est), + 7 => (Opcode::FDIVR, OperandCodeX87::St_Est), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_dd => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FFREE, OperandCodeX87::Est), + 1 => (Opcode::FXCH, OperandCodeX87::St_Est), + 2 => (Opcode::FST, OperandCodeX87::Est_St), + 3 => (Opcode::FSTP, OperandCodeX87::Est_St), + 4 => (Opcode::FUCOM, OperandCodeX87::St_Est), + 5 => (Opcode::FUCOMP, OperandCodeX87::St_Est), + 6 => (Opcode::Invalid, OperandCodeX87::Nothing), + 7 => (Opcode::Invalid, OperandCodeX87::Nothing), + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FLD, OperandCodeX87::St_Est), + 1 => (Opcode::FISTTP, OperandCodeX87::Est_St), + 2 => (Opcode::FST, OperandCodeX87::Est_St), + 3 => (Opcode::FSTP, OperandCodeX87::Est_St), + 4 => (Opcode::FRSTOR, OperandCodeX87::Md), // TODO: m94/108byte + 5 => (Opcode::Invalid, OperandCodeX87::Nothing), + 6 => (Opcode::FNSAVE, OperandCodeX87::Est), + 7 => (Opcode::FNSTSW, OperandCodeX87::Ew), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_de => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FADDP, OperandCodeX87::Est_St), + 1 => (Opcode::FMULP, OperandCodeX87::Est_St), + // undocumented in intel manual, argument order inferred from + // by xed and capstone. TODO: check amd manual. + 2 => (Opcode::FCOMP, OperandCodeX87::St_Est), + 3 => { + if modrm == 0xd9 { + (Opcode::FCOMPP, OperandCodeX87::Nothing) + } else { + return Err(DecodeError::InvalidOperand); + } + }, + 4 => (Opcode::FSUBRP, OperandCodeX87::Est_St), + 5 => (Opcode::FSUBP, OperandCodeX87::Est_St), + 6 => (Opcode::FDIVRP, OperandCodeX87::Est_St), + 7 => (Opcode::FDIVP, OperandCodeX87::Est_St), + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FIADD, OperandCodeX87::St_Ew), + 1 => (Opcode::FIMUL, OperandCodeX87::St_Ew), + 2 => (Opcode::FICOM, OperandCodeX87::St_Ew), + 3 => (Opcode::FICOMP, OperandCodeX87::St_Ew), + 4 => (Opcode::FISUB, OperandCodeX87::St_Ew), + 5 => (Opcode::FISUBR, OperandCodeX87::St_Ew), + 6 => (Opcode::FIDIV, OperandCodeX87::St_Ew), + 7 => (Opcode::FIDIVR, OperandCodeX87::St_Ew), + _ => { unreachable!("impossible r"); } + } + } + } + OperandCode::x87_df => { + if modrm >= 0xc0 { + match r { + 0 => (Opcode::FFREEP, OperandCodeX87::Est), + 1 => (Opcode::FXCH, OperandCodeX87::St_Est), + 2 => (Opcode::FSTP, OperandCodeX87::Est_St), + 3 => (Opcode::FSTP, OperandCodeX87::Est_St), + 4 => { + if modrm == 0xe0 { + (Opcode::FNSTSW, OperandCodeX87::Ew) + } else { + return Err(DecodeError::InvalidOpcode); + } + }, + 5 => (Opcode::FUCOMIP, OperandCodeX87::St_Est), + 6 => (Opcode::FCOMIP, OperandCodeX87::St_Est), + 7 => { + return Err(DecodeError::InvalidOpcode); + }, + _ => { unreachable!("impossible r"); } + } + } else { + match r { + 0 => (Opcode::FILD, OperandCodeX87::St_Est), + 1 => (Opcode::FISTTP, OperandCodeX87::Est_St), + 2 => (Opcode::FIST, OperandCodeX87::Est_St), + 3 => (Opcode::FISTP, OperandCodeX87::Est_St), + 4 => (Opcode::FBLD, OperandCodeX87::St_Est), + 5 => (Opcode::FILD, OperandCodeX87::St_Est), + 6 => (Opcode::FBSTP, OperandCodeX87::Est_St), + 7 => (Opcode::FISTP, OperandCodeX87::Est_St), + _ => { unreachable!("impossible r"); } + } + } + } + other => { + panic!("invalid x87 operand dispatch, operand code is {:?}", other); + } + }; + instruction.opcode = opcode; + if instruction.opcode == Opcode::Invalid { + return Err(DecodeError::InvalidOpcode); + } + // TODO: support 80-bit operands + match x87_operands { + OperandCodeX87::Est => { + instruction.operands[0] = read_E_st(&mut bytes_iter, instruction, modrm, length)?; + instruction.operand_count = 1; + } + OperandCodeX87::St_Est => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = RegSpec::st(0); + instruction.operands[1] = read_E_st(&mut bytes_iter, instruction, modrm, length)?; + instruction.operand_count = 2; + } + OperandCodeX87::St_Ew => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = RegSpec::st(0); + instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?; + instruction.operand_count = 2; + } + OperandCodeX87::St_Md => { + instruction.operands[0] = OperandSpec::RegRRR; + instruction.modrm_rrr = RegSpec::st(0); + instruction.operands[1] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?; + if instruction.operands[1] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operand_count = 2; + } + OperandCodeX87::Md => { + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operand_count = 1; + } + OperandCodeX87::Ew => { + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 2, length)?; + instruction.operand_count = 1; + } + OperandCodeX87::Est_St => { + instruction.operands[0] = read_E_st(&mut bytes_iter, instruction, modrm, length)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.modrm_rrr = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Ed_St => { + instruction.operands[0] = read_E_st(&mut bytes_iter, instruction, modrm, length)?; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.modrm_rrr = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Md_St => { + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?; + if instruction.operands[0] == OperandSpec::RegMMM { + return Err(DecodeError::InvalidOperand); + } + instruction.operands[1] = OperandSpec::RegRRR; + instruction.modrm_rrr = RegSpec::st(0); + instruction.operand_count = 2; + } + OperandCodeX87::Ex87S => { + instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 4, length)?; + instruction.operand_count = 1; + } + OperandCodeX87::Nothing => { + instruction.operand_count = 0; + }, + } + + Ok(()) +} + fn decode_one<'b, T: IntoIterator>(decoder: &InstDecoder, bytes: T, instr: &'b mut Instruction) -> Result<(), DecodeError> { instr.operands = [ OperandSpec::Nothing, @@ -7118,15 +8308,23 @@ fn decode_one<'b, T: IntoIterator>(decoder: &InstDecoder, bytes: T, ins #[inline] fn read_num>(bytes: &mut T, width: u8) -> Result { - let mut result = 0u32; - let mut idx = 0; - loop { - if idx == width { - return Ok(result); + match width { + 1 => { bytes.next().map(|x| x as u32).ok_or(DecodeError::ExhaustedInput) } + 2 => { + bytes.next().and_then(|b0| { + bytes.next().map(|b1| u16::from_le_bytes([b0, b1]) as u32) + }).ok_or(DecodeError::ExhaustedInput) + } + 4 => { + bytes.next() + .and_then(|b0| bytes.next().map(|b1| (b0, b1))) + .and_then(|(b0, b1)| bytes.next().map(|b2| (b0, b1, b2))) + .and_then(|(b0, b1, b2)| bytes.next().map(|b3| u32::from_le_bytes([b0, b1, b2, b3]))) + .ok_or(DecodeError::ExhaustedInput) + } + _ => { + panic!("unsupported read size"); } - let byte = bytes.next().ok_or(DecodeError::ExhaustedInput)?; - result |= (byte as u32) << (idx * 8); - idx += 1; } } @@ -7153,16 +8351,6 @@ fn read_imm_unsigned>(bytes: &mut T, width: u8, length: &mu } #[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>(bytes_iter: &mut T, length: &mut u8) -> Result { 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 index b2a845e..497c25d 100644 --- a/src/protected_mode/vex.rs +++ b/src/protected_mode/vex.rs @@ -77,7 +77,7 @@ enum VEXOperandCode { G_V_M_xmm, G_V_M_ymm, V_xmm_G_ymm_E_ymm_imm8, - V_ymm_G_ymm_E_xmm_imm8, + G_ymm_V_ymm_E_xmm_imm8, G_V_xmm_Ew_imm8, Eq_G_xmm, Ed_G_xmm, @@ -134,7 +134,7 @@ pub(crate) fn two_byte_vex>(bytes: &mut T, vex_byte: u8, in }; instruction.vex_reg = RegSpec { bank: RegisterBank::X, - num: ((vex_byte >> 3) & 0b1111) ^ 0b1111, + num: ((vex_byte >> 3) & 0b0111) ^ 0b0111, }; instruction.prefixes.vex_from_c5(vex_byte); @@ -162,24 +162,15 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst 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) // :) + instruction.modrm_rrr = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.vex_reg.bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) } VEXOperandCode::VPS_71_L => { let modrm = read_modrm(bytes, length)?; @@ -197,24 +188,15 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst 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) // :) + instruction.modrm_rrr = + RegSpec::from_parts(modrm & 7, RegisterBank::Y); + instruction.vex_reg.bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) } VEXOperandCode::VPS_72 => { let modrm = read_modrm(bytes, length)?; @@ -232,24 +214,15 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst 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) // :) + instruction.modrm_rrr = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.vex_reg.bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) } VEXOperandCode::VPS_72_L => { let modrm = read_modrm(bytes, length)?; @@ -267,24 +240,15 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst 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) // :) + instruction.modrm_rrr = + RegSpec::from_parts(modrm & 7, RegisterBank::Y); + instruction.vex_reg.bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) } VEXOperandCode::VPS_73 => { let modrm = read_modrm(bytes, length)?; @@ -305,9 +269,15 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst 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) // :) + instruction.modrm_rrr = + RegSpec::from_parts(modrm & 7, RegisterBank::X); + instruction.vex_reg.bank = RegisterBank::X; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) } VEXOperandCode::VPS_73_L => { let modrm = read_modrm(bytes, length)?; @@ -334,9 +304,15 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst 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) // :) + instruction.modrm_rrr = + RegSpec::from_parts(modrm & 7, RegisterBank::Y); + instruction.vex_reg.bank = RegisterBank::Y; + instruction.operands[0] = OperandSpec::RegVex; + instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmI8; + instruction.operand_count = 3; + Ok(()) } VEXOperandCode::VMOVSS_10 | VEXOperandCode::VMOVSD_10 => { @@ -349,9 +325,11 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst OperandSpec::RegMMM => { instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = OperandSpec::RegMMM; + instruction.operand_count = 3; }, other => { instruction.operands[1] = other; + instruction.operand_count = 2; } } Ok(()) @@ -367,9 +345,11 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst OperandSpec::RegMMM => { instruction.operands[0] = OperandSpec::RegVex; instruction.operands[2] = OperandSpec::RegMMM; + instruction.operand_count = 3; }, other => { instruction.operands[0] = other; + instruction.operand_count = 2; } } Ok(()) @@ -389,6 +369,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; instruction.imm = read_imm_unsigned(bytes, 1, length)?; Ok(()) }, @@ -403,6 +384,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E(bytes, instruction, modrm, 4, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } VEXOperandCode::G_xmm_Ed => { @@ -416,6 +398,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E(bytes, instruction, modrm, 4, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } VEXOperandCode::Eq_G_xmm => { @@ -429,6 +412,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E(bytes, instruction, modrm, 4, length)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; Ok(()) } VEXOperandCode::Ed_G_xmm => { @@ -442,6 +426,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E(bytes, instruction, modrm, 4, length)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::E_G_xmm | @@ -459,6 +444,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::E_xmm_G_ymm_imm8 => { @@ -472,6 +458,9 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; Ok(()) } @@ -489,6 +478,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::G_xmm_E_xmm => { @@ -502,6 +492,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::G_xmm_E_ymm => { @@ -515,6 +506,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::G_ymm_E_xmm => { @@ -528,6 +520,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_xmm(bytes, instruction, modrm, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::G_ymm_E_ymm => { @@ -541,6 +534,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } @@ -557,6 +551,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; + instruction.operand_count = 2; Ok(()) } @@ -573,6 +568,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst let mem_oper = read_E_ymm(bytes, instruction, modrm, length)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; + instruction.operand_count = 2; Ok(()) } _op @ VEXOperandCode::G_V_E_ymm | @@ -585,6 +581,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; + instruction.operand_count = 3; Ok(()) } _op @ VEXOperandCode::G_V_E_ymm_imm8 => { @@ -598,6 +595,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[2] = mem_oper; instruction.imm = read_imm_unsigned(bytes, 1, length)?; instruction.operands[3] = OperandSpec::ImmU8; + instruction.operand_count = 4; Ok(()) } _op @ VEXOperandCode::E_V_G_ymm | @@ -610,6 +608,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = OperandSpec::RegRRR; + instruction.operand_count = 3; Ok(()) } _op @ VEXOperandCode::G_V_M_xmm | @@ -621,6 +620,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = mem_oper; + instruction.operand_count = 3; Ok(()) } _op @ VEXOperandCode::G_V_E_xmm_imm8 => { @@ -633,19 +633,21 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[2] = mem_oper; instruction.imm = read_imm_unsigned(bytes, 1, length)?; instruction.operands[3] = OperandSpec::ImmU8; + instruction.operand_count = 4; Ok(()) } - _op @ VEXOperandCode::V_ymm_G_ymm_E_xmm_imm8 => { + _op @ VEXOperandCode::G_ymm_V_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[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; + instruction.operand_count = 4; Ok(()) } _op @ VEXOperandCode::V_xmm_G_ymm_E_ymm_imm8 => { @@ -658,6 +660,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[2] = mem_oper; instruction.imm = read_imm_unsigned(bytes, 1, length)?; instruction.operands[3] = OperandSpec::ImmU8; + instruction.operand_count = 4; Ok(()) } _op @ VEXOperandCode::E_V_G_xmm | @@ -669,6 +672,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = OperandSpec::RegRRR; + instruction.operand_count = 3; Ok(()) } @@ -681,6 +685,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; instruction.operands[2] = OperandSpec::RegVex; + instruction.operand_count = 3; Ok(()) } VEXOperandCode::G_Ey_V_ymm => { @@ -693,6 +698,7 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; instruction.operands[2] = OperandSpec::RegVex; + instruction.operand_count = 3; Ok(()) } VEXOperandCode::G_V_E => { @@ -761,13 +767,73 @@ fn read_vex_operands>(bytes: &mut T, instruction: &mut Inst instruction.vex_reg.bank = bank; 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_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::RegRRR; + instruction.operands[1] = mem_oper; + instruction.imm = read_imm_unsigned(bytes, 1, length)?; + instruction.operands[2] = OperandSpec::ImmU8; + instruction.operand_count = 3; + Ok(()) + } + VEXOperandCode::G_V_E_ymm_ymm4 => { + 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)? >> 4; + instruction.operands[3] = OperandSpec::Reg4; + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::G_V_E_xmm_xmm4 => { + let modrm = read_modrm(bytes, length)?; + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.vex_reg.bank = 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)? >> 4; + instruction.operands[3] = OperandSpec::Reg4; + instruction.operand_count = 4; + Ok(()) + } + VEXOperandCode::G_V_ymm_E_xmm => { + 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::RegRRR; + instruction.operands[1] = OperandSpec::RegVex; + instruction.operands[2] = mem_oper; + instruction.operand_count = 3; + Ok(()) + } VEXOperandCode::G_V_xmm_Ew_imm8 => { - Err(DecodeError::IncompleteDecoder) // :) + let modrm = read_modrm(bytes, length)?; + instruction.modrm_rrr = + RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); + instruction.vex_reg.bank = RegisterBank::X; + // TODO: but the memory access is word-sized + let mem_oper = read_E(bytes, instruction, modrm, 4, 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::ImmI8; + instruction.operand_count = 4; + Ok(()) + } } @@ -1275,14 +1341,18 @@ fn read_vex_instruction>(opcode_map: VEXOpcodeMap, bytes: & 0xDC => (Opcode::VPADDUSB, if L { VEXOperandCode::G_V_E_ymm } else { - instruction.opcode = Opcode::Invalid; - return Err(DecodeError::InvalidOpcode); + VEXOperandCode::G_V_E_xmm }), 0xDD => (Opcode::VPADDUSW, if L { VEXOperandCode::G_V_E_ymm } else { VEXOperandCode::G_V_E_xmm }), + 0xDE => (Opcode::VPMAXUB, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), 0xDF => (Opcode::VPANDN, if L { VEXOperandCode::G_V_E_ymm } else { @@ -1338,6 +1408,11 @@ fn read_vex_instruction>(opcode_map: VEXOpcodeMap, bytes: & } else { VEXOperandCode::G_V_E_xmm }), + 0xEA => (Opcode::VPMINSW, if L { + VEXOperandCode::G_V_E_ymm + } else { + VEXOperandCode::G_V_E_xmm + }), 0xEB => (Opcode::VPOR, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2571,10 +2646,10 @@ fn read_vex_instruction>(opcode_map: VEXOpcodeMap, bytes: & }) }, 0x38 => (Opcode::VINSERTI128, if L { + VEXOperandCode::G_ymm_V_ymm_E_xmm_imm8 + } else { 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 @@ -2594,9 +2669,9 @@ fn read_vex_instruction>(opcode_map: VEXOpcodeMap, bytes: & VEXOperandCode::G_V_E_xmm_imm8 }), 0x42 => (Opcode::VMPSADBW, if L { - VEXOperandCode::G_E_ymm_imm8 + VEXOperandCode::G_V_E_ymm_imm8 } else { - VEXOperandCode::G_E_xmm_imm8 + VEXOperandCode::G_V_E_xmm_imm8 }), 0x44 => (Opcode::VPCLMULQDQ, if L { instruction.opcode = Opcode::Invalid; diff --git a/test/protected_mode/mod.rs b/test/protected_mode/mod.rs index e37c1e6..243b283 100644 --- a/test/protected_mode/mod.rs +++ b/test/protected_mode/mod.rs @@ -51,7 +51,6 @@ fn test_display_under(decoder: &InstDecoder, data: &[u8], expected: &'static str #[test] fn test_mmx() { - test_display(&[0x4f, 0x0f, 0xf7, 0xc1], "maskmovq mm0, mm1"); test_display(&[0x0f, 0xf7, 0xc1], "maskmovq mm0, mm1"); test_invalid(&[0x0f, 0xf7, 0x01]); @@ -75,7 +74,7 @@ fn test_mmx() { test_display(&[0x0f, 0xf9, 0xc2], "psubw mm0, mm2"); test_display(&[0x0f, 0xfd, 0xd2], "paddw mm2, mm2"); test_display(&[0x0f, 0x6f, 0xe9], "movq mm5, mm1"); - test_display(&[0x0f, 0xe5, 0x3d, 0xaa, 0xbb, 0xcc, 0x77], "pmulhw mm7, [eip + 0x77ccbbaa]"); + test_display(&[0x0f, 0xe5, 0x3d, 0xaa, 0xbb, 0xcc, 0x77], "pmulhw mm7, [0x77ccbbaa]"); test_display(&[0x0f, 0x38, 0x00, 0xda], "pshufb mm3, mm2"); @@ -521,24 +520,23 @@ fn test_sse4_2() { test_invalid_under(&InstDecoder::default(), bytes); } - test_instr(&[0x66, 0x0f, 0x38, 0x37, 0x03], "pcmpgtq xmm0, [rbx]"); + test_instr(&[0x66, 0x0f, 0x38, 0x37, 0x03], "pcmpgtq xmm0, [ebx]"); test_instr(&[0x66, 0x0f, 0x38, 0x37, 0xc3], "pcmpgtq xmm0, xmm3"); - test_instr(&[0xf2, 0x0f, 0x38, 0xf0, 0x06], "crc32 eax, [rsi]"); + test_instr(&[0xf2, 0x0f, 0x38, 0xf0, 0x06], "crc32 eax, [esi]"); test_instr(&[0xf2, 0x0f, 0x38, 0xf0, 0xc6], "crc32 eax, dh"); - test_instr(&[0xf2, 0x0f, 0x38, 0xf1, 0x06], "crc32 eax, [rsi]"); + test_instr(&[0xf2, 0x0f, 0x38, 0xf1, 0x06], "crc32 eax, [esi]"); test_instr(&[0xf2, 0x0f, 0x38, 0xf1, 0xc6], "crc32 eax, esi"); test_instr(&[0x66, 0xf2, 0x0f, 0x38, 0xf1, 0xc6], "crc32 eax, si"); - test_instr(&[0x66, 0xf2, 0x48, 0x0f, 0x38, 0xf1, 0xc6], "crc32 rax, rsi"); test_instr(&[0x66, 0x0f, 0x3a, 0x60, 0xc6, 0x54], "pcmpestrm xmm0, xmm6, 0x54"); - test_instr(&[0x66, 0x0f, 0x3a, 0x60, 0x06, 0x54], "pcmpestrm xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x60, 0x06, 0x54], "pcmpestrm xmm0, [esi], 0x54"); test_instr(&[0x66, 0x0f, 0x3a, 0x61, 0xc6, 0x54], "pcmpestri xmm0, xmm6, 0x54"); - test_instr(&[0x66, 0x0f, 0x3a, 0x61, 0x06, 0x54], "pcmpestri xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x61, 0x06, 0x54], "pcmpestri xmm0, [esi], 0x54"); test_instr(&[0x66, 0x0f, 0x3a, 0x62, 0xc6, 0x54], "pcmpistrm xmm0, xmm6, 0x54"); - test_instr(&[0x66, 0x0f, 0x3a, 0x62, 0x06, 0x54], "pcmpistrm xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x62, 0x06, 0x54], "pcmpistrm xmm0, [esi], 0x54"); test_instr(&[0x66, 0x0f, 0x3a, 0x63, 0xc6, 0x54], "pcmpistri xmm0, xmm6, 0x54"); - test_instr(&[0x66, 0x0f, 0x3a, 0x63, 0x06, 0x54], "pcmpistri xmm0, [rsi], 0x54"); + test_instr(&[0x66, 0x0f, 0x3a, 0x63, 0x06, 0x54], "pcmpistri xmm0, [esi], 0x54"); } #[test] @@ -558,115 +556,113 @@ fn test_sse4_1() { test_invalid_under(&InstDecoder::default(), bytes); } - test_instr(&[0x66, 0x0f, 0x38, 0x0c, 0x06], "blendps xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x0c, 0x06], "blendps xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x0c, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x0d, 0x06], "blendpd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x0d, 0x06], "blendpd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x0d, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x10, 0x06], "pblendvb xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x10, 0x06], "pblendvb xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x10, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x14, 0x06], "blendvps xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x14, 0x06], "blendvps xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x14, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x15, 0x06], "blendvpd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x15, 0x06], "blendvpd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x15, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x17, 0x06], "ptest xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x17, 0x06], "ptest xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x17, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x20, 0x06], "pmovsxbw xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x20, 0x06], "pmovsxbw xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x20, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x21, 0x06], "pmovsxbd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x21, 0x06], "pmovsxbd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x21, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x22, 0x06], "pmovsxbq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x22, 0x06], "pmovsxbq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x22, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x23, 0x06], "pmovsxwd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x23, 0x06], "pmovsxwd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x23, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x24, 0x06], "pmovsxwq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x24, 0x06], "pmovsxwq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x24, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x25, 0x06], "pmovsxdq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x25, 0x06], "pmovsxdq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x25, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x28, 0x06], "pmuldq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x28, 0x06], "pmuldq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x28, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x29, 0x06], "pcmpeqq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x29, 0x06], "pcmpeqq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x29, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x2a, 0x06], "movntdqa xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x2a, 0x06], "movntdqa xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x2a, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x2b, 0x06], "packusdw xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x2b, 0x06], "packusdw xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x2b, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x30, 0x06], "pmovzxbw xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x30, 0x06], "pmovzxbw xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x30, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x31, 0x06], "pmovzxbd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x31, 0x06], "pmovzxbd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x31, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x32, 0x06], "pmovzxbq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x32, 0x06], "pmovzxbq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x32, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x33, 0x06], "pmovzxwd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x33, 0x06], "pmovzxwd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x33, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x34, 0x06], "pmovzxwq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x34, 0x06], "pmovzxwq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x34, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x35, 0x06], "pmovzxdq xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x35, 0x06], "pmovzxdq xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x35, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x38, 0x06], "pminsb xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x38, 0x06], "pminsb xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x38, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x39, 0x06], "pminsd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x39, 0x06], "pminsd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x39, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x3a, 0x06], "pminuw xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x3a, 0x06], "pminuw xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x3a, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x3b, 0x06], "pminud xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x3b, 0x06], "pminud xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x3b, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x3c, 0x06], "pmaxsb xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x3c, 0x06], "pmaxsb xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x3c, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x3d, 0x06], "pmaxsd xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x3d, 0x06], "pmaxsd xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x3d, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x3e, 0x06], "pmaxuw xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x3e, 0x06], "pmaxuw xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x3e, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x3f, 0x06], "pmaxud xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x3f, 0x06], "pmaxud xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x3f, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x40, 0x06], "pmulld xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x40, 0x06], "pmulld xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x40, 0x06]); - test_instr(&[0x66, 0x0f, 0x38, 0x41, 0x06], "phminposuw xmm0, [rsi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x41, 0x06], "phminposuw xmm0, [esi]"); test_invalid(&[0x0f, 0x38, 0x41, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x08, 0x06, 0x31], "roundps xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x08, 0x06, 0x31], "roundps xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x08, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x09, 0x06, 0x31], "roundpd xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x09, 0x06, 0x31], "roundpd xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x09, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x0a, 0x06, 0x31], "roundss xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x0a, 0x06, 0x31], "roundss xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x0a, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x0b, 0x06, 0x31], "roundsd xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x0b, 0x06, 0x31], "roundsd xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x0b, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x0e, 0x06, 0x31], "pblendw xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x0e, 0x06, 0x31], "pblendw xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x0e, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x14, 0x06, 0x31], "pextrb xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x14, 0x06, 0x31], "pextrb xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x14, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x15, 0x06, 0x31], "pextrw xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x15, 0x06, 0x31], "pextrw xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x15, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x16, 0x06, 0x31], "pextrd xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x16, 0x06, 0x31], "pextrd xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x16, 0x06]); - test_instr(&[0x66, 0x48, 0x0f, 0x3a, 0x16, 0x06, 0x31], "pextrq xmm0, [rsi], 0x31"); - test_instr(&[0x66, 0x0f, 0x3a, 0x17, 0x06, 0x31], "extractps xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x17, 0x06, 0x31], "extractps xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x17, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x20, 0x06, 0x31], "pinsrb xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x20, 0x06, 0x31], "pinsrb xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x20, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x21, 0x06, 0x31], "insertps xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x21, 0x06, 0x31], "insertps xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x21, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x22, 0x06, 0x31], "pinsrd xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x22, 0x06, 0x31], "pinsrd xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x22, 0x06]); - test_instr(&[0x66, 0x48, 0x0f, 0x3a, 0x22, 0x06, 0x31], "pinsrq xmm0, [rsi], 0x31"); - test_instr(&[0x66, 0x0f, 0x3a, 0x40, 0x06, 0x31], "dpps xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x40, 0x06, 0x31], "dpps xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x40, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x41, 0x06, 0x31], "dppd xmm0, [rsi], 0x31"); + test_instr(&[0x66, 0x0f, 0x3a, 0x41, 0x06, 0x31], "dppd xmm0, [esi], 0x31"); test_invalid(&[0x0f, 0x3a, 0x41, 0x06]); - test_instr(&[0x66, 0x0f, 0x3a, 0x42, 0x06, 0x44], "mpsadbw xmm0, [rsi], 0x44"); + test_instr(&[0x66, 0x0f, 0x3a, 0x42, 0x06, 0x44], "mpsadbw xmm0, [esi], 0x44"); test_invalid(&[0x0f, 0x3a, 0x42, 0x06]); } @@ -688,40 +684,40 @@ fn test_ssse3() { test_invalid_under(&InstDecoder::default(), bytes); } test_instr(&[0x66, 0x0f, 0x38, 0x00, 0xda], "pshufb xmm3, xmm2"); - test_instr(&[0x66, 0x0f, 0x38, 0x00, 0x06], "pshufb xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x00, 0x06], "pshufb mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x01, 0x06], "phaddw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x01, 0x06], "phaddw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x02, 0x06], "phaddd xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x02, 0x06], "phaddd mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x03, 0x06], "phaddsw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x03, 0x06], "phaddsw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x04, 0x06], "pmaddubsw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x04, 0x06], "pmaddubsw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x05, 0x06], "phsubw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x05, 0x06], "phsubw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x06, 0x06], "phsubd xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x06, 0x06], "phsubd mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x07, 0x06], "phsubsw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x07, 0x06], "phsubsw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x08, 0x06], "psignb xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x08, 0x06], "psignb mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x09, 0x06], "psignw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x09, 0x06], "psignw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x0a, 0x06], "psignd xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x0a, 0x06], "psignd mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x0b, 0x06], "pmulhrsw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x0b, 0x06], "pmulhrsw mm0, [rsi]"); - - test_instr(&[0x66, 0x0f, 0x38, 0x1c, 0x06], "pabsb xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x1c, 0x06], "pabsb mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x1d, 0x06], "pabsw xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x1d, 0x06], "pabsw mm0, [rsi]"); - test_instr(&[0x66, 0x0f, 0x38, 0x1e, 0x06], "pabsd xmm0, [rsi]"); - test_instr(&[0x0f, 0x38, 0x1e, 0x06], "pabsd mm0, [rsi]"); - - test_instr(&[0x66, 0x0f, 0x3a, 0x0f, 0x06, 0x30], "palignr xmm0, [rsi], 0x30"); - test_instr(&[0x0f, 0x3a, 0x0f, 0x06, 0x30], "palignr mm0, [rsi], 0x30"); + test_instr(&[0x66, 0x0f, 0x38, 0x00, 0x06], "pshufb xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x00, 0x06], "pshufb mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x01, 0x06], "phaddw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x01, 0x06], "phaddw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x02, 0x06], "phaddd xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x02, 0x06], "phaddd mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x03, 0x06], "phaddsw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x03, 0x06], "phaddsw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x04, 0x06], "pmaddubsw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x04, 0x06], "pmaddubsw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x05, 0x06], "phsubw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x05, 0x06], "phsubw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x06, 0x06], "phsubd xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x06, 0x06], "phsubd mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x07, 0x06], "phsubsw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x07, 0x06], "phsubsw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x08, 0x06], "psignb xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x08, 0x06], "psignb mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x09, 0x06], "psignw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x09, 0x06], "psignw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x0a, 0x06], "psignd xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x0a, 0x06], "psignd mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x0b, 0x06], "pmulhrsw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x0b, 0x06], "pmulhrsw mm0, [esi]"); + + test_instr(&[0x66, 0x0f, 0x38, 0x1c, 0x06], "pabsb xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x1c, 0x06], "pabsb mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x1d, 0x06], "pabsw xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x1d, 0x06], "pabsw mm0, [esi]"); + test_instr(&[0x66, 0x0f, 0x38, 0x1e, 0x06], "pabsd xmm0, [esi]"); + test_instr(&[0x0f, 0x38, 0x1e, 0x06], "pabsd mm0, [esi]"); + + test_instr(&[0x66, 0x0f, 0x3a, 0x0f, 0x06, 0x30], "palignr xmm0, [esi], 0x30"); + test_instr(&[0x0f, 0x3a, 0x0f, 0x06, 0x30], "palignr mm0, [esi], 0x30"); } #[test] @@ -922,7 +918,7 @@ fn test_sse() { #[test] fn test_mov() { test_display(&[0xa0, 0x93, 0x62, 0xc4, 0x00], "mov al, [0xc46293]"); - test_display(&[0x67, 0xa0, 0x93, 0x62], "mov al, [0xc293]"); + test_display(&[0x67, 0xa0, 0x93, 0x62], "mov al, [0x6293]"); test_display(&[0xa1, 0x93, 0x62, 0xc4, 0x00], "mov eax, [0xc46293]"); test_display(&[0x67, 0xa1, 0x93, 0x62], "mov eax, [0x6293]"); test_display(&[0xa2, 0x93, 0x62, 0xc4, 0x00], "mov [0xc46293], al"); @@ -1011,8 +1007,8 @@ fn test_push_pop() { test_display(&[0x5b], "pop ebx"); test_display(&[0x5e], "pop esi"); test_display(&[0x68, 0x7f, 0x63, 0xc4, 0x00], "push 0xc4637f"); - test_display(&[0x66, 0x8f, 0x00], "pop [rax]"); - test_display(&[0x8f, 0x00], "pop [rax]"); + test_display(&[0x66, 0x8f, 0x00], "pop [eax]"); + test_display(&[0x8f, 0x00], "pop [eax]"); } #[test] @@ -1106,7 +1102,6 @@ fn test_misc() { test_display(&[0xcb], "retf"); test_display(&[0x66, 0xcf], "iret"); test_display(&[0xcf], "iretd"); - test_display(&[0x66, 0x4f, 0xcf], "iretq"); 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] @@ -1290,10 +1285,10 @@ fn test_vex() { test_instr(&[0xc4, 0xc3, 0x75, 0x46, 0x7c, 0x12, 0x05, 0x61], "vperm2i128 ymm7, ymm1, [edx + edx * 1 + 0x5], 0x61"); test_instr(&[0xc4, 0xc3, 0x75, 0x4a, 0x7c, 0x12, 0x05, 0x61], "vblendvps ymm7, ymm1, [edx + edx * 1 + 0x5], ymm6"); test_instr(&[0xc4, 0xc3, 0x71, 0x4a, 0x7c, 0x12, 0x05, 0x61], "vblendvps xmm7, xmm1, [edx + edx * 1 + 0x5], xmm6"); - test_instr(&[0xc4, 0xc3, 0x71, 0x4a, 0xdc, 0x61], "vblendvps xmm3, xmm1, xmm12, xmm6"); + test_instr(&[0xc4, 0xc3, 0x71, 0x4a, 0xdc, 0x61], "vblendvps xmm3, xmm1, xmm4, xmm6"); test_instr(&[0xc4, 0xc3, 0x75, 0x4b, 0x7c, 0x12, 0x05, 0x61], "vblendvpd ymm7, ymm1, [edx + edx * 1 + 0x5], ymm6"); - test_instr(&[0xc4, 0xc3, 0x71, 0x4b, 0x7c, 0x12, 0x05, 0x61], "vblendvpd xmm7, xmm1, [edx + rdx * 1 + 0x5], xmm6"); - test_instr(&[0xc4, 0xc3, 0x71, 0x4b, 0xdc, 0x61], "vblendvpd xmm3, xmm1, xmm12, xmm6"); + test_instr(&[0xc4, 0xc3, 0x71, 0x4b, 0x7c, 0x12, 0x05, 0x61], "vblendvpd xmm7, xmm1, [edx + edx * 1 + 0x5], xmm6"); + test_instr(&[0xc4, 0xc3, 0x71, 0x4b, 0xdc, 0x61], "vblendvpd xmm3, xmm1, xmm4, xmm6"); test_instr(&[0xc4, 0xc3, 0x71, 0x4c, 0x7c, 0x12, 0x05, 0x61], "vpblendvb xmm7, xmm1, [edx + edx * 1 + 0x5], xmm6"); test_instr(&[0xc5, 0xc9, 0xf1, 0x0f], "vpsllw xmm1, xmm6, [edi]"); @@ -1458,6 +1453,10 @@ fn only_32bit() { 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]"); + + test_display(&[0x60], "pusha"); + test_display(&[0x61], "popa"); + test_display(&[0xce], "into"); } #[test] -- cgit v1.1