mod vex; mod evex; #[cfg(feature = "fmt")] mod display; pub mod uarch; pub use crate::MemoryAccessSize; #[cfg(feature = "fmt")] pub use self::display::DisplayStyle; use core::cmp::PartialEq; use core::hint::unreachable_unchecked; use yaxpeax_arch::{AddressDiff, Decoder, Reader, LengthedInstruction}; use yaxpeax_arch::{DecodeError as ArchDecodeError}; use core::fmt; impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.description()) } } /// an `x86` register, including its number and type. if `fmt` is enabled, name too. /// /// ``` /// use yaxpeax_x86::long_mode::{RegSpec, register_class}; /// /// assert_eq!(RegSpec::ecx().num(), 1); /// assert_eq!(RegSpec::ecx().class(), register_class::D); /// ``` /// /// some registers have classes of their own, and only one member: `eip` and `eflags`. #[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)] pub struct RegSpec { num: u8, bank: RegisterBank } use core::hash::Hash; use core::hash::Hasher; impl Hash for RegSpec { fn hash(&self, state: &mut H) { let code = ((self.bank as u16) << 8) | (self.num as u16); code.hash(state); } } /// the condition for a conditional instruction. /// /// these are only obtained through [`Opcode::condition()`]: /// ``` /// use yaxpeax_x86::long_mode::{Opcode, ConditionCode}; /// /// assert_eq!(Opcode::JB.condition(), Some(ConditionCode::B)); /// ``` #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ConditionCode { O, NO, B, AE, Z, NZ, A, BE, S, NS, P, NP, L, GE, G, LE, } #[allow(non_snake_case)] impl RegSpec { /// the register `eip`. this register is in the class `eip`, which contains only it. pub const EIP: RegSpec = RegSpec::eip(); /// the number of this register in its `RegisterClass`. /// /// for many registers this is a number in the name, but for registers harkening back to /// `x86_32`, the first eight registers are `rax`, `rcx`, `rdx`, `rbx`, `rsp`, `rbp`, `rsi`, /// and `rdi` (or `eXX` for the 32-bit forms, `XX` for 16-bit forms). pub fn num(&self) -> u8 { self.num } /// the class of register this register is in. /// /// this corresponds to the register's size, but is by the register's usage in the instruction /// set; `rax` and `mm0` are the same size, but different classes (`Q`(word) and `MM` (mmx) /// respectively). pub fn class(&self) -> RegisterClass { RegisterClass { kind: self.bank } } #[cfg(feature = "fmt")] /// return a human-friendly name for this register. the returned name is the same as would be /// used to render this register in an instruction. pub fn name(&self) -> &'static str { display::regspec_label(self) } /// construct a `RegSpec` for x87 register `st(num)` #[inline] pub fn st(num: u8) -> RegSpec { if num >= 8 { panic!("invalid x87 reg st({})", num); } RegSpec { num, bank: RegisterBank::ST } } /// construct a `RegSpec` for xmm reg `num` #[inline] pub fn xmm(num: u8) -> RegSpec { if num >= 32 { panic!("invalid x86 xmm reg {}", num); } RegSpec { num, bank: RegisterBank::X } } /// construct a `RegSpec` for ymm reg `num` #[inline] pub fn ymm(num: u8) -> RegSpec { if num >= 32 { panic!("invalid x86 ymm reg {}", num); } RegSpec { num, bank: RegisterBank::Y } } /// construct a `RegSpec` for zmm reg `num` #[inline] pub fn zmm(num: u8) -> RegSpec { if num >= 32 { panic!("invalid x86 zmm reg {}", num); } RegSpec { num, bank: RegisterBank::Z } } /// construct a `RegSpec` for mask reg `num` #[inline] pub fn mask(num: u8) -> RegSpec { if num >= 32 { panic!("invalid x86 mask reg {}", num); } RegSpec { num, bank: RegisterBank::K } } /// construct a `RegSpec` for dword reg `num` #[inline] pub fn d(num: u8) -> RegSpec { if num >= 8 { panic!("invalid x86 dword reg {}", num); } RegSpec { num, bank: RegisterBank::D } } /// construct a `RegSpec` for word reg `num` #[inline] pub fn w(num: u8) -> RegSpec { if num >= 8 { panic!("invalid x86 word reg {}", num); } RegSpec { num, bank: RegisterBank::W } } /// construct a `RegSpec` for byte reg `num` #[inline] pub fn b(num: u8) -> RegSpec { if num >= 8 { panic!("invalid x86 byte reg {}", num); } RegSpec { num, bank: RegisterBank::B } } #[inline] fn from_parts(num: u8, bank: RegisterBank) -> RegSpec { RegSpec { num: num, bank: bank } } #[inline] pub const fn eip() -> RegSpec { RegSpec { num: 0, bank: RegisterBank::EIP } } #[inline] pub const fn eflags() -> RegSpec { RegSpec { num: 0, bank: RegisterBank::EFlags } } #[inline] pub const fn esp() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 4 } } #[inline] pub const fn ebp() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 5 } } #[inline] pub const fn cs() -> RegSpec { RegSpec { bank: RegisterBank::S, num: 1 } } #[inline] pub const fn ds() -> RegSpec { RegSpec { bank: RegisterBank::S, num: 3 } } #[inline] pub const fn es() -> RegSpec { RegSpec { bank: RegisterBank::S, num: 0 } } #[inline] pub const fn ss() -> RegSpec { RegSpec { bank: RegisterBank::S, num: 2 } } #[inline] pub const fn fs() -> RegSpec { RegSpec { bank: RegisterBank::S, num: 4 } } #[inline] pub const fn gs() -> RegSpec { RegSpec { bank: RegisterBank::S, num: 5 } } #[inline] pub const fn eax() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 0 } } #[inline] pub const fn ecx() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 1 } } #[inline] pub const fn edx() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 2 } } #[inline] pub const fn ebx() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 3 } } #[inline] pub const fn esi() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 6 } } #[inline] pub const fn edi() -> RegSpec { RegSpec { bank: RegisterBank::D, num: 7 } } #[inline] pub const fn ax() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 0 } } #[inline] pub const fn cx() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 1 } } #[inline] pub const fn dx() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 2 } } #[inline] pub const fn bx() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 3 } } #[inline] pub const fn sp() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 4 } } #[inline] pub const fn bp() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 5 } } #[inline] pub const fn si() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 6 } } #[inline] pub const fn di() -> RegSpec { RegSpec { bank: RegisterBank::W, num: 7 } } #[inline] pub const fn al() -> RegSpec { RegSpec { bank: RegisterBank::B, num: 0 } } #[inline] pub const fn cl() -> RegSpec { RegSpec { bank: RegisterBank::B, num: 1 } } #[inline] pub const fn dl() -> RegSpec { RegSpec { bank: RegisterBank::B, num: 2 } } #[inline] pub const fn ah() -> RegSpec { RegSpec { bank: RegisterBank::B, num: 4 } } #[inline] pub const fn ch() -> RegSpec { RegSpec { bank: RegisterBank::B, num: 5 } } #[inline] pub const fn zmm0() -> RegSpec { RegSpec { bank: RegisterBank::Z, num: 0 } } #[inline] pub const fn ymm0() -> RegSpec { RegSpec { bank: RegisterBank::Y, num: 0 } } #[inline] pub const fn xmm0() -> RegSpec { RegSpec { bank: RegisterBank::X, num: 0 } } #[inline] pub const fn st0() -> RegSpec { RegSpec { bank: RegisterBank::ST, num: 0 } } #[inline] pub const fn mm0() -> RegSpec { RegSpec { bank: RegisterBank::MM, num: 0 } } /// return the size of this register, in bytes #[inline] pub fn width(&self) -> u8 { self.class().width() } } #[allow(non_camel_case_types)] #[allow(dead_code)] enum SizeCode { b, vd, } /// an operand for an `x86` instruction. /// /// `Operand::Nothing` should be unreachable in practice; any such instructions should have an /// operand count of 0 (or at least one fewer than the `Nothing` operand's position). #[derive(Clone, Debug, PartialEq)] #[non_exhaustive] pub enum Operand { /// a sign-extended byte ImmediateI8(i8), /// a zero-extended byte ImmediateU8(u8), /// a sign-extended word ImmediateI16(i16), /// a zero-extended word ImmediateU16(u16), /// a sign-extended dword ImmediateI32(i32), /// a zero-extended dword ImmediateU32(u32), /// a bare register operand, such as `rcx`. Register(RegSpec), /// an `avx512` register operand with optional mask register and merge mode, such as /// `zmm3{k4}{z}`. /// /// if the mask register is `k0`, there is no masking applied, and the default x86 operation is /// `MergeMode::Merge`. RegisterMaskMerge(RegSpec, RegSpec, MergeMode), /// an `avx512` register operand with optional mask register, merge mode, and suppressed /// exceptions, such as `zmm3{k4}{z}{rd-sae}`. /// /// if the mask register is `k0`, there is no masking applied, and the default x86 operation is /// `MergeMode::Merge`. RegisterMaskMergeSae(RegSpec, RegSpec, MergeMode, SaeMode), /// an `avx512` register operand with optional mask register, merge mode, and suppressed /// exceptions, with no overridden rounding mode, such as `zmm3{k4}{z}{sae}`. /// /// if the mask register is `k0`, there is no masking applied, and the default x86 operation is /// `MergeMode::Merge`. RegisterMaskMergeSaeNoround(RegSpec, RegSpec, MergeMode), /// a memory access to a literal word address. it's extremely rare that a well-formed x86 /// instruction uses this mode. as an example, `[0x1133]` DisplacementU16(u16), /// a memory access to a literal qword address. it's relatively rare that a well-formed x86 /// instruction uses this mode, but plausibe. for example, `fs:[0x14]`. segment overrides, /// however, are maintained on the instruction itself. DisplacementU32(u32), /// a simple dereference of the address held in some register. for example: `[esi]`. RegDeref(RegSpec), /// a dereference of the address held in some register with offset. for example: `[esi + 0x14]`. RegDisp(RegSpec, i32), /// a dereference of the address held in some register scaled by 1, 2, 4, or 8. this is almost always used with the `lea` instruction. for example: `[edx * 4]`. RegScale(RegSpec, u8), /// a dereference of the address from summing two registers. for example: `[ebp + rax]` RegIndexBase(RegSpec, RegSpec), /// a dereference of the address from summing two registers with offset. for example: `[edi + ecx + 0x40]` RegIndexBaseDisp(RegSpec, RegSpec, i32), /// a dereference of the address held in some register scaled by 1, 2, 4, or 8 with offset. this is almost always used with the `lea` instruction. for example: `[eax * 4 + 0x30]`. RegScaleDisp(RegSpec, u8, i32), /// a dereference of the address from summing a register and index register scaled by 1, 2, 4, /// or 8. for /// example: `[esi + ecx * 4]` RegIndexBaseScale(RegSpec, RegSpec, u8), /// a dereference of the address from summing a register and index register scaled by 1, 2, 4, /// or 8, with offset. for /// example: `[esi + ecx * 4 + 0x1234]` RegIndexBaseScaleDisp(RegSpec, RegSpec, u8, i32), /// an `avx512` dereference of register with optional masking. for example: `[edx]{k3}` RegDerefMasked(RegSpec, RegSpec), /// an `avx512` dereference of register plus offset, with optional masking. for example: `[esp + 0x40]{k3}` RegDispMasked(RegSpec, i32, RegSpec), /// an `avx512` dereference of a register scaled by 1, 2, 4, or 8, with optional masking. this /// seems extraordinarily unlikely to occur in practice. for example: `[esi * 4]{k2}` RegScaleMasked(RegSpec, u8, RegSpec), /// an `avx512` dereference of a register plus index scaled by 1, 2, 4, or 8, with optional masking. /// for example: `[esi + eax * 4]{k6}` RegIndexBaseMasked(RegSpec, RegSpec, RegSpec), /// an `avx512` dereference of a register plus offset, with optional masking. for example: /// `[esi + eax + 0x1313]{k6}` RegIndexBaseDispMasked(RegSpec, RegSpec, i32, RegSpec), /// an `avx512` dereference of a register scaled by 1, 2, 4, or 8 plus offset, with optional /// masking. this seems extraordinarily unlikely to occur in practice. for example: `[esi * /// 4 + 0x1357]{k2}` RegScaleDispMasked(RegSpec, u8, i32, RegSpec), /// an `avx512` dereference of a register plus index scaled by 1, 2, 4, or 8, with optional /// masking. for example: `[esi + eax * 4]{k6}` RegIndexBaseScaleMasked(RegSpec, RegSpec, u8, RegSpec), /// an `avx512` dereference of a register plus index scaled by 1, 2, 4, or 8 and offset, with /// optional masking. for example: `[esi + eax * 4 + 0x1313]{k6}` RegIndexBaseScaleDispMasked(RegSpec, RegSpec, u8, i32, RegSpec), /// no operand. it is a bug for `yaxpeax-x86` to construct an `Operand` of this kind for public /// use; the instruction's `operand_count` should be reduced so as to make this invisible to /// library clients. Nothing, } impl OperandSpec { fn masked(self) -> Self { match self { OperandSpec::RegRRR => OperandSpec::RegRRR_maskmerge, OperandSpec::RegMMM => OperandSpec::RegMMM_maskmerge, OperandSpec::RegVex => OperandSpec::RegVex_maskmerge, OperandSpec::Deref => OperandSpec::Deref_mask, OperandSpec::RegDisp => OperandSpec::RegDisp_mask, OperandSpec::RegScale => OperandSpec::RegScale_mask, OperandSpec::RegScaleDisp => OperandSpec::RegScaleDisp_mask, OperandSpec::RegIndexBase => OperandSpec::RegIndexBase_mask, OperandSpec::RegIndexBaseDisp => OperandSpec::RegIndexBaseDisp_mask, OperandSpec::RegIndexBaseScale => OperandSpec::RegIndexBaseScale_mask, OperandSpec::RegIndexBaseScaleDisp => OperandSpec::RegIndexBaseScaleDisp_mask, o => o, } } fn is_memory(&self) -> bool { match self { OperandSpec::DispU16 | OperandSpec::DispU32 | OperandSpec::Deref | OperandSpec::Deref_si | OperandSpec::Deref_di | OperandSpec::Deref_esi | OperandSpec::Deref_edi | OperandSpec::RegDisp | OperandSpec::RegScale | OperandSpec::RegIndexBase | OperandSpec::RegIndexBaseDisp | OperandSpec::RegScaleDisp | OperandSpec::RegIndexBaseScale | OperandSpec::RegIndexBaseScaleDisp | OperandSpec::Deref_mask | OperandSpec::RegDisp_mask | OperandSpec::RegScale_mask | OperandSpec::RegScaleDisp_mask | OperandSpec::RegIndexBase_mask | OperandSpec::RegIndexBaseDisp_mask | OperandSpec::RegIndexBaseScale_mask | OperandSpec::RegIndexBaseScaleDisp_mask => { true }, OperandSpec::ImmI8 | OperandSpec::ImmI16 | OperandSpec::ImmI32 | OperandSpec::ImmU8 | OperandSpec::ImmU16 | OperandSpec::RegRRR | OperandSpec::RegRRR_maskmerge | OperandSpec::RegRRR_maskmerge_sae | OperandSpec::RegRRR_maskmerge_sae_noround | OperandSpec::RegMMM | OperandSpec::RegMMM_maskmerge | OperandSpec::RegMMM_maskmerge_sae_noround | OperandSpec::RegVex | OperandSpec::RegVex_maskmerge | OperandSpec::Reg4 | OperandSpec::ImmInDispField | OperandSpec::Nothing => { false } } } } /// an `avx512` merging mode. /// /// the behavior for non-`avx512` instructions is equivalent to `merge`. `zero` is only useful in /// conjunction with a mask register, where bits specified in the mask register correspond to /// unmodified items in the instruction's desination. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MergeMode { Merge, Zero, } impl From for MergeMode { fn from(b: bool) -> Self { if b { MergeMode::Zero } else { MergeMode::Merge } } } /// an `avx512` custom rounding mode. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum SaeMode { RoundNearest, RoundDown, RoundUp, RoundZero, } const SAE_MODES: [SaeMode; 4] = [ SaeMode::RoundNearest, SaeMode::RoundDown, SaeMode::RoundUp, SaeMode::RoundZero, ]; impl SaeMode { /// a human-friendly label for this `SaeMode`: /// /// ``` /// use yaxpeax_x86::long_mode::SaeMode; /// /// assert_eq!(SaeMode::RoundNearest.label(), "{rne-sae}"); /// assert_eq!(SaeMode::RoundDown.label(), "{rd-sae}"); /// assert_eq!(SaeMode::RoundUp.label(), "{ru-sae}"); /// assert_eq!(SaeMode::RoundZero.label(), "{rz-sae}"); /// ``` pub fn label(&self) -> &'static str { match self { SaeMode::RoundNearest => "{rne-sae}", SaeMode::RoundDown => "{rd-sae}", SaeMode::RoundUp => "{ru-sae}", SaeMode::RoundZero => "{rz-sae}", } } fn from(l: bool, lp: bool) -> Self { let mut idx = 0; if l { idx |= 1; } if lp { idx |= 2; } SAE_MODES[idx] } } impl Operand { fn from_spec(inst: &Instruction, spec: OperandSpec) -> Operand { match spec { OperandSpec::Nothing => { Operand::Nothing } // the register in modrm_rrr OperandSpec::RegRRR => { Operand::Register(inst.regs[0]) } OperandSpec::RegRRR_maskmerge => { Operand::RegisterMaskMerge( inst.regs[0], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), MergeMode::from(inst.prefixes.evex_unchecked().merge()), ) } OperandSpec::RegRRR_maskmerge_sae => { Operand::RegisterMaskMergeSae( inst.regs[0], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), MergeMode::from(inst.prefixes.evex_unchecked().merge()), SaeMode::from(inst.prefixes.evex_unchecked().vex().l(), inst.prefixes.evex_unchecked().lp()), ) } OperandSpec::RegRRR_maskmerge_sae_noround => { Operand::RegisterMaskMergeSaeNoround( inst.regs[0], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), MergeMode::from(inst.prefixes.evex_unchecked().merge()), ) } // the register in modrm_mmm (eg modrm mod bits were 11) OperandSpec::RegMMM => { Operand::Register(inst.regs[1]) } OperandSpec::RegMMM_maskmerge => { Operand::RegisterMaskMerge( inst.regs[1], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), MergeMode::from(inst.prefixes.evex_unchecked().merge()), ) } OperandSpec::RegMMM_maskmerge_sae_noround => { Operand::RegisterMaskMergeSaeNoround( inst.regs[1], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), MergeMode::from(inst.prefixes.evex_unchecked().merge()), ) } OperandSpec::RegVex => { Operand::Register(inst.regs[3]) } OperandSpec::RegVex_maskmerge => { Operand::RegisterMaskMerge( inst.regs[3], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), MergeMode::from(inst.prefixes.evex_unchecked().merge()), ) } OperandSpec::Reg4 => { Operand::Register(RegSpec { num: inst.imm as u8, bank: inst.regs[3].bank }) } OperandSpec::ImmI8 => Operand::ImmediateI8(inst.imm as i8), OperandSpec::ImmU8 => Operand::ImmediateU8(inst.imm as u8), OperandSpec::ImmI16 => Operand::ImmediateI16(inst.imm as i16), OperandSpec::ImmU16 => Operand::ImmediateU16(inst.imm as u16), OperandSpec::ImmI32 => Operand::ImmediateI32(inst.imm as i32), OperandSpec::ImmInDispField => 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.regs[1]) } OperandSpec::Deref_si => { Operand::RegDeref(RegSpec::si()) } OperandSpec::Deref_di => { Operand::RegDeref(RegSpec::di()) } OperandSpec::Deref_esi => { Operand::RegDeref(RegSpec::esi()) } OperandSpec::Deref_edi => { Operand::RegDeref(RegSpec::edi()) } OperandSpec::RegDisp => { Operand::RegDisp(inst.regs[1], inst.disp as i32) } OperandSpec::RegScale => { Operand::RegScale(inst.regs[2], inst.scale) } OperandSpec::RegIndexBase => { Operand::RegIndexBase(inst.regs[1], inst.regs[2]) } OperandSpec::RegIndexBaseDisp => { Operand::RegIndexBaseDisp(inst.regs[1], inst.regs[2], inst.disp as i32) } OperandSpec::RegScaleDisp => { Operand::RegScaleDisp(inst.regs[2], inst.scale, inst.disp as i32) } OperandSpec::RegIndexBaseScale => { Operand::RegIndexBaseScale(inst.regs[1], inst.regs[2], inst.scale) } OperandSpec::RegIndexBaseScaleDisp => { Operand::RegIndexBaseScaleDisp(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32) } OperandSpec::Deref_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegDerefMasked(inst.regs[1], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegDeref(inst.regs[1]) } } OperandSpec::RegDisp_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegDispMasked(inst.regs[1], inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegDisp(inst.regs[1], inst.disp as i32) } } OperandSpec::RegScale_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegScaleMasked(inst.regs[2], inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegScale(inst.regs[2], inst.scale) } } OperandSpec::RegScaleDisp_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegScaleDispMasked(inst.regs[2], inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegScaleDisp(inst.regs[2], inst.scale, inst.disp as i32) } } OperandSpec::RegIndexBase_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegIndexBaseMasked(inst.regs[1], inst.regs[2], RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegIndexBase(inst.regs[1], inst.regs[2]) } } OperandSpec::RegIndexBaseDisp_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegIndexBaseDispMasked(inst.regs[1], inst.regs[2], inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegIndexBaseDisp(inst.regs[1], inst.regs[2], inst.disp as i32) } } OperandSpec::RegIndexBaseScale_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegIndexBaseScaleMasked(inst.regs[1], inst.regs[2], inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegIndexBaseScale(inst.regs[1], inst.regs[2], inst.scale) } } OperandSpec::RegIndexBaseScaleDisp_mask => { if inst.prefixes.evex_unchecked().mask_reg() != 0 { Operand::RegIndexBaseScaleDispMasked(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) } else { Operand::RegIndexBaseScaleDisp(inst.regs[1], inst.regs[2], inst.scale, inst.disp as i32) } } } } /// returns `true` if this operand implies a memory access, `false` otherwise. /// /// notably, the `lea` instruction uses a memory operand without actually ever accessing /// memory. pub fn is_memory(&self) -> bool { match self { Operand::DisplacementU16(_) | Operand::DisplacementU32(_) | Operand::RegDeref(_) | Operand::RegDisp(_, _) | Operand::RegScale(_, _) | Operand::RegIndexBase(_, _) | Operand::RegIndexBaseDisp(_, _, _) | Operand::RegScaleDisp(_, _, _) | Operand::RegIndexBaseScale(_, _, _) | Operand::RegIndexBaseScaleDisp(_, _, _, _) | Operand::RegDerefMasked(_, _) | Operand::RegDispMasked(_, _, _) | Operand::RegScaleMasked(_, _, _) | Operand::RegIndexBaseMasked(_, _, _) | Operand::RegIndexBaseDispMasked(_, _, _, _) | Operand::RegScaleDispMasked(_, _, _, _) | Operand::RegIndexBaseScaleMasked(_, _, _, _) | Operand::RegIndexBaseScaleDispMasked(_, _, _, _, _) => { true }, Operand::ImmediateI8(_) | Operand::ImmediateU8(_) | Operand::ImmediateI16(_) | Operand::ImmediateU16(_) | Operand::ImmediateU32(_) | Operand::ImmediateI32(_) | Operand::Register(_) | Operand::RegisterMaskMerge(_, _, _) | Operand::RegisterMaskMergeSae(_, _, _, _) | Operand::RegisterMaskMergeSaeNoround(_, _, _) | Operand::Nothing => { false } } } /// return the width of this operand, in bytes. register widths are determined by the /// register's class. the widths of memory operands are recorded on the instruction this /// `Operand` came from; `None` here means the authoritative width is `instr.mem_size()`. pub fn width(&self) -> Option { match self { Operand::Register(reg) => { Some(reg.width()) } Operand::RegisterMaskMerge(reg, _, _) => { Some(reg.width()) } Operand::ImmediateI8(_) | Operand::ImmediateU8(_) => { Some(1) } Operand::ImmediateI16(_) | Operand::ImmediateU16(_) => { Some(2) } Operand::ImmediateI32(_) | Operand::ImmediateU32(_) => { Some(4) } // memory operands or `Nothing` _ => { None } } } } #[test] fn operand_size() { assert_eq!(core::mem::size_of::(), 1); assert_eq!(core::mem::size_of::(), 2); // assert_eq!(core::mem::size_of::(), 4); // assert_eq!(core::mem::size_of::(), 40); } /// an `x86` register class - `qword`, `dword`, `xmmword`, `segment`, and so on. /// /// this is mostly useful for comparing a `RegSpec`'s [`RegSpec::class()`] with a constant out of /// [`register_class`]. #[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] pub struct RegisterClass { kind: RegisterBank, } const REGISTER_CLASS_NAMES: &[&'static str] = &[ "dword", "word", "byte", "cr", "dr", "segment", "xmm", "BUG. PLEASE REPORT.", "BUG. PLEASE REPORT.", "BUG. PLEASE REPORT.", "ymm", "BUG. PLEASE REPORT.", "BUG. PLEASE REPORT.", "BUG. PLEASE REPORT.", "zmm", "BUG. PLEASE REPORT.", "BUG. PLEASE REPORT.", "BUG. PLEASE REPORT.", "x87-stack", "mmx", "k", "eip", "eflags", ]; /// high-level register classes in an x86 machine, such as "4-byte general purpose", "xmm", "x87", /// and so on. constants in this module are useful for inspecting the register class of a decoded /// instruction. as an example: /// ``` /// use yaxpeax_x86::protected_mode::{self as amd64}; /// use yaxpeax_x86::protected_mode::{Opcode, Operand, RegisterClass}; /// use yaxpeax_arch::{Decoder, U8Reader}; /// /// let movsx_eax_cl = &[0x0f, 0xbe, 0xc1]; /// let decoder = amd64::InstDecoder::default(); /// let instruction = decoder /// .decode(&mut U8Reader::new(movsx_eax_cl)) /// .expect("can decode"); /// /// assert_eq!(instruction.opcode(), Opcode::MOVSX); /// /// fn show_register_class_info(regclass: RegisterClass) { /// match regclass { /// amd64::register_class::D => { /// println!(" and is a dword register"); /// } /// amd64::register_class::B => { /// println!(" and is a byte register"); /// } /// other => { /// panic!("unexpected and invalid register class {:?}", other); /// } /// } /// } /// /// if let Operand::Register(regspec) = instruction.operand(0) { /// println!("first operand is {}", regspec); /// show_register_class_info(regspec.class()); /// } /// /// if let Operand::Register(regspec) = instruction.operand(1) { /// println!("first operand is {}", regspec); /// show_register_class_info(regspec.class()); /// } /// ``` /// /// this is preferable to alternatives like checking register names against a known list: a /// register class is one byte and "is qword general-purpose" can then be a simple one-byte /// compare, instead of 16 string compares. /// /// `yaxpeax-x86` does not attempt to further distinguish between, for example, register /// suitability as operands. as an example, `cl` is only a byte register, with no additional /// register class to describe its use as an implicit shift operand. pub mod register_class { use super::{RegisterBank, RegisterClass}; /// doubleword registers: eax through edi. pub const D: RegisterClass = RegisterClass { kind: RegisterBank::D }; /// word registers: ax through di. pub const W: RegisterClass = RegisterClass { kind: RegisterBank::W }; /// byte registers: al, cl, dl, bl, ah, ch, dh, bh. pub const B: RegisterClass = RegisterClass { kind: RegisterBank::B }; /// control registers cr0 through cr7. pub const CR: RegisterClass = RegisterClass { kind: RegisterBank::CR}; /// debug registers dr0 through dr7. pub const DR: RegisterClass = RegisterClass { kind: RegisterBank::DR }; /// segment registers es, cs, ss, ds, fs, gs. pub const S: RegisterClass = RegisterClass { kind: RegisterBank::S }; /// xmm registers xmm0 through xmm31. pub const X: RegisterClass = RegisterClass { kind: RegisterBank::X }; /// ymm registers ymm0 through ymm31. pub const Y: RegisterClass = RegisterClass { kind: RegisterBank::Y }; /// zmm registers zmm0 through zmm31. pub const Z: RegisterClass = RegisterClass { kind: RegisterBank::Z }; /// x87 floating point stack entries st(0) through st(7). pub const ST: RegisterClass = RegisterClass { kind: RegisterBank::ST }; /// mmx registers mm0 through mm7. pub const MM: RegisterClass = RegisterClass { kind: RegisterBank::MM }; /// `AVX512` mask registers k0 through k7. pub const K: RegisterClass = RegisterClass { kind: RegisterBank::K }; /// the full instruction pointer register. pub const EIP: RegisterClass = RegisterClass { kind: RegisterBank::EIP }; /// the full cpu flags register. pub const EFLAGS: RegisterClass = RegisterClass { kind: RegisterBank::EFlags }; } impl RegisterClass { /// return a human-friendly name for this register class pub fn name(&self) -> &'static str { REGISTER_CLASS_NAMES[self.kind as usize] } /// return the size of this register class, in bytes pub fn width(&self) -> u8 { match self.kind { RegisterBank::D => 4, RegisterBank::W => 2, RegisterBank::B => 1, RegisterBank::CR | RegisterBank::DR => { 4 }, RegisterBank::S => { 2 }, RegisterBank::EIP => { 4 } RegisterBank::EFlags => { 4 } RegisterBank::X => { 16 } RegisterBank::Y => { 32 } RegisterBank::Z => { 64 } RegisterBank::ST => { 10 } RegisterBank::MM => { 8 } RegisterBank::K => { 8 } } } } #[allow(non_camel_case_types)] #[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] enum RegisterBank { 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 } /// the segment register used by the corresponding instruction. /// /// typically this will be `ds` but can be overridden. some instructions have specific segment /// registers used regardless of segment prefixes, and in these cases `yaxpeax-x86` will report the /// actual segment register a physical processor would use. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum Segment { DS = 0, CS, ES, FS, GS, SS } const BMI1: [Opcode; 6] = [ Opcode::ANDN, Opcode::BEXTR, Opcode::BLSI, Opcode::BLSMSK, Opcode::BLSR, Opcode::TZCNT, ]; const BMI2: [Opcode; 8] = [ Opcode::BZHI, Opcode::MULX, Opcode::PDEP, Opcode::PEXT, Opcode::RORX, Opcode::SARX, Opcode::SHRX, Opcode::SHLX, ]; #[allow(dead_code)] const XSAVE: [Opcode; 10] = [ Opcode::XGETBV, Opcode::XRSTOR, Opcode::XRSTORS, Opcode::XSAVE, Opcode::XSAVEC, Opcode::XSAVEC64, Opcode::XSAVEOPT, Opcode::XSAVES, Opcode::XSAVES64, Opcode::XSETBV, ]; #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Opcode { 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, 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, RETURN, 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, UD0, UD1, 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, PCONFIG, MONITOR, MWAIT, MONITORX, MWAITX, CLAC, STAC, ENCLS, ENCLV, XGETBV, XSETBV, VMFUNC, XABORT, XBEGIN, XEND, XTEST, ENCLU, RDPKRU, WRPKRU, RDPRU, CLZERO, 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, EXTRQ, INSERTQ, MOVNTSS, MOVNTSD, 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, VMREAD, VMWRITE, XORPS, XORPD, VMOVDDUP, VPSHUFLW, VPSHUFHW, 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, VPACKUSDW, VPACKSSWB, VPACKUSWB, VPADDB, VPADDD, VPADDQ, VPADDSB, VPADDSW, VPADDUSB, VPADDUSW, VPADDW, VPALIGNR, VANDPD, VANDPS, VORPD, VORPS, VANDNPD, VANDNPS, VPAND, VPANDN, VPAVGB, VPAVGW, VPBLENDD, VPBLENDVB, VPBLENDW, VPBROADCASTB, VPBROADCASTD, VPBROADCASTQ, VPBROADCASTW, VPCLMULQDQ, VPCMPEQB, VPCMPEQD, VPCMPEQQ, VPCMPEQW, VPCMPGTB, VPCMPGTD, VPCMPGTQ, VPCMPGTW, VPCMPESTRI, VPCMPESTRM, VPCMPISTRI, VPCMPISTRM, VPERM2F128, VPERM2I128, VPERMD, VPERMILPD, VPERMILPS, VPERMPD, VPERMPS, VPERMQ, VPEXTRB, VPEXTRD, VPEXTRQ, VPEXTRW, VPGATHERDD, VPGATHERDQ, VPGATHERQD, VPGATHERQQ, VPHADDD, VPHADDSW, VPHADDW, VPMADDUBSW, VPHMINPOSUW, VPHSUBD, VPHSUBSW, VPHSUBW, VPINSRB, VPINSRD, VPINSRQ, VPINSRW, VPMADDWD, VPMASKMOVD, VPMASKMOVQ, VPMAXSB, VPMAXSD, VPMAXSW, VPMAXUB, VPMAXUW, VPMAXUD, VPMINSB, VPMINSW, VPMINSD, VPMINUB, VPMINUW, VPMINUD, VPMOVMSKB, VPMOVSXBD, VPMOVSXBQ, VPMOVSXBW, VPMOVSXDQ, VPMOVSXWD, VPMOVSXWQ, VPMOVZXBD, VPMOVZXBQ, VPMOVZXBW, VPMOVZXDQ, VPMOVZXWD, VPMOVZXWQ, VPMULDQ, VPMULHRSW, VPMULHUW, VPMULHW, VPMULLQ, 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, VZEROALL, VLDMXCSR, VSTMXCSR, 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, INVLPGB, TLBSYNC, 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, SALC, 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, JECXZ, PUSHA, POPA, BOUND, ARPL, AAS, AAA, DAS, DAA, AAM, AAD, // started shipping in Tremont, 2020 sept 23 MOVDIR64B, MOVDIRI, // started shipping in Tiger Lake, 2020 sept 2 AESDEC128KL, AESDEC256KL, AESDECWIDE128KL, AESDECWIDE256KL, AESENC128KL, AESENC256KL, AESENCWIDE128KL, AESENCWIDE256KL, ENCODEKEY128, ENCODEKEY256, LOADIWKEY, // unsure HRESET, // 3dnow FEMMS, PI2FW, PI2FD, PF2IW, PF2ID, PMULHRW, PFCMPGE, PFMIN, PFRCP, PFRSQRT, PFSUB, PFADD, PFCMPGT, PFMAX, PFRCPIT1, PFRSQIT1, PFSUBR, PFACC, PFCMPEQ, PFMUL, PFMULHRW, PFRCPIT2, PFNACC, PFPNACC, PSWAPD, PAVGUSB, // ENQCMD ENQCMD, ENQCMDS, // INVPCID INVEPT, INVVPID, INVPCID, // PTWRITE PTWRITE, // GFNI GF2P8AFFINEQB, GF2P8AFFINEINVQB, GF2P8MULB, // CET WRUSS, WRSS, INCSSP, SAVEPREVSSP, SETSSBSY, CLRSSBSY, RSTORSSP, // TDX TDCALL, SEAMRET, SEAMOPS, SEAMCALL, // WAITPKG TPAUSE, UMONITOR, UMWAIT, // UINTR UIRET, TESTUI, CLUI, STUI, SENDUIPI, // TSXLDTRK XSUSLDTRK, XRESLDTRK, // AVX512F VALIGND, VALIGNQ, VBLENDMPD, VBLENDMPS, VCOMPRESSPD, VCOMPRESSPS, VCVTPD2UDQ, VCVTTPD2UDQ, VCVTPS2UDQ, VCVTTPS2UDQ, VCVTQQ2PD, VCVTQQ2PS, VCVTSD2USI, VCVTTSD2USI, VCVTSS2USI, VCVTTSS2USI, VCVTUDQ2PD, VCVTUDQ2PS, VCVTUSI2USD, VCVTUSI2USS, VEXPANDPD, VEXPANDPS, VEXTRACTF32X4, VEXTRACTF64X4, VEXTRACTI32X4, VEXTRACTI64X4, VFIXUPIMMPD, VFIXUPIMMPS, VFIXUPIMMSD, VFIXUPIMMSS, VGETEXPPD, VGETEXPPS, VGETEXPSD, VGETEXPSS, VGETMANTPD, VGETMANTPS, VGETMANTSD, VGETMANTSS, VINSERTF32X4, VINSERTF64X4, VINSERTI64X4, VMOVDQA32, VMOVDQA64, VMOVDQU32, VMOVDQU64, VPBLENDMD, VPBLENDMQ, VPCMPD, VPCMPUD, VPCMPQ, VPCMPUQ, VPCOMPRESSQ, VPCOMPRESSD, VPERMI2D, VPERMI2Q, VPERMI2PD, VPERMI2PS, VPERMT2D, VPERMT2Q, VPERMT2PD, VPERMT2PS, VPMAXSQ, VPMAXUQ, VPMINSQ, VPMINUQ, VPMOVSQB, VPMOVUSQB, VPMOVSQW, VPMOVUSQW, VPMOVSQD, VPMOVUSQD, VPMOVSDB, VPMOVUSDB, VPMOVSDW, VPMOVUSDW, VPROLD, VPROLQ, VPROLVD, VPROLVQ, VPRORD, VPRORQ, VPRORRD, VPRORRQ, VPSCATTERDD, VPSCATTERDQ, VPSCATTERQD, VPSCATTERQQ, VPSRAQ, VPSRAVQ, VPTESTNMD, VPTESTNMQ, VPTERNLOGD, VPTERNLOGQ, VPTESTMD, VPTESTMQ, VRCP14PD, VRCP14PS, VRCP14SD, VRCP14SS, VRNDSCALEPD, VRNDSCALEPS, VRNDSCALESD, VRNDSCALESS, VRSQRT14PD, VRSQRT14PS, VRSQRT14SD, VRSQRT14SS, VSCALEDPD, VSCALEDPS, VSCALEDSD, VSCALEDSS, VSCATTERDD, VSCATTERDQ, VSCATTERQD, VSCATTERQQ, VSHUFF32X4, VSHUFF64X2, VSHUFI32X4, VSHUFI64X2, // AVX512DQ VCVTTPD2QQ, VCVTPD2QQ, VCVTTPD2UQQ, VCVTPD2UQQ, VCVTTPS2QQ, VCVTPS2QQ, VCVTTPS2UQQ, VCVTPS2UQQ, VCVTUQQ2PD, VCVTUQQ2PS, VEXTRACTF64X2, VEXTRACTI64X2, VFPCLASSPD, VFPCLASSPS, VFPCLASSSD, VFPCLASSSS, VINSERTF64X2, VINSERTI64X2, VPMOVM2D, VPMOVM2Q, VPMOVB2D, VPMOVQ2M, VRANGEPD, VRANGEPS, VRANGESD, VRANGESS, VREDUCEPD, VREDUCEPS, VREDUCESD, VREDUCESS, // AVX512BW VDBPSADBW, VMOVDQU8, VMOVDQU16, VPBLENDMB, VPBLENDMW, VPCMPB, VPCMPUB, VPCMPW, VPCMPUW, VPERMW, VPERMI2B, VPERMI2W, VPMOVM2B, VPMOVM2W, VPMOVB2M, VPMOVW2M, VPMOVSWB, VPMOVUSWB, VPSLLVW, VPSRAVW, VPSRLVW, VPTESTNMB, VPTESTNMW, VPTESTMB, VPTESTMW, // AVX512CD VPBROADCASTM, VPCONFLICTD, VPCONFLICTQ, VPLZCNTD, VPLZCNTQ, KUNPCKBW, KUNPCKWD, KUNPCKDQ, KADDB, KANDB, KANDNB, KMOVB, KNOTB, KORB, KORTESTB, KSHIFTLB, KSHIFTRB, KTESTB, KXNORB, KXORB, KADDW, KANDW, KANDNW, KMOVW, KNOTW, KORW, KORTESTW, KSHIFTLW, KSHIFTRW, KTESTW, KXNORW, KXORW, KADDD, KANDD, KANDND, KMOVD, KNOTD, KORD, KORTESTD, KSHIFTLD, KSHIFTRD, KTESTD, KXNORD, KXORD, KADDQ, KANDQ, KANDNQ, KMOVQ, KNOTQ, KORQ, KORTESTQ, KSHIFTLQ, KSHIFTRQ, KTESTQ, KXNORQ, KXORQ, // AVX512ER VEXP2PD, VEXP2PS, VEXP2SD, VEXP2SS, VRCP28PD, VRCP28PS, VRCP28SD, VRCP28SS, VRSQRT28PD, VRSQRT28PS, VRSQRT28SD, VRSQRT28SS, // AVX512PF VGATHERPF0DPD, VGATHERPF0DPS, VGATHERPF0QPD, VGATHERPF0QPS, VGATHERPF1DPD, VGATHERPF1DPS, VGATHERPF1QPD, VGATHERPF1QPS, VSCATTERPF0DPD, VSCATTERPF0DPS, VSCATTERPF0QPD, VSCATTERPF0QPS, VSCATTERPF1DPD, VSCATTERPF1DPS, VSCATTERPF1QPD, VSCATTERPF1QPS, // MPX BNDMK, BNDCL, BNDCU, BNDCN, BNDMOV, BNDLDX, BNDSTX, VGF2P8AFFINEQB, VGF2P8AFFINEINVQB, VPSHRDQ, VPSHRDD, VPSHRDW, VPSHLDQ, VPSHLDD, VPSHLDW, VBROADCASTF32X8, VBROADCASTF64X4, VBROADCASTF32X4, VBROADCASTF64X2, VBROADCASTF32X2, VBROADCASTI32X8, VBROADCASTI64X4, VBROADCASTI32X4, VBROADCASTI64X2, VBROADCASTI32X2, VEXTRACTI32X8, VEXTRACTF32X8, VINSERTI32X8, VINSERTF32X8, VINSERTI32X4, V4FNMADDSS, V4FNMADDPS, VCVTNEPS2BF16, V4FMADDSS, V4FMADDPS, VCVTNE2PS2BF16, VP2INTERSECTD, VP2INTERSECTQ, VP4DPWSSDS, VP4DPWSSD, VPDPWSSDS, VPDPWSSD, VPDPBUSDS, VDPBF16PS, VPBROADCASTMW2D, VPBROADCASTMB2Q, VPMOVD2M, VPMOVQD, VPMOVWB, VPMOVDB, VPMOVDW, VPMOVQB, VPMOVQW, VGF2P8MULB, VPMADD52HUQ, VPMADD52LUQ, VPSHUFBITQMB, VPERMB, VPEXPANDD, VPEXPANDQ, VPABSQ, VPRORVD, VPRORVQ, VPMULTISHIFTQB, VPERMT2B, VPERMT2W, VPSHRDVQ, VPSHRDVD, VPSHRDVW, VPSHLDVQ, VPSHLDVD, VPSHLDVW, VPCOMPRESSB, VPCOMPRESSW, VPEXPANDB, VPEXPANDW, VPOPCNTD, VPOPCNTQ, VPOPCNTB, VPOPCNTW, VSCALEFSS, VSCALEFSD, VSCALEFPS, VSCALEFPD, VPDPBUSD, VCVTUSI2SD, VCVTUSI2SS, VPXORD, VPXORQ, VPORD, VPORQ, VPANDND, VPANDNQ, VPANDD, VPANDQ, PSMASH, PVALIDATE, RMPADJUST, RMPUPDATE, } impl PartialEq for Instruction { fn eq(&self, other: &Self) -> bool { if self.prefixes != other.prefixes { return false; } if self.opcode != other.opcode { return false; } if self.operand_count != other.operand_count { return false; } if self.mem_size != other.mem_size { return false; } for i in 0..self.operand_count { if self.operands[i as usize] != other.operands[i as usize] { return false; } if self.operand(i) != other.operand(i) { return false; } } true } } /// an `x86` instruction. /// /// typically an opcode will be inspected by [`Instruction::opcode()`], and an instruction has /// [`Instruction::operand_count()`] many operands. operands are provided by /// [`Instruction::operand()`]. #[derive(Debug, Clone, Copy, Eq)] pub struct Instruction { pub prefixes: Prefixes, /* modrm_rrr: RegSpec, modrm_mmm: RegSpec, // doubles as sib_base sib_index: RegSpec, vex_reg: RegSpec, */ regs: [RegSpec; 4], scale: u8, length: u8, operand_count: u8, operands: [OperandSpec; 4], imm: u32, disp: u32, opcode: Opcode, mem_size: u8, } impl yaxpeax_arch::Instruction for Instruction { fn well_defined(&self) -> bool { // TODO: this is incorrect! true } } #[derive(Debug, PartialEq, Eq, Copy, Clone)] #[non_exhaustive] pub enum DecodeError { ExhaustedInput, InvalidOpcode, InvalidOperand, InvalidPrefixes, TooLong, IncompleteDecoder, } impl yaxpeax_arch::DecodeError for DecodeError { fn data_exhausted(&self) -> bool { self == &DecodeError::ExhaustedInput } fn bad_opcode(&self) -> bool { self == &DecodeError::InvalidOpcode } fn bad_operand(&self) -> bool { self == &DecodeError::InvalidOperand } fn description(&self) -> &'static str { match self { DecodeError::ExhaustedInput => { "exhausted input" }, DecodeError::InvalidOpcode => { "invalid opcode" }, DecodeError::InvalidOperand => { "invalid operand" }, DecodeError::InvalidPrefixes => { "invalid prefixes" }, DecodeError::TooLong => { "too long" }, DecodeError::IncompleteDecoder => { "the decoder is incomplete" }, } } } #[cfg(feature = "std")] extern crate std; #[cfg(feature = "std")] impl std::error::Error for DecodeError { fn description(&self) -> &str { ::description(self) } } #[allow(non_camel_case_types)] #[derive(Debug, Copy, Clone, Eq, PartialEq)] enum OperandSpec { Nothing, // the register in modrm_rrr RegRRR, // the register in modrm_rrr and is EVEX-encoded (may have a mask register, is merged or // zeroed) RegRRR_maskmerge, // the register in modrm_rrr and is EVEX-encoded (may have a mask register, is merged or // zeroed). additionally, this instruction has exceptions suppressed with a potentially // custom rounding mode. RegRRR_maskmerge_sae, // the register in modrm_rrr and is EVEX-encoded (may have a mask register, is merged or // zeroed). additionally, this instruction has exceptions suppressed. RegRRR_maskmerge_sae_noround, // the register in modrm_mmm (eg modrm mod bits were 11) RegMMM, // same as `RegRRR`: the register is modrm's `mmm` bits, and may be masekd. RegMMM_maskmerge, RegMMM_maskmerge_sae_noround, // the register selected by vex-vvvv bits RegVex, RegVex_maskmerge, // the register selected by a handful of avx2 vex-coded instructions, // stuffed in imm4. Reg4, ImmI8, ImmI16, ImmI32, ImmU8, ImmU16, // 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. // turns out `insertq` and `extrq` are also two-immediate instructions, so this is generalized // to cover them too. ImmInDispField, DispU16, DispU32, Deref, Deref_si, Deref_di, Deref_esi, Deref_edi, RegDisp, RegScale, RegIndexBase, RegIndexBaseDisp, RegScaleDisp, RegIndexBaseScale, RegIndexBaseScaleDisp, Deref_mask, RegDisp_mask, RegScale_mask, RegScaleDisp_mask, RegIndexBase_mask, RegIndexBaseDisp_mask, RegIndexBaseScale_mask, RegIndexBaseScaleDisp_mask, } // 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 // which themselves are bounded, but their #[derive] require T to // implement these traits. /// a trivial struct for `yaxpeax_arch::Arch` to be implemented on. it's only interesting for the /// associated type parameters. #[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] #[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub struct Arch; impl yaxpeax_arch::Arch for Arch { type Address = u32; type Word = u8; type Instruction = Instruction; type DecodeError = DecodeError; type Decoder = InstDecoder; type Operand = Operand; } 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) } } /// an `x86` instruction decoder. /// /// fundamentally this is one or two primitives with no additional state kept during decoding. it /// can be copied cheaply, hashed cheaply, compared cheaply. if you really want to share an /// `InstDecoder` between threads, you could - but you might want to clone it instead. /// /// unless you're using an `Arc>`, which is _fine_ but i'd be very curious about /// the design requiring that. #[derive(PartialEq, Copy, Clone, Eq, Hash, PartialOrd, Ord)] pub struct InstDecoder { // extensions tracked here: // 0. SSE3 // 1. SSSE3 // 2. monitor (intel-only?) // 3. vmx (some atom chips still lack it) // 4. fma3 (intel haswell/broadwell+, amd piledriver+) // 5. cmpxchg16b (some amd are missing this one) // 6. sse4.1 // 7. sse4.2 // 8. movbe // 9. popcnt (independent of BMI) // 10. aesni // 11. xsave (xsave, xrestor, xsetbv, xgetbv) // 12. rdrand (intel ivybridge+, amd ..??) // 13. sgx (eadd, eblock, ecreate, edbgrd, edbgwr, einit, eldb, eldu, epa, eremove, etrace, // ewb, eenter, eexit, egetkey, ereport, eresume) // 14. bmi1 (intel haswell+, amd jaguar+) // 15. avx2 (intel haswell+, amd excavator+) // 16. bmi2 (intel ?, amd ?) // 17. invpcid // 18. mpx // 19. avx512_f // 20. avx512_dq // 21. rdseed // 22. adx // 23. avx512_fma // 24. pcommit // 25. clflushopt // 26. clwb // 27. avx512_pf // 28. avx512_er // 29. avx512_cd // 30. sha // 31. avx512_bw // 32. avx512_vl // 33. prefetchwt1 // 34. avx512_vbmi // 35. avx512_vbmi2 // 36. gfni (galois field instructions) // 37. vaes // 38. pclmulqdq // 39. avx_vnni // 40. avx512_bitalg // 41. avx512_vpopcntdq // 42. avx512_4vnniw // 43. avx512_4fmaps // 44. cx8 // cmpxchg8 - is this actually optional in x86? // 45. syscall // syscall/sysret - actually optional in x86? // 46. rdtscp // actually optional in x86? // 47. abm (lzcnt, popcnt) // 48. sse4a // 49. 3dnowprefetch // actually optional? // 50. xop // 51. skinit // 52. tbm // 53. intel quirks // 54. amd quirks // 55. avx (intel ?, amd ?) // 56. amd-v/svm // 57. lahfsahf // 58. cmov // 59. f16c // 60. fma4 // 61. prefetchw // 62. tsx // 63. lzcnt flags: u64, } impl InstDecoder { /// instantiates an x86 decoder that decodes the bare minimum of protected-mode x86. /// /// pedantic and only decodes what the spec says is well-defined, rejecting undefined sequences /// and any instructions defined by extensions. pub fn minimal() -> Self { InstDecoder { flags: 0, } } /// helper to decode an instruction directly from a byte slice. /// /// this lets callers avoid the work of setting up a [`yaxpeax_arch::U8Reader`] for the slice /// to decode. pub fn decode_slice(&self, data: &[u8]) -> Result { let mut reader = yaxpeax_arch::U8Reader::new(data); self.decode(&mut reader) } pub fn sse3(&self) -> bool { self.flags & (1 << 0) != 0 } pub fn with_sse3(mut self) -> Self { self.flags |= 1 << 0; self } pub fn ssse3(&self) -> bool { self.flags & (1 << 1) != 0 } pub fn with_ssse3(mut self) -> Self { self.flags |= 1 << 1; self } pub fn monitor(&self) -> bool { self.flags & (1 << 2) != 0 } pub fn with_monitor(mut self) -> Self { self.flags |= 1 << 2; self } pub fn vmx(&self) -> bool { self.flags & (1 << 3) != 0 } pub fn with_vmx(mut self) -> Self { self.flags |= 1 << 3; self } pub fn fma3(&self) -> bool { self.flags & (1 << 4) != 0 } pub fn with_fma3(mut self) -> Self { self.flags |= 1 << 4; self } pub fn cmpxchg16b(&self) -> bool { self.flags & (1 << 5) != 0 } pub fn with_cmpxchg16b(mut self) -> Self { self.flags |= 1 << 5; self } pub fn sse4_1(&self) -> bool { self.flags & (1 << 6) != 0 } pub fn with_sse4_1(mut self) -> Self { self.flags |= 1 << 6; self } pub fn sse4_2(&self) -> bool { self.flags & (1 << 7) != 0 } pub fn with_sse4_2(mut self) -> Self { self.flags |= 1 << 7; self } pub fn with_sse4(self) -> Self { self .with_sse4_1() .with_sse4_2() } pub fn movbe(&self) -> bool { self.flags & (1 << 8) != 0 } pub fn with_movbe(mut self) -> Self { self.flags |= 1 << 8; self } pub fn popcnt(&self) -> bool { self.flags & (1 << 9) != 0 } pub fn with_popcnt(mut self) -> Self { self.flags |= 1 << 9; self } pub fn aesni(&self) -> bool { self.flags & (1 << 10) != 0 } pub fn with_aesni(mut self) -> Self { self.flags |= 1 << 10; self } pub fn xsave(&self) -> bool { self.flags & (1 << 11) != 0 } pub fn with_xsave(mut self) -> Self { self.flags |= 1 << 11; self } pub fn rdrand(&self) -> bool { self.flags & (1 << 12) != 0 } pub fn with_rdrand(mut self) -> Self { self.flags |= 1 << 12; self } pub fn sgx(&self) -> bool { self.flags & (1 << 13) != 0 } pub fn with_sgx(mut self) -> Self { self.flags |= 1 << 13; self } pub fn bmi1(&self) -> bool { self.flags & (1 << 14) != 0 } pub fn with_bmi1(mut self) -> Self { self.flags |= 1 << 14; self } pub fn avx2(&self) -> bool { self.flags & (1 << 15) != 0 } pub fn with_avx2(mut self) -> Self { self.flags |= 1 << 15; self } /// `bmi2` indicates support for the `BZHI`, `MULX`, `PDEP`, `PEXT`, `RORX`, `SARX`, `SHRX`, /// 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 } pub fn with_bmi2(mut self) -> Self { self.flags |= 1 << 16; self } pub fn invpcid(&self) -> bool { self.flags & (1 << 17) != 0 } pub fn with_invpcid(mut self) -> Self { self.flags |= 1 << 17; self } pub fn mpx(&self) -> bool { self.flags & (1 << 18) != 0 } pub fn with_mpx(mut self) -> Self { self.flags |= 1 << 18; self } pub fn avx512_f(&self) -> bool { self.flags & (1 << 19) != 0 } pub fn with_avx512_f(mut self) -> Self { self.flags |= 1 << 19; self } pub fn avx512_dq(&self) -> bool { self.flags & (1 << 20) != 0 } pub fn with_avx512_dq(mut self) -> Self { self.flags |= 1 << 20; self } pub fn rdseed(&self) -> bool { self.flags & (1 << 21) != 0 } pub fn with_rdseed(mut self) -> Self { self.flags |= 1 << 21; self } pub fn adx(&self) -> bool { self.flags & (1 << 22) != 0 } pub fn with_adx(mut self) -> Self { self.flags |= 1 << 22; self } pub fn avx512_fma(&self) -> bool { self.flags & (1 << 23) != 0 } pub fn with_avx512_fma(mut self) -> Self { self.flags |= 1 << 23; self } pub fn pcommit(&self) -> bool { self.flags & (1 << 24) != 0 } pub fn with_pcommit(mut self) -> Self { self.flags |= 1 << 24; self } pub fn clflushopt(&self) -> bool { self.flags & (1 << 25) != 0 } pub fn with_clflushopt(mut self) -> Self { self.flags |= 1 << 25; self } pub fn clwb(&self) -> bool { self.flags & (1 << 26) != 0 } pub fn with_clwb(mut self) -> Self { self.flags |= 1 << 26; self } pub fn avx512_pf(&self) -> bool { self.flags & (1 << 27) != 0 } pub fn with_avx512_pf(mut self) -> Self { self.flags |= 1 << 27; self } pub fn avx512_er(&self) -> bool { self.flags & (1 << 28) != 0 } pub fn with_avx512_er(mut self) -> Self { self.flags |= 1 << 28; self } pub fn avx512_cd(&self) -> bool { self.flags & (1 << 29) != 0 } pub fn with_avx512_cd(mut self) -> Self { self.flags |= 1 << 29; self } pub fn sha(&self) -> bool { self.flags & (1 << 30) != 0 } pub fn with_sha(mut self) -> Self { self.flags |= 1 << 30; self } pub fn avx512_bw(&self) -> bool { self.flags & (1 << 31) != 0 } pub fn with_avx512_bw(mut self) -> Self { self.flags |= 1 << 31; self } pub fn avx512_vl(&self) -> bool { self.flags & (1 << 32) != 0 } pub fn with_avx512_vl(mut self) -> Self { self.flags |= 1 << 32; self } pub fn prefetchwt1(&self) -> bool { self.flags & (1 << 33) != 0 } pub fn with_prefetchwt1(mut self) -> Self { self.flags |= 1 << 33; self } pub fn avx512_vbmi(&self) -> bool { self.flags & (1 << 34) != 0 } pub fn with_avx512_vbmi(mut self) -> Self { self.flags |= 1 << 34; self } pub fn avx512_vbmi2(&self) -> bool { self.flags & (1 << 35) != 0 } pub fn with_avx512_vbmi2(mut self) -> Self { self.flags |= 1 << 35; self } pub fn gfni(&self) -> bool { self.flags & (1 << 36) != 0 } pub fn with_gfni(mut self) -> Self { self.flags |= 1 << 36; self } pub fn vaes(&self) -> bool { self.flags & (1 << 37) != 0 } pub fn with_vaes(mut self) -> Self { self.flags |= 1 << 37; self } pub fn pclmulqdq(&self) -> bool { self.flags & (1 << 38) != 0 } pub fn with_pclmulqdq(mut self) -> Self { self.flags |= 1 << 38; self } pub fn avx_vnni(&self) -> bool { self.flags & (1 << 39) != 0 } pub fn with_avx_vnni(mut self) -> Self { self.flags |= 1 << 39; self } pub fn avx512_bitalg(&self) -> bool { self.flags & (1 << 40) != 0 } pub fn with_avx512_bitalg(mut self) -> Self { self.flags |= 1 << 40; self } pub fn avx512_vpopcntdq(&self) -> bool { self.flags & (1 << 41) != 0 } pub fn with_avx512_vpopcntdq(mut self) -> Self { self.flags |= 1 << 41; self } pub fn avx512_4vnniw(&self) -> bool { self.flags & (1 << 42) != 0 } pub fn with_avx512_4vnniw(mut self) -> Self { self.flags |= 1 << 42; self } pub fn avx512_4fmaps(&self) -> bool { self.flags & (1 << 43) != 0 } pub fn with_avx512_4fmaps(mut self) -> Self { self.flags |= 1 << 43; self } /// returns `true` if this `InstDecoder` has **all** `avx512` features enabled. pub fn avx512(&self) -> bool { let avx512_mask = (1 << 19) | (1 << 20) | (1 << 23) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 31) | (1 << 32) | (1 << 34) | (1 << 35) | (1 << 40) | (1 << 41) | (1 << 42) | (1 << 43); (self.flags & avx512_mask) == avx512_mask } /// enable all `avx512` features on this `InstDecoder`. no real CPU, at time of writing, /// actually has such a feature comination, but this is a useful overestimate for `avx512` /// generally. pub fn with_avx512(mut self) -> Self { let avx512_mask = (1 << 19) | (1 << 20) | (1 << 23) | (1 << 27) | (1 << 28) | (1 << 29) | (1 << 31) | (1 << 32) | (1 << 34) | (1 << 35) | (1 << 40) | (1 << 41) | (1 << 42) | (1 << 43); self.flags |= avx512_mask; self } pub fn cx8(&self) -> bool { self.flags & (1 << 44) != 0 } pub fn with_cx8(mut self) -> Self { self.flags |= 1 << 44; self } pub fn syscall(&self) -> bool { self.flags & (1 << 45) != 0 } pub fn with_syscall(mut self) -> Self { self.flags |= 1 << 45; self } pub fn rdtscp(&self) -> bool { self.flags & (1 << 46) != 0 } pub fn with_rdtscp(mut self) -> Self { self.flags |= 1 << 46; self } pub fn abm(&self) -> bool { self.flags & (1 << 47) != 0 } pub fn with_abm(mut self) -> Self { self.flags |= 1 << 47; self } pub fn sse4a(&self) -> bool { self.flags & (1 << 48) != 0 } pub fn with_sse4a(mut self) -> Self { self.flags |= 1 << 48; self } pub fn _3dnowprefetch(&self) -> bool { self.flags & (1 << 49) != 0 } pub fn with_3dnowprefetch(mut self) -> Self { self.flags |= 1 << 49; self } pub fn xop(&self) -> bool { self.flags & (1 << 50) != 0 } pub fn with_xop(mut self) -> Self { self.flags |= 1 << 50; self } pub fn skinit(&self) -> bool { self.flags & (1 << 51) != 0 } pub fn with_skinit(mut self) -> Self { self.flags |= 1 << 51; self } pub fn tbm(&self) -> bool { self.flags & (1 << 52) != 0 } pub fn with_tbm(mut self) -> Self { self.flags |= 1 << 52; self } pub fn intel_quirks(&self) -> bool { self.flags & (1 << 53) != 0 } pub fn with_intel_quirks(mut self) -> Self { self.flags |= 1 << 53; self } pub fn amd_quirks(&self) -> bool { self.flags & (1 << 54) != 0 } pub fn with_amd_quirks(mut self) -> Self { self.flags |= 1 << 54; self } pub fn avx(&self) -> bool { self.flags & (1 << 55) != 0 } pub fn with_avx(mut self) -> Self { self.flags |= 1 << 55; self } pub fn svm(&self) -> bool { self.flags & (1 << 56) != 0 } pub fn with_svm(mut self) -> Self { self.flags |= 1 << 56; self } /// `lahfsahf` is only unset for early revisions of 64-bit amd and intel chips. unfortunately /// the clearest documentation on when these instructions were reintroduced into 64-bit /// architectures seems to be /// [wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations): /// ```text /// Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD /// introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and /// Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the /// instructions with the Pentium 4 G1 stepping in December 2005. The 64-bit version of Windows /// 8.1 requires this feature.[47] /// ``` /// /// this puts reintroduction of these instructions somewhere in the middle of prescott and k8 /// lifecycles, for intel and amd respectively. because there is no specific uarch where these /// features become enabled, prescott and k8 default to not supporting these instructions, /// where later uarches support these instructions. pub fn lahfsahf(&self) -> bool { self.flags & (1 << 57) != 0 } pub fn with_lahfsahf(mut self) -> Self { self.flags |= 1 << 57; self } pub fn cmov(&self) -> bool { self.flags & (1 << 58) != 0 } pub fn with_cmov(mut self) -> Self { self.flags |= 1 << 58; self } pub fn f16c(&self) -> bool { self.flags & (1 << 59) != 0 } pub fn with_f16c(mut self) -> Self { self.flags |= 1 << 59; self } pub fn fma4(&self) -> bool { self.flags & (1 << 60) != 0 } pub fn with_fma4(mut self) -> Self { self.flags |= 1 << 60; self } pub fn prefetchw(&self) -> bool { self.flags & (1 << 61) != 0 } pub fn with_prefetchw(mut self) -> Self { self.flags |= 1 << 61; self } pub fn tsx(&self) -> bool { self.flags & (1 << 62) != 0 } pub fn with_tsx(mut self) -> Self { self.flags |= 1 << 62; self } pub fn lzcnt(&self) -> bool { self.flags & (1 << 63) != 0 } pub fn with_lzcnt(mut self) -> Self { self.flags |= 1 << 63; self } /// Optionally reject or reinterpret instruction according to the decoder's /// declared extensions. fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), DecodeError> { if inst.prefixes.evex().is_some() { if !self.avx512() { return Err(DecodeError::InvalidOpcode); } else { return Ok(()); } } match inst.opcode { Opcode::TZCNT => { if !self.bmi1() { // tzcnt is only supported if bmi1 is enabled. without bmi1, this decodes as // bsf. inst.opcode = Opcode::BSF; } } Opcode::LDDQU | Opcode::ADDSUBPS | Opcode::ADDSUBPD | Opcode::HADDPS | Opcode::HSUBPS | Opcode::HADDPD | Opcode::HSUBPD | Opcode::MOVSHDUP | Opcode::MOVSLDUP | Opcode::MOVDDUP | Opcode::MONITOR | Opcode::MWAIT => { // via Intel section 5.7, SSE3 Instructions if !self.sse3() { return Err(DecodeError::InvalidOpcode); } } Opcode::PHADDW | Opcode::PHADDSW | Opcode::PHADDD | Opcode::PHSUBW | Opcode::PHSUBSW | Opcode::PHSUBD | Opcode::PABSB | Opcode::PABSW | Opcode::PABSD | Opcode::PMADDUBSW | Opcode::PMULHRSW | Opcode::PSHUFB | Opcode::PSIGNB | Opcode::PSIGNW | Opcode::PSIGND | Opcode::PALIGNR => { // via Intel section 5.8, SSSE3 Instructions if !self.ssse3() { return Err(DecodeError::InvalidOpcode); } } Opcode::PMULLD | Opcode::PMULDQ | Opcode::MOVNTDQA | Opcode::BLENDPD | Opcode::BLENDPS | Opcode::BLENDVPD | Opcode::BLENDVPS | Opcode::PBLENDVB | Opcode::BLENDW | Opcode::PMINUW | Opcode::PMINUD | Opcode::PMINSB | Opcode::PMINSD | 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::PMOVSXBW | Opcode::PMOVZXBW | Opcode::PMOVSXBD | Opcode::PMOVZXBD | Opcode::PMOVSXWD | Opcode::PMOVZXWD | Opcode::PMOVSXBQ | Opcode::PMOVZXBQ | Opcode::PMOVSXWQ | 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() { return Err(DecodeError::InvalidOpcode); } } Opcode::EXTRQ | Opcode::INSERTQ | Opcode::MOVNTSS | Opcode::MOVNTSD => { if !self.sse4a() { return Err(DecodeError::InvalidOpcode); } } Opcode::CRC32 | Opcode::PCMPESTRI | Opcode::PCMPESTRM | Opcode::PCMPISTRI | Opcode::PCMPISTRM | Opcode::PCMPGTQ => { // via Intel section 5.11, SSE4.2 Instructions if !self.sse4_2() { return Err(DecodeError::InvalidOpcode); } } Opcode::AESDEC | Opcode::AESDECLAST | Opcode::AESENC | Opcode::AESENCLAST | Opcode::AESIMC | Opcode::AESKEYGENASSIST => { // via Intel section 5.12. AESNI AND PCLMULQDQ if !self.aesni() { return Err(DecodeError::InvalidOpcode); } } Opcode::PCLMULQDQ => { // via Intel section 5.12. AESNI AND PCLMULQDQ if !self.pclmulqdq() { return Err(DecodeError::InvalidOpcode); } } Opcode::XABORT | Opcode::XBEGIN | Opcode::XEND | Opcode::XTEST => { if !self.tsx() { return Err(DecodeError::InvalidOpcode); } } Opcode::SHA1MSG1 | Opcode::SHA1MSG2 | Opcode::SHA1NEXTE | Opcode::SHA1RNDS4 | Opcode::SHA256MSG1 | Opcode::SHA256MSG2 | Opcode::SHA256RNDS2 => { if !self.sha() { return Err(DecodeError::InvalidOpcode); } } Opcode::ENCLV | Opcode::ENCLS | Opcode::ENCLU => { if !self.sgx() { return Err(DecodeError::InvalidOpcode); } } // AVX... Opcode::VMOVDDUP | Opcode::VPSHUFLW | Opcode::VPSHUFHW | Opcode::VHADDPS | Opcode::VHSUBPS | Opcode::VADDSUBPS | Opcode::VCVTPD2DQ | Opcode::VLDDQU | Opcode::VCOMISD | Opcode::VCOMISS | Opcode::VUCOMISD | Opcode::VUCOMISS | Opcode::VADDPD | Opcode::VADDPS | Opcode::VADDSD | Opcode::VADDSS | Opcode::VADDSUBPD | Opcode::VBLENDPD | Opcode::VBLENDPS | Opcode::VBLENDVPD | Opcode::VBLENDVPS | Opcode::VBROADCASTF128 | Opcode::VBROADCASTI128 | Opcode::VBROADCASTSD | Opcode::VBROADCASTSS | Opcode::VCMPSD | Opcode::VCMPSS | Opcode::VCMPPD | Opcode::VCMPPS | Opcode::VCVTDQ2PD | Opcode::VCVTDQ2PS | Opcode::VCVTPD2PS | Opcode::VCVTPS2DQ | Opcode::VCVTPS2PD | Opcode::VCVTSS2SD | Opcode::VCVTSI2SS | Opcode::VCVTSI2SD | Opcode::VCVTSD2SI | Opcode::VCVTSD2SS | Opcode::VCVTSS2SI | Opcode::VCVTTPD2DQ | Opcode::VCVTTPS2DQ | Opcode::VCVTTSS2SI | Opcode::VCVTTSD2SI | Opcode::VDIVPD | Opcode::VDIVPS | Opcode::VDIVSD | Opcode::VDIVSS | Opcode::VDPPD | Opcode::VDPPS | Opcode::VEXTRACTF128 | Opcode::VEXTRACTI128 | Opcode::VEXTRACTPS | Opcode::VFMADD132PD | Opcode::VFMADD132PS | Opcode::VFMADD132SD | Opcode::VFMADD132SS | Opcode::VFMADD213PD | Opcode::VFMADD213PS | Opcode::VFMADD213SD | Opcode::VFMADD213SS | Opcode::VFMADD231PD | Opcode::VFMADD231PS | Opcode::VFMADD231SD | Opcode::VFMADD231SS | Opcode::VFMADDSUB132PD | Opcode::VFMADDSUB132PS | Opcode::VFMADDSUB213PD | Opcode::VFMADDSUB213PS | Opcode::VFMADDSUB231PD | Opcode::VFMADDSUB231PS | Opcode::VFMSUB132PD | Opcode::VFMSUB132PS | Opcode::VFMSUB132SD | Opcode::VFMSUB132SS | Opcode::VFMSUB213PD | Opcode::VFMSUB213PS | Opcode::VFMSUB213SD | Opcode::VFMSUB213SS | Opcode::VFMSUB231PD | Opcode::VFMSUB231PS | Opcode::VFMSUB231SD | Opcode::VFMSUB231SS | Opcode::VFMSUBADD132PD | Opcode::VFMSUBADD132PS | Opcode::VFMSUBADD213PD | Opcode::VFMSUBADD213PS | Opcode::VFMSUBADD231PD | Opcode::VFMSUBADD231PS | Opcode::VFNMADD132PD | Opcode::VFNMADD132PS | Opcode::VFNMADD132SD | Opcode::VFNMADD132SS | Opcode::VFNMADD213PD | Opcode::VFNMADD213PS | Opcode::VFNMADD213SD | Opcode::VFNMADD213SS | Opcode::VFNMADD231PD | Opcode::VFNMADD231PS | Opcode::VFNMADD231SD | Opcode::VFNMADD231SS | Opcode::VFNMSUB132PD | Opcode::VFNMSUB132PS | Opcode::VFNMSUB132SD | Opcode::VFNMSUB132SS | Opcode::VFNMSUB213PD | Opcode::VFNMSUB213PS | Opcode::VFNMSUB213SD | Opcode::VFNMSUB213SS | Opcode::VFNMSUB231PD | Opcode::VFNMSUB231PS | Opcode::VFNMSUB231SD | Opcode::VFNMSUB231SS | Opcode::VGATHERDPD | Opcode::VGATHERDPS | Opcode::VGATHERQPD | Opcode::VGATHERQPS | Opcode::VHADDPD | Opcode::VHSUBPD | Opcode::VINSERTF128 | Opcode::VINSERTI128 | Opcode::VINSERTPS | Opcode::VMASKMOVDQU | Opcode::VMASKMOVPD | Opcode::VMASKMOVPS | Opcode::VMAXPD | Opcode::VMAXPS | Opcode::VMAXSD | Opcode::VMAXSS | Opcode::VMINPD | Opcode::VMINPS | Opcode::VMINSD | Opcode::VMINSS | Opcode::VMOVAPD | Opcode::VMOVAPS | Opcode::VMOVD | Opcode::VMOVDQA | Opcode::VMOVDQU | Opcode::VMOVHLPS | Opcode::VMOVHPD | Opcode::VMOVHPS | Opcode::VMOVLHPS | Opcode::VMOVLPD | Opcode::VMOVLPS | Opcode::VMOVMSKPD | Opcode::VMOVMSKPS | Opcode::VMOVNTDQ | Opcode::VMOVNTDQA | Opcode::VMOVNTPD | Opcode::VMOVNTPS | Opcode::VMOVQ | Opcode::VMOVSS | Opcode::VMOVSD | Opcode::VMOVSHDUP | Opcode::VMOVSLDUP | Opcode::VMOVUPD | Opcode::VMOVUPS | Opcode::VMPSADBW | Opcode::VMULPD | Opcode::VMULPS | Opcode::VMULSD | Opcode::VMULSS | Opcode::VPABSB | Opcode::VPABSD | Opcode::VPABSW | Opcode::VPACKSSDW | Opcode::VPACKUSDW | Opcode::VPACKSSWB | Opcode::VPACKUSWB | Opcode::VPADDB | Opcode::VPADDD | Opcode::VPADDQ | Opcode::VPADDSB | Opcode::VPADDSW | Opcode::VPADDUSB | Opcode::VPADDUSW | Opcode::VPADDW | Opcode::VPALIGNR | Opcode::VPAND | Opcode::VANDPD | Opcode::VANDPS | Opcode::VANDNPD | Opcode::VANDNPS | Opcode::VORPD | Opcode::VORPS | Opcode::VPANDN | Opcode::VPAVGB | Opcode::VPAVGW | Opcode::VPBLENDD | Opcode::VPBLENDVB | Opcode::VPBLENDW | Opcode::VPBROADCASTB | Opcode::VPBROADCASTD | Opcode::VPBROADCASTQ | Opcode::VPBROADCASTW | Opcode::VPCLMULQDQ | Opcode::VPCMPEQB | Opcode::VPCMPEQD | Opcode::VPCMPEQQ | Opcode::VPCMPEQW | Opcode::VPCMPGTB | Opcode::VPCMPGTD | Opcode::VPCMPGTQ | Opcode::VPCMPGTW | Opcode::VPCMPESTRI | Opcode::VPCMPESTRM | Opcode::VPCMPISTRI | Opcode::VPCMPISTRM | Opcode::VPERM2F128 | Opcode::VPERM2I128 | Opcode::VPERMD | Opcode::VPERMILPD | Opcode::VPERMILPS | Opcode::VPERMPD | Opcode::VPERMPS | Opcode::VPERMQ | Opcode::VPEXTRB | Opcode::VPEXTRD | Opcode::VPEXTRQ | Opcode::VPEXTRW | Opcode::VPGATHERDD | Opcode::VPGATHERDQ | Opcode::VPGATHERQD | Opcode::VPGATHERQQ | Opcode::VPHADDD | Opcode::VPHADDSW | Opcode::VPHADDW | Opcode::VPMADDUBSW | Opcode::VPHMINPOSUW | Opcode::VPHSUBD | Opcode::VPHSUBSW | Opcode::VPHSUBW | Opcode::VPINSRB | Opcode::VPINSRD | Opcode::VPINSRQ | Opcode::VPINSRW | Opcode::VPMADDWD | Opcode::VPMASKMOVD | Opcode::VPMASKMOVQ | Opcode::VPMAXSB | Opcode::VPMAXSD | Opcode::VPMAXSW | Opcode::VPMAXUB | Opcode::VPMAXUW | Opcode::VPMAXUD | Opcode::VPMINSB | Opcode::VPMINSW | Opcode::VPMINSD | Opcode::VPMINUB | Opcode::VPMINUW | Opcode::VPMINUD | Opcode::VPMOVMSKB | Opcode::VPMOVSXBD | Opcode::VPMOVSXBQ | Opcode::VPMOVSXBW | Opcode::VPMOVSXDQ | Opcode::VPMOVSXWD | Opcode::VPMOVSXWQ | Opcode::VPMOVZXBD | Opcode::VPMOVZXBQ | Opcode::VPMOVZXBW | Opcode::VPMOVZXDQ | Opcode::VPMOVZXWD | Opcode::VPMOVZXWQ | Opcode::VPMULDQ | Opcode::VPMULHRSW | Opcode::VPMULHUW | Opcode::VPMULHW | Opcode::VPMULLQ | Opcode::VPMULLD | Opcode::VPMULLW | Opcode::VPMULUDQ | Opcode::VPOR | Opcode::VPSADBW | Opcode::VPSHUFB | Opcode::VPSHUFD | Opcode::VPSIGNB | Opcode::VPSIGND | Opcode::VPSIGNW | Opcode::VPSLLD | Opcode::VPSLLDQ | Opcode::VPSLLQ | Opcode::VPSLLVD | Opcode::VPSLLVQ | Opcode::VPSLLW | Opcode::VPSRAD | Opcode::VPSRAVD | Opcode::VPSRAW | Opcode::VPSRLD | Opcode::VPSRLDQ | Opcode::VPSRLQ | Opcode::VPSRLVD | Opcode::VPSRLVQ | Opcode::VPSRLW | Opcode::VPSUBB | Opcode::VPSUBD | Opcode::VPSUBQ | Opcode::VPSUBSB | Opcode::VPSUBSW | Opcode::VPSUBUSB | Opcode::VPSUBUSW | Opcode::VPSUBW | Opcode::VPTEST | Opcode::VPUNPCKHBW | Opcode::VPUNPCKHDQ | Opcode::VPUNPCKHQDQ | Opcode::VPUNPCKHWD | Opcode::VPUNPCKLBW | Opcode::VPUNPCKLDQ | Opcode::VPUNPCKLQDQ | Opcode::VPUNPCKLWD | Opcode::VPXOR | Opcode::VRCPPS | Opcode::VROUNDPD | Opcode::VROUNDPS | Opcode::VROUNDSD | Opcode::VROUNDSS | Opcode::VRSQRTPS | Opcode::VRSQRTSS | Opcode::VRCPSS | Opcode::VSHUFPD | Opcode::VSHUFPS | Opcode::VSQRTPD | Opcode::VSQRTPS | Opcode::VSQRTSS | Opcode::VSQRTSD | Opcode::VSUBPD | Opcode::VSUBPS | Opcode::VSUBSD | Opcode::VSUBSS | Opcode::VTESTPD | Opcode::VTESTPS | Opcode::VUNPCKHPD | Opcode::VUNPCKHPS | Opcode::VUNPCKLPD | Opcode::VUNPCKLPS | Opcode::VXORPD | Opcode::VXORPS | Opcode::VZEROUPPER | Opcode::VZEROALL | Opcode::VLDMXCSR | Opcode::VSTMXCSR => { // TODO: check a table for these if !self.avx() { return Err(DecodeError::InvalidOpcode); } } Opcode::VAESDEC | Opcode::VAESDECLAST | Opcode::VAESENC | Opcode::VAESENCLAST | Opcode::VAESIMC | Opcode::VAESKEYGENASSIST => { // TODO: check a table for these if !self.avx() || !self.aesni() { return Err(DecodeError::InvalidOpcode); } } Opcode::MOVBE => { if !self.movbe() { return Err(DecodeError::InvalidOpcode); } } Opcode::POPCNT => { /* * from the intel SDM: * ``` * Before an application attempts to use the POPCNT instruction, it must check that * the processor supports SSE4.2 (if CPUID.01H:ECX.SSE4_2[bit 20] = 1) and POPCNT * (if CPUID.01H:ECX.POPCNT[bit 23] = 1). * ``` */ if self.intel_quirks() && (self.sse4_2() || self.popcnt()) { return Ok(()); } else if !self.popcnt() { /* * elsewhere from the amd APM: * `Instruction Subsets and CPUID Feature Flags` on page 507 indicates that * popcnt is present when the popcnt bit is reported by cpuid. this seems to be * the less quirky default, so `intel_quirks` is considered the outlier, and * before this default. * */ return Err(DecodeError::InvalidOpcode); } } Opcode::LZCNT => { /* * amd APM, `LZCNT` page 212: * LZCNT is an Advanced Bit Manipulation (ABM) instruction. Support for the LZCNT * instruction is indicated by CPUID Fn8000_0001_ECX[ABM] = 1. * * meanwhile the intel SDM simply states: * ``` * CPUID.EAX=80000001H:ECX.LZCNT[bit 5]: if 1 indicates the processor supports the * LZCNT instruction. * ``` * * so that's considered the less-quirky (default) case here. * */ if self.amd_quirks() && !self.abm() { return Err(DecodeError::InvalidOpcode); } else if !self.lzcnt() { return Err(DecodeError::InvalidOpcode); } } Opcode::ADCX | Opcode::ADOX => { if !self.adx() { return Err(DecodeError::InvalidOpcode); } } Opcode::VMRUN | Opcode::VMLOAD | Opcode::VMSAVE | Opcode::CLGI | Opcode::VMMCALL | Opcode::INVLPGA => { if !self.svm() { return Err(DecodeError::InvalidOpcode); } } Opcode::STGI | Opcode::SKINIT => { if !self.svm() || !self.skinit() { return Err(DecodeError::InvalidOpcode); } } Opcode::LAHF | Opcode::SAHF => { if !self.lahfsahf() { return Err(DecodeError::InvalidOpcode); } } Opcode::VCVTPS2PH | Opcode::VCVTPH2PS => { /* * from intel SDM: * ``` * 14.4.1 Detection of F16C Instructions Application using float 16 instruction * must follow a detection sequence similar to AVX to ensure: • The OS has * enabled YMM state management support, • The processor support AVX as * indicated by the CPUID feature flag, i.e. CPUID.01H:ECX.AVX[bit 28] = 1. • * The processor support 16-bit floating-point conversion instructions via a * CPUID feature flag (CPUID.01H:ECX.F16C[bit 29] = 1). * ``` * * TODO: only the VEX-coded variant of this instruction should be gated on `f16c`. * the EVEX-coded variant should be gated on `avx512f` or `avx512vl` if not * EVEX.512-coded. */ if !self.avx() || !self.f16c() { return Err(DecodeError::InvalidOpcode); } } Opcode::RDRAND => { if !self.rdrand() { return Err(DecodeError::InvalidOpcode); } } Opcode::RDSEED => { if !self.rdseed() { return Err(DecodeError::InvalidOpcode); } } Opcode::MONITORX | Opcode::MWAITX | // these are gated on the `monitorx` and `mwaitx` cpuid bits, but are AMD-only. Opcode::CLZERO | Opcode::RDPRU => { // again, gated on specific cpuid bits, but AMD-only. if !self.amd_quirks() { return Err(DecodeError::InvalidOpcode); } } other => { if !self.bmi1() { if BMI1.contains(&other) { return Err(DecodeError::InvalidOpcode); } } if !self.bmi2() { if BMI2.contains(&other) { return Err(DecodeError::InvalidOpcode); } } } } Ok(()) } } impl Default for InstDecoder { /// Instantiates an x86 decoder that probably decodes what you want. /// /// Attempts to match real processors in interpretation of undefined sequences, and decodes any /// instruction defined in any extension. fn default() -> Self { Self { flags: 0xffffffff_ffffffff, } } } impl Decoder for InstDecoder { fn decode::Address, ::Word>>(&self, words: &mut T) -> Result::DecodeError> { let mut instr = Instruction::invalid(); read_instr(self, words, &mut instr)?; instr.length = words.offset() as u8; if words.offset() > 15 { return Err(DecodeError::TooLong); } if self != &InstDecoder::default() { self.revise_instruction(&mut instr)?; } Ok(instr) } fn decode_into::Address, ::Word>>(&self, instr: &mut Instruction, words: &mut T) -> Result<(), ::DecodeError> { read_instr(self, words, instr)?; instr.length = words.offset() as u8; if words.offset() > 15 { return Err(DecodeError::TooLong); } if self != &InstDecoder::default() { self.revise_instruction(instr)?; } Ok(()) } } impl Opcode { /// get the [`ConditionCode`] for this instruction, if it is in fact conditional. x86's /// conditional instructions are `Jcc`, `CMOVcc`, andd `SETcc`. pub fn condition(&self) -> Option { match self { Opcode::JO | Opcode::CMOVO | Opcode::SETO => { Some(ConditionCode::O) }, Opcode::JNO | Opcode::CMOVNO | Opcode::SETNO => { Some(ConditionCode::NO) }, Opcode::JB | Opcode::CMOVB | Opcode::SETB => { Some(ConditionCode::B) }, Opcode::JNB | Opcode::CMOVNB | Opcode::SETAE => { Some(ConditionCode::AE) }, Opcode::JZ | Opcode::CMOVZ | Opcode::SETZ => { Some(ConditionCode::Z) }, Opcode::JNZ | Opcode::CMOVNZ | Opcode::SETNZ => { Some(ConditionCode::NZ) }, Opcode::JA | Opcode::CMOVA | Opcode::SETA => { Some(ConditionCode::A) }, Opcode::JNA | Opcode::CMOVNA | Opcode::SETBE => { Some(ConditionCode::BE) }, Opcode::JS | Opcode::CMOVS | Opcode::SETS => { Some(ConditionCode::S) }, Opcode::JNS | Opcode::CMOVNS | Opcode::SETNS => { Some(ConditionCode::NS) }, Opcode::JP | Opcode::CMOVP | Opcode::SETP => { Some(ConditionCode::P) }, Opcode::JNP | Opcode::CMOVNP | Opcode::SETNP => { Some(ConditionCode::NP) }, Opcode::JL | Opcode::CMOVL | Opcode::SETL => { Some(ConditionCode::L) }, Opcode::JGE | Opcode::CMOVGE | Opcode::SETGE => { Some(ConditionCode::GE) }, Opcode::JG | Opcode::CMOVG | Opcode::SETG => { Some(ConditionCode::G) }, Opcode::JLE | Opcode::CMOVLE | Opcode::SETLE => { Some(ConditionCode::LE) }, _ => None, } } } impl Default for Instruction { fn default() -> Self { Instruction::invalid() } } impl Instruction { /// get the `Opcode` of this instruction. pub fn opcode(&self) -> Opcode { self.opcode } /// get the `Operand` at the provided index. /// /// panics if the index is `>= 4`. pub fn operand(&self, i: u8) -> Operand { assert!(i < 4); Operand::from_spec(self, self.operands[i as usize]) } /// get the number of operands in this instruction. useful in iterating an instruction's /// operands generically. pub fn operand_count(&self) -> u8 { self.operand_count } /// check if operand `i` is an actual operand or not. will be `false` for `i >= /// inst.operand_count()`. pub fn operand_present(&self, i: u8) -> bool { assert!(i < 4); if i >= self.operand_count { return false; } if let OperandSpec::Nothing = self.operands[i as usize] { false } else { true } } /// get the memory access information for this instruction, if it accesses memory. /// /// the corresponding `MemoryAccessSize` may report that the size of accessed memory is /// indeterminate; this is the case for `xsave/xrestor`-style instructions whose operation size /// varies based on physical processor. pub fn mem_size(&self) -> Option { if self.mem_size != 0 { Some(MemoryAccessSize { size: self.mem_size }) } else { None } } /// build a new instruction representing nothing in particular. this is primarily useful as a /// default to pass to `decode_into`. pub fn invalid() -> Instruction { Instruction { prefixes: Prefixes::new(0), opcode: Opcode::NOP, mem_size: 0, regs: [RegSpec::eax(); 4], scale: 0, length: 0, disp: 0, imm: 0, operand_count: 0, operands: [OperandSpec::Nothing; 4], } } /// get the `Segment` that will *actually* be used for accessing the operand at index `i`. /// /// `stos`, `lods`, `movs`, and `cmps` specifically name some segments for use regardless of /// prefixes. pub fn segment_override_for_op(&self, op: u8) -> Option { match self.opcode { Opcode::STOS | Opcode::SCAS => { if op == 0 { Some(Segment::ES) } else { None } } Opcode::LODS => { if op == 1 { Some(self.prefixes.segment) } else { None } } Opcode::MOVS => { if op == 0 { Some(Segment::ES) } else if op == 1 { Some(self.prefixes.segment) } else { None } } Opcode::CMPS => { if op == 0 { Some(self.prefixes.segment) } else if op == 1 { Some(Segment::ES) } else { None } }, _ => { // most operands are pretty simple: if self.operands[op as usize].is_memory() && self.prefixes.segment != Segment::DS { Some(self.prefixes.segment) } else { None } } } } #[cfg(feature = "fmt")] /// wrap a reference to this instruction with a `DisplayStyle` to format the instruction with /// later. see the documentation on [`display::DisplayStyle`] for more. /// /// ``` /// use yaxpeax_x86::long_mode::{InstDecoder, DisplayStyle}; /// /// let decoder = InstDecoder::default(); /// let inst = decoder.decode_slice(&[0x33, 0xc1]).unwrap(); /// /// assert_eq!("eax ^= ecx", inst.display_with(DisplayStyle::C).to_string()); /// assert_eq!("xor eax, ecx", inst.display_with(DisplayStyle::Intel).to_string()); /// ``` pub fn display_with<'a>(&'a self, style: display::DisplayStyle) -> display::InstructionDisplayer<'a> { display::InstructionDisplayer { style, instr: self, } } /// does this instruction include the `xacquire` hint for hardware lock elision? pub fn xacquire(&self) -> bool { if self.prefixes.repnz() { // xacquire is permitted on typical `lock` instructions, OR `xchg` with memory operand, // regardless of `lock` prefix. if self.prefixes.lock() { true } else if self.opcode == Opcode::XCHG { self.operands[0] != OperandSpec::RegMMM && self.operands[1] != OperandSpec::RegMMM } else { false } } else { false } } /// does this instruction include the `xrelease` hint for hardware lock elision? pub fn xrelease(&self) -> bool { if self.prefixes.rep() { // xrelease is permitted on typical `lock` instructions, OR `xchg` with memory operand, // regardless of `lock` prefix. additionally, xrelease is permitted on some forms of mov. if self.prefixes.lock() { true } else if self.opcode == Opcode::XCHG { self.operands[0] != OperandSpec::RegMMM && self.operands[1] != OperandSpec::RegMMM } else if self.opcode == Opcode::MOV { self.operands[0] != OperandSpec::RegMMM && ( self.operands[1] == OperandSpec::RegRRR || self.operands[1] == OperandSpec::ImmI8 || self.operands[1] == OperandSpec::ImmI16 || self.operands[1] == OperandSpec::ImmI32 ) } else { false } } else { false } } } #[derive(Debug, Copy, Clone, Eq, PartialEq)] struct EvexData { // data: present, z, b, Lp, Rp. aaa bits: u8, } /// the prefixes on an instruction. /// /// `rep`, `repnz`, `lock`, and segment override prefixes are directly accessible here. `vex` and /// `evex` prefixes are available through their associated helpers. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Prefixes { bits: u8, vex: PrefixVex, segment: Segment, evex_data: EvexData, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PrefixEvex { vex: PrefixVex, evex_data: EvexData, } impl PrefixEvex { fn present(&self) -> bool { self.evex_data.present() } /// the `evex` prefix's parts that overlap with `vex` definitions - `L`, `W`, `R`, `X`, and `B` /// bits. pub fn vex(&self) -> &PrefixVex { &self.vex } /// the `avx512` mask register in use. `0` indicates "no mask register". pub fn mask_reg(&self) -> u8 { self.evex_data.aaa() } pub fn broadcast(&self) -> bool { self.evex_data.b() } pub fn merge(&self) -> bool { self.evex_data.z() } /// the `evex` `L'` bit. pub fn lp(&self) -> bool { self.evex_data.lp() } /// the `evex` `R'` bit. pub fn rp(&self) -> bool { self.evex_data.rp() } } /// bits specified in an avx/avx2 [`vex`](https://en.wikipedia.org/wiki/VEX_prefix) prefix, `L`, `W`, `R`, `X`, and `B`. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PrefixVex { bits: u8, } #[allow(dead_code)] impl PrefixVex { #[inline] pub fn b(&self) -> bool { (self.bits & 0x01) == 0x01 } #[inline] pub fn x(&self) -> bool { (self.bits & 0x02) == 0x02 } #[inline] pub fn r(&self) -> bool { (self.bits & 0x04) == 0x04 } #[inline] pub fn w(&self) -> bool { (self.bits & 0x08) == 0x08 } #[inline] pub fn l(&self) -> bool { (self.bits & 0x10) == 0x10 } #[inline] fn present(&self) -> bool { (self.bits & 0x80) == 0x80 } #[inline] fn compressed_disp(&self) -> bool { (self.bits & 0x20) == 0x20 } } #[allow(dead_code)] impl Prefixes { fn new(bits: u8) -> Prefixes { Prefixes { bits: bits, vex: PrefixVex { bits: 0 }, segment: Segment::DS, evex_data: EvexData { bits: 0 }, } } fn vex_from(&mut self, bits: u8) { self.vex = PrefixVex { bits }; } #[inline] pub fn rep(&self) -> bool { self.bits & 0x30 == 0x10 } #[inline] fn set_rep(&mut self) { self.bits = (self.bits & 0xcf) | 0x10 } #[inline] pub fn repnz(&self) -> bool { self.bits & 0x30 == 0x30 } #[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 } #[inline] fn unset_operand_size(&mut self) { self.bits = self.bits & !0x1 } #[inline] fn address_size(&self) -> bool { self.bits & 0x2 == 2 } #[inline] fn set_address_size(&mut self) { self.bits = self.bits | 0x2 } #[inline] fn set_lock(&mut self) { self.bits |= 0x4 } #[inline] pub fn lock(&self) -> bool { self.bits & 0x4 == 4 } #[inline] pub fn cs(&mut self) { self.segment = Segment::CS } #[inline] fn set_cs(&mut self) { self.segment = Segment::CS } #[inline] pub fn ds(&self) -> bool { self.segment == Segment::DS } #[inline] fn set_ds(&mut self) { self.segment = Segment::DS } #[inline] pub fn es(&self) -> bool { self.segment == Segment::ES } #[inline] fn set_es(&mut self) { self.segment = Segment::ES } #[inline] pub fn fs(&self) -> bool { self.segment == Segment::FS } #[inline] fn set_fs(&mut self) { self.segment = Segment::FS } #[inline] pub fn gs(&self) -> bool { self.segment == Segment::GS } #[inline] fn set_gs(&mut self) { self.segment = Segment::GS } #[inline] pub fn ss(&self) -> bool { self.segment == Segment::SS } #[inline] fn set_ss(&mut self) { self.segment = Segment::SS } #[inline] fn vex_unchecked(&self) -> PrefixVex { PrefixVex { bits: self.vex.bits } } #[inline] pub fn vex(&self) -> Option { let vex = self.vex_unchecked(); if vex.present() { Some(vex) } else { None } } #[inline] fn evex_unchecked(&self) -> PrefixEvex { PrefixEvex { vex: PrefixVex { bits: self.vex.bits }, evex_data: self.evex_data } } #[inline] pub fn evex(&self) -> Option { let evex = self.evex_unchecked(); if evex.present() { Some(evex) } else { None } } #[inline] fn apply_compressed_disp(&mut self, state: bool) { if state { self.vex.bits |= 0x20; } else { self.vex.bits &= 0xdf; } } #[inline] fn vex_from_c5(&mut self, bits: u8) { // collect rex bits let r = bits & 0x80; let wrxb = (r >> 5) ^ 0x04; let l = (bits & 0x04) << 2; let synthetic_rex = wrxb | l | 0x80; self.vex = PrefixVex { bits: synthetic_rex }; } #[inline] fn vex_from_c4(&mut self, high: u8, low: u8) { let w = low & 0x80; let rxb = (high >> 5) ^ 0x07; let wrxb = rxb | w >> 4; let l = (low & 0x04) << 2; let synthetic_vex = wrxb | l | 0x80; self.vex = PrefixVex { bits: synthetic_vex }; } #[inline] fn evex_from(&mut self, b1: u8, b2: u8, b3: u8) { let w = b2 & 0x80; let rxb = ((b1 >> 5) & 0b111) ^ 0b111; // `rxb` is provided in inverted form let wrxb = rxb | (w >> 4); let l = (b3 & 0x20) >> 1; let synthetic_vex = wrxb | l | 0x80; self.vex_from(synthetic_vex); // R' is provided in inverted form let rp = ((b1 & 0x10) >> 4) ^ 1; let lp = (b3 & 0x40) >> 6; let aaa = b3 & 0b111; let z = (b3 & 0x80) >> 7; let b = (b3 & 0x10) >> 4; self.evex_data.from(rp, lp, z, b, aaa); } } impl EvexData { fn from(&mut self, rp: u8, lp: u8, z: u8, b: u8, aaa: u8) { let mut bits = 0; bits |= aaa; bits |= b << 3; bits |= z << 4; bits |= lp << 5; bits |= rp << 6; bits |= 0x80; self.bits = bits; } } impl EvexData { pub(crate) fn present(&self) -> bool { self.bits & 0b1000_0000 != 0 } pub(crate) fn aaa(&self) -> u8 { self.bits & 0b111 } pub(crate) fn b(&self) -> bool { (self.bits & 0b0000_1000) != 0 } pub(crate) fn z(&self) -> bool { (self.bits & 0b0001_0000) != 0 } pub(crate) fn lp(&self) -> bool { (self.bits & 0b0010_0000) != 0 } pub(crate) fn rp(&self) -> bool { (self.bits & 0b0100_0000) != 0 } } #[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)] enum OperandCode { 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_0x0f0f = OperandCodeBuilder::new().read_modrm().special_case(65).bits(), // 3dnow ModRM_0x0fae = OperandCodeBuilder::new().read_modrm().special_case(43).bits(), ModRM_0x0fba = OperandCodeBuilder::new().read_modrm().special_case(44).bits(), // ModRM_0xf30fae = OperandCodeBuilder::new().read_modrm().special_case(46).bits(), // 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_0xf30f38d8 = OperandCodeBuilder::new().read_modrm().special_case(45).bits(), ModRM_0xf30f38dc = OperandCodeBuilder::new().read_modrm().special_case(46).bits(), ModRM_0xf30f38dd = OperandCodeBuilder::new().read_modrm().special_case(47).bits(), ModRM_0xf30f38de = OperandCodeBuilder::new().read_modrm().special_case(48).bits(), ModRM_0xf30f38df = OperandCodeBuilder::new().read_modrm().special_case(49).bits(), ModRM_0xf30f38fa = OperandCodeBuilder::new().read_modrm().special_case(50).bits(), ModRM_0xf30f38fb = OperandCodeBuilder::new().read_modrm().special_case(51).bits(), ModRM_0xf30f3af0 = OperandCodeBuilder::new().read_modrm().special_case(52).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_0xf20f78 = OperandCodeBuilder::new().read_modrm().special_case(58).bits(), ModRM_0x660f78 = OperandCodeBuilder::new().read_modrm().special_case(59).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(66).bits(), ModRM_0xc5 = OperandCodeBuilder::new().read_modrm().special_case(67).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 = 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 = 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_Ed = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().operand_case(51).bits(), Md_Gd = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().operand_case(52).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_xmm_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(22).bits(), G_E_xmm_Ub = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(60).bits(), G_U_xmm_Ub = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(61).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(), MOVDIR64B = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(108).bits(), M_Gv = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(109).bits(), Gv_Ev_Ib = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().with_imm(false, 0).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 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_Ed, but also read an immediate G_xmm_Ew_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(), G_Ed_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().reg_mem().operand_case(31).bits(), Ed_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(29).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(), Ed_G_mm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(67).bits(), // Ed_G_xmm = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().read_E().mem_reg().operand_case(68).bits(), G_mm_Ed = 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_Mq_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_q = OperandCodeBuilder::new().op0_is_rrr_and_embedded_instructions().operand_case(76).bits(), E_G_q = 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(), ES = OperandCodeBuilder::new().special_case(103).bits(), CS = OperandCodeBuilder::new().special_case(104).bits(), SS = OperandCodeBuilder::new().special_case(105).bits(), DS = OperandCodeBuilder::new().special_case(106).bits(), ModRM_0x62 = OperandCodeBuilder::new().special_case(107).bits(), INV_Gv_M = OperandCodeBuilder::new().special_case(108).bits(), PMOVX_G_E_xmm = OperandCodeBuilder::new().operand_case(109).bits(), PMOVX_E_G_xmm = OperandCodeBuilder::new().operand_case(110).bits(), G_Ev_xmm_Ib = OperandCodeBuilder::new().operand_case(111).bits(), G_E_mm_Ib = OperandCodeBuilder::new().operand_case(112).bits(), } const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ Opcode::ADD, Opcode::ADC, Opcode::AND, Opcode::BTC, Opcode::BTR, Opcode::BTS, Opcode::CMPXCHG, Opcode::CMPXCHG8B, Opcode::DEC, Opcode::INC, Opcode::NEG, Opcode::NOT, Opcode::OR, Opcode::SBB, Opcode::SUB, Opcode::XOR, Opcode::XADD, Opcode::XCHG, ]; fn base_opcode_map(v: u8) -> Opcode { match v { 0 => Opcode::ADD, 1 => Opcode::OR, 2 => Opcode::ADC, 3 => Opcode::SBB, 4 => Opcode::AND, 5 => Opcode::SUB, 6 => Opcode::XOR, 7 => Opcode::CMP, _ => { unsafe { unreachable_unchecked() } } } } const BITWISE_OPCODE_MAP: [Opcode; 8] = [ Opcode::ROL, Opcode::ROR, Opcode::RCL, Opcode::RCR, Opcode::SHL, Opcode::SHR, Opcode::SAL, Opcode::SAR ]; #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Interpretation { Instruction(Opcode), Prefix, } #[derive(Copy, Clone, Debug, PartialEq)] // this should be a 32-byte struct.. struct OpcodeRecord(Interpretation, OperandCode); #[test] fn opcode_record_size() { // there are more than 256 opcodes... assert_eq!(core::mem::size_of::(), 4); } const OPCODES: [OpcodeRecord; 256] = [ OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::ADD), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::ES), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::ES), OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::OR), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::CS), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::ADC), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::SS), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::SS), OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::SBB), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::DS), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::DS), OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::AND), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::DAA), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::SUB), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::DAS), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::XOR), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::AAA), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::CMP), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::AAS), OperandCode::Nothing), // 0x40: OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R0), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R1), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R2), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R3), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R4), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R5), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R6), OpcodeRecord(Interpretation::Instruction(Opcode::INC), OperandCode::Zv_R7), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R0), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R1), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R2), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R3), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R4), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R5), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R6), OpcodeRecord(Interpretation::Instruction(Opcode::DEC), OperandCode::Zv_R7), // 0x50: OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R0), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R1), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R2), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R3), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R4), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R5), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R6), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Zv_R7), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R0), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R1), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R2), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R3), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R4), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R5), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R6), OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::Zv_R7), // 0x60 OpcodeRecord(Interpretation::Instruction(Opcode::PUSHA), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::POPA), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::BOUND), OperandCode::ModRM_0x62), OpcodeRecord(Interpretation::Instruction(Opcode::ARPL), OperandCode::Ew_Gw), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ivs), OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Iv), OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::INS), OperandCode::Yb_DX), OpcodeRecord(Interpretation::Instruction(Opcode::INS), OperandCode::Yv_DX), OpcodeRecord(Interpretation::Instruction(Opcode::OUTS), OperandCode::DX_Xb), OpcodeRecord(Interpretation::Instruction(Opcode::OUTS), OperandCode::DX_Xv), // 0x70 OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Ibs), // 0x80 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x80_Eb_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x81_Ev_Ivs), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x83_Ev_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Eb_Gb), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ev_Gv), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gb_Eb), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Gv_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ew_Sw), OpcodeRecord(Interpretation::Instruction(Opcode::LEA), OperandCode::Gv_M), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Sw_Ew), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x8f_Ev), OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R1), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R2), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R3), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R4), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R5), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R6), OpcodeRecord(Interpretation::Instruction(Opcode::XCHG), OperandCode::Zv_AX_R7), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_AA), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::CVT_DA), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::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), OpcodeRecord(Interpretation::Instruction(Opcode::LAHF), OperandCode::AH), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::AL_Ob), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::AX_Ov), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ob_AL), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Ov_AX), OpcodeRecord(Interpretation::Instruction(Opcode::MOVS), OperandCode::Yb_Xb), OpcodeRecord(Interpretation::Instruction(Opcode::MOVS), OperandCode::Yv_Xv), OpcodeRecord(Interpretation::Instruction(Opcode::CMPS), OperandCode::Yb_Xb), OpcodeRecord(Interpretation::Instruction(Opcode::CMPS), OperandCode::Yv_Xv), OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::AL_Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::TEST), OperandCode::AX_Ivd), OpcodeRecord(Interpretation::Instruction(Opcode::STOS), OperandCode::Yb_AL), OpcodeRecord(Interpretation::Instruction(Opcode::STOS), OperandCode::Yv_AX), OpcodeRecord(Interpretation::Instruction(Opcode::LODS), OperandCode::AL_Xb), OpcodeRecord(Interpretation::Instruction(Opcode::LODS), OperandCode::AX_Xv), OpcodeRecord(Interpretation::Instruction(Opcode::SCAS), OperandCode::Yb_AL), OpcodeRecord(Interpretation::Instruction(Opcode::SCAS), OperandCode::Yv_AX), // 0xb0 OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R0), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R1), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R2), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R3), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R4), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R5), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R6), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zb_Ib_R7), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R0), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R1), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R2), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R3), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R4), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R5), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R6), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Zv_Iv_R7), // 0xc0 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xc0_Eb_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xc1_Ev_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::RETURN), OperandCode::Iw), OpcodeRecord(Interpretation::Instruction(Opcode::RETURN), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::LES), OperandCode::ModRM_0xc4), OpcodeRecord(Interpretation::Instruction(Opcode::LDS), OperandCode::ModRM_0xc5), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::ModRM_0xc6_Eb_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::ModRM_0xc7_Ev_Iv), OpcodeRecord(Interpretation::Instruction(Opcode::ENTER), OperandCode::Iw_Ib), OpcodeRecord(Interpretation::Instruction(Opcode::LEAVE), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Iw), OpcodeRecord(Interpretation::Instruction(Opcode::RETF), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::I_3), OpcodeRecord(Interpretation::Instruction(Opcode::INT), OperandCode::Ib), OpcodeRecord(Interpretation::Instruction(Opcode::INTO), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::IRET), OperandCode::Fw), // 0xd0 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd0_Eb_1), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd1_Ev_1), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd2_Eb_CL), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xd3_Ev_CL), OpcodeRecord(Interpretation::Instruction(Opcode::AAM), OperandCode::Ib), OpcodeRecord(Interpretation::Instruction(Opcode::AAD), OperandCode::Ib), OpcodeRecord(Interpretation::Instruction(Opcode::SALC), OperandCode::Nothing), // XLAT OpcodeRecord(Interpretation::Instruction(Opcode::XLAT), OperandCode::Nothing), // x86 d8 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d8), // x86 d9 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_d9), // x86 da OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_da), // x86 db OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_db), // x86 dc OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dc), // x86 dd OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_dd), // x86 de OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_de), // x86 df OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::x87_df), // 0xe0 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::JECXZ), 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), OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::Ib_AX), // 0xe8 OpcodeRecord(Interpretation::Instruction(Opcode::CALL), OperandCode::Jvds), OpcodeRecord(Interpretation::Instruction(Opcode::JMP), OperandCode::Jvds), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::JMP), OperandCode::Ibs), OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AL_DX), OpcodeRecord(Interpretation::Instruction(Opcode::IN), OperandCode::AX_DX), OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::DX_AL), OpcodeRecord(Interpretation::Instruction(Opcode::OUT), OperandCode::DX_AX), // 0xf0 OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), // ICEBP? OpcodeRecord(Interpretation::Instruction(Opcode::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::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), OpcodeRecord(Interpretation::Instruction(Opcode::STC), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::CLI), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::STI), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::CLD), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::STD), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xfe_Eb), // TODO: test 0xff /3 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xff_Ev), ]; #[allow(non_snake_case)] pub(self) fn read_E::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8, width: u8) -> Result { let bank = width_to_gp_reg_bank(width); if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, bank) } else { read_M(words, instr, modrm) } } #[allow(non_snake_case)] pub(self) fn read_E_mm::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, RegisterBank::MM) } else { read_M(words, instr, modrm) } } #[allow(non_snake_case)] pub(self) fn read_E_st::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, RegisterBank::ST) } else { read_M(words, instr, modrm) } } #[allow(non_snake_case)] pub(self) fn read_E_xmm::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, RegisterBank::X) } else { read_M(words, instr, modrm) } } #[allow(non_snake_case)] pub(self) fn read_E_ymm::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, RegisterBank::Y) } else { read_M(words, instr, modrm) } } #[allow(non_snake_case)] pub(self) fn read_E_vex::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8, bank: RegisterBank) -> Result { if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, bank) } else { let res = read_M(words, instr, modrm)?; if (modrm & 0b01_000_000) == 0b01_000_000 { instr.prefixes.apply_compressed_disp(true); } Ok(res) } } #[allow(non_snake_case)] fn read_modrm_reg(instr: &mut Instruction, modrm: u8, reg_bank: RegisterBank) -> Result { instr.regs[1] = RegSpec::from_parts(modrm & 7, reg_bank); Ok(OperandSpec::RegMMM) } #[allow(non_snake_case)] fn read_sib::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { let modbits = modrm >> 6; let sibbyte = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; instr.regs[1].num |= sibbyte & 7; instr.regs[2].num |= (sibbyte >> 3) & 7; let disp = if modbits == 0b00 { if (sibbyte & 7) == 0b101 { read_num(words, 4)? as i32 } else { 0 } } else if modbits == 0b01 { read_num(words, 1)? as i8 as i32 } else { read_num(words, 4)? as i32 }; instr.disp = disp as u32; let scale = 1u8 << (sibbyte >> 6); instr.scale = scale; let op_spec = if (sibbyte & 7) == 0b101 { if ((sibbyte >> 3) & 7) == 0b100 { if modbits == 0b00 { OperandSpec::DispU32 } else { instr.regs[1].num |= 0b101; if disp == 0 { OperandSpec::Deref } else { OperandSpec::RegDisp } } } else { instr.regs[1].num |= 0b101; instr.regs[2].num |= (sibbyte >> 3) & 7; let scale = 1u8 << (sibbyte >> 6); instr.scale = scale; if disp == 0 { if modbits == 0 { OperandSpec::RegScale } else { OperandSpec::RegIndexBaseScale } } else { if modbits == 0 { OperandSpec::RegScaleDisp } else { OperandSpec::RegIndexBaseScaleDisp } } } } else { instr.regs[1].num |= sibbyte & 7; if ((sibbyte >> 3) & 7) == 0b100 { if disp == 0 { OperandSpec::Deref } else { OperandSpec::RegDisp } } else { instr.regs[2].num |= (sibbyte >> 3) & 7; let scale = 1u8 << (sibbyte >> 6); instr.scale = scale; if disp == 0 { OperandSpec::RegIndexBaseScale } else { OperandSpec::RegIndexBaseScaleDisp } } }; Ok(op_spec) } #[allow(non_snake_case)] fn read_M_16bit::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { let modbits = modrm >> 6; let mmm = modrm & 7; if modbits == 0b00 && mmm == 0b110 { instr.disp = read_num(words, 2)? as u16 as u32; return Ok(OperandSpec::DispU16); } match mmm { 0b000 => { instr.regs[1] = RegSpec::bx(); instr.regs[2] = RegSpec::si(); }, 0b001 => { instr.regs[1] = RegSpec::bx(); instr.regs[2] = RegSpec::di(); }, 0b010 => { instr.regs[1] = RegSpec::bp(); instr.regs[2] = RegSpec::si(); }, 0b011 => { instr.regs[1] = RegSpec::bp(); instr.regs[2] = RegSpec::di(); }, 0b100 => { instr.regs[1] = RegSpec::si(); }, 0b101 => { instr.regs[1] = RegSpec::di(); }, 0b110 => { instr.regs[1] = RegSpec::bp(); }, 0b111 => { instr.regs[1] = RegSpec::bx(); }, _ => { unreachable!("impossible bit pattern"); } } match modbits { 0b00 => { if mmm > 3 { Ok(OperandSpec::Deref) } else { Ok(OperandSpec::RegIndexBase) } }, 0b01 => { instr.disp = read_num(words, 1)? as i8 as i32 as u32; if mmm > 3 { if instr.disp != 0 { Ok(OperandSpec::RegDisp) } else { Ok(OperandSpec::Deref) } } else { if instr.disp != 0 { Ok(OperandSpec::RegIndexBaseDisp) } else { Ok(OperandSpec::RegIndexBase) } } }, 0b10 => { instr.disp = read_num(words, 2)? as i16 as i32 as u32; if mmm > 3 { if instr.disp != 0 { Ok(OperandSpec::RegDisp) } else { Ok(OperandSpec::Deref) } } else { if instr.disp != 0 { Ok(OperandSpec::RegIndexBaseDisp) } else { Ok(OperandSpec::RegIndexBase) } } }, _ => { unreachable!("read_M_16but but mod bits were not a memory operand"); } } } #[allow(non_snake_case)] fn read_M::Address, ::Word>>(words: &mut T, instr: &mut Instruction, modrm: u8) -> Result { if instr.prefixes.address_size() { return read_M_16bit(words, instr, modrm); } instr.regs[1].bank = RegisterBank::D; let modbits = modrm >> 6; let mmm = modrm & 7; let op_spec = if mmm == 4 { return read_sib(words, instr, modrm); } else if mmm == 5 && modbits == 0b00 { instr.disp = read_num(words, 4)?; OperandSpec::DispU32 } else { instr.regs[1].num |= mmm; if modbits == 0b00 { OperandSpec::Deref } else { let disp = if modbits == 0b01 { read_num(words, 1)? as i8 as i32 } else { read_num(words, 4)? as i32 }; if disp == 0 { OperandSpec::Deref } else { instr.disp = disp as i32 as u32; OperandSpec::RegDisp } } }; Ok(op_spec) } #[inline] fn width_to_gp_reg_bank(width: u8) -> RegisterBank { match width { 1 => return RegisterBank::B, 2 => return RegisterBank::W, 4 => return RegisterBank::D, _ => unsafe { unreachable_unchecked(); } } } fn read_0f_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { // seems like f2 takes priority, then f3, then 66, then "no prefix". for SOME instructions an // invalid prefix is in fact an invalid instruction. so just duplicate for the four kinds of // opcode lists. if prefixes.repnz() { match opcode { 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSD), OperandCode::PMOVX_G_E_xmm), 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSD), OperandCode::PMOVX_E_G_xmm), 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDDUP), OperandCode::PMOVX_G_E_xmm), 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), // 0x20 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SD), OperandCode::G_xmm_Ed), 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTSD), OperandCode::M_G_xmm), 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTSD2SI), OperandCode::PMOVX_G_E_xmm), 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSD2SI), OperandCode::PMOVX_G_E_xmm), 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTSD), OperandCode::PMOVX_G_E_xmm), 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSD), OperandCode::PMOVX_G_E_xmm), 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULSD), OperandCode::PMOVX_G_E_xmm), 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSD2SS), OperandCode::PMOVX_G_E_xmm), 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBSD), OperandCode::PMOVX_G_E_xmm), 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINSD), OperandCode::PMOVX_G_E_xmm), 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVSD), OperandCode::PMOVX_G_E_xmm), 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXSD), OperandCode::PMOVX_G_E_xmm), 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFLW), OperandCode::G_E_xmm_Ib), 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f2-0f71 instructions, so we can stop early 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f2-0f72 instructions, so we can stop early 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f2-0f73 instructions, so we can stop early 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf20f78), 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::INSERTQ), OperandCode::G_U_xmm), 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::HADDPS), OperandCode::G_E_xmm), 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPS), OperandCode::G_E_xmm), 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // 0x80 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), // 0x90 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), // 0xa0 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), // 0xb0 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M), 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M), 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M), 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::BSF), OperandCode::Gv_Ev), 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev), 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), // 0xc0 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPSD), OperandCode::G_E_xmm_Ib), 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), // cmpxchg permits an f2 prefix, which is the only reason this entry is not `Nothing` 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPS), OperandCode::G_E_xmm), 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQ2Q), OperandCode::U_mm_G_xmm), 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // 0xe0 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2DQ), OperandCode::G_E_xmm), 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::LDDQU), OperandCode::G_M_xmm), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), } } else if prefixes.rep() { match opcode { 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSS), OperandCode::G_Ed_xmm), 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSS), OperandCode::Ed_G_xmm), 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSLDUP), OperandCode::G_E_xmm), 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSHDUP), OperandCode::G_E_xmm), 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSI2SS), OperandCode::G_xmm_Ed), 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTSS), OperandCode::M_G_xmm), 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTSS2SI), OperandCode::Gv_E_xmm), 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSS2SI), OperandCode::Gv_E_xmm), 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), // 0x50 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTSS), OperandCode::G_Ed_xmm), 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::RSQRTSS), OperandCode::G_Ed_xmm), 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::RCPSS), OperandCode::G_Ed_xmm), 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSS), OperandCode::G_Ed_xmm), 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULSS), OperandCode::G_Ed_xmm), 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTSS2SD), OperandCode::PMOVX_G_E_xmm), 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPS2DQ), OperandCode::G_E_xmm), 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBSS), OperandCode::G_Ed_xmm), 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINSS), OperandCode::G_Ed_xmm), 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVSS), OperandCode::G_Ed_xmm), 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXSS), OperandCode::G_Ed_xmm), // 0x60 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQU), OperandCode::G_E_xmm), // 0x70 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFHW), OperandCode::G_E_xmm_Ib), 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f3-0f71 instructions, so we can stop early 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f3-0f72 instructions, so we can stop early 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // no f3-0f73 instructions, so we can stop early 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::MOVQ_f30f), 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQU), OperandCode::E_G_xmm), // 0x80 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), // 0x90 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), // 0xa0 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), // 0xb0 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M), 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M), 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M), 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::POPCNT), OperandCode::Gv_Ev), 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::TZCNT), OperandCode::Gv_Ev), 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::LZCNT), OperandCode::Gv_Ev), 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), // 0xc0 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPSS), OperandCode::G_E_xmm_Ib), 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ2DQ), OperandCode::G_xmm_U_mm), 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // 0xe0 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::CVTDQ2PD), OperandCode::G_E_xmm), 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // 0xf0 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), } } else if prefixes.operand_size() { match opcode { 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPD), OperandCode::G_E_xmm), 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPD), OperandCode::E_G_xmm), 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPD), OperandCode::PMOVX_G_E_xmm), 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPD), OperandCode::PMOVX_E_G_xmm), 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKLPD), OperandCode::G_E_xmm), 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKHPD), OperandCode::G_E_xmm), 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPD), OperandCode::PMOVX_G_E_xmm), 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPD), OperandCode::PMOVX_E_G_xmm), 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPD), OperandCode::G_E_xmm), 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPD), OperandCode::E_G_xmm), 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPI2PD), OperandCode::G_xmm_E_mm), 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTPD), OperandCode::M_G_xmm), 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPD2PI), OperandCode::G_mm_E_xmm), 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2PI), OperandCode::G_mm_E_xmm), 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::UCOMISD), OperandCode::PMOVX_G_E_xmm), 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::COMISD), OperandCode::PMOVX_G_E_xmm), 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVMSKPD), OperandCode::Gd_U_xmm), 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTPD), OperandCode::G_E_xmm), 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDPD), OperandCode::G_E_xmm), 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDNPD), OperandCode::G_E_xmm), 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::ORPD), OperandCode::G_E_xmm), 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::XORPD), OperandCode::G_E_xmm), 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDPD), OperandCode::G_E_xmm), 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULPD), OperandCode::G_E_xmm), 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPD2PS), OperandCode::G_E_xmm), 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2DQ), OperandCode::G_E_xmm), 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBPD), OperandCode::G_E_xmm), 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINPD), OperandCode::G_E_xmm), 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVPD), OperandCode::G_E_xmm), 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXPD), OperandCode::G_E_xmm), 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLBW), OperandCode::G_E_xmm), 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLWD), OperandCode::G_E_xmm), 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLDQ), OperandCode::G_E_xmm), 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSWB), OperandCode::G_E_xmm), 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTB), OperandCode::G_E_xmm), 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTW), OperandCode::G_E_xmm), 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTD), OperandCode::G_E_xmm), 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSWB), OperandCode::G_E_xmm), 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHBW), OperandCode::G_E_xmm), 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHWD), OperandCode::G_E_xmm), 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHDQ), OperandCode::G_E_xmm), 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSDW), OperandCode::G_E_xmm), 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLQDQ), OperandCode::G_E_xmm), 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHQDQ), OperandCode::G_E_xmm), 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::G_xmm_Ed), 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQA), OperandCode::G_E_xmm), 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFD), OperandCode::G_E_xmm_Ib), 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f71), 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f72), 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f73), 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQB), OperandCode::G_E_xmm), 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_xmm), 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_xmm), 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660f78), 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::EXTRQ), OperandCode::G_U_xmm), 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::HADDPD), OperandCode::G_E_xmm), 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::HSUBPD), OperandCode::G_E_xmm), 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::Ed_G_xmm), 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDQA), OperandCode::E_G_xmm), // 0x80 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), // 0x90 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), // 0xa0 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), // 0xb0 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::Gv_M), 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::Gv_M), 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::Gv_M), 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::BSF), OperandCode::Gv_Ev), 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev), 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), // 0xc0 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPPD), OperandCode::G_E_xmm_Ib), 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_xmm_Ew_Ib), 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::G_U_xmm_Ub), 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPD), OperandCode::G_E_xmm_Ib), 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), // 0xd0 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDSUBPD), OperandCode::G_E_xmm), 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLW), OperandCode::G_E_xmm), 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLD), OperandCode::G_E_xmm), 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLQ), OperandCode::G_E_xmm), 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_xmm), 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULLW), OperandCode::G_E_xmm), 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::PMOVX_E_G_xmm), 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVMSKB), OperandCode::Gd_U_xmm), 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::G_E_xmm), 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::G_E_xmm), 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::G_E_xmm), 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::G_E_xmm), 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::G_E_xmm), 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::G_E_xmm), 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::G_E_xmm), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::G_E_xmm), // 0xe0 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGB), OperandCode::G_E_xmm), 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::G_E_xmm), 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::G_E_xmm), 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::G_E_xmm), 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_xmm), 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_xmm), 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPD2DQ), OperandCode::G_E_xmm), 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTDQ), OperandCode::M_G_xmm), 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_xmm), 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_xmm), 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_xmm), 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::G_E_xmm), 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::G_E_xmm), 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::G_E_xmm), 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::G_E_xmm), 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::PXOR), OperandCode::G_E_xmm), // 0xf0 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLW), OperandCode::G_E_xmm), 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::G_E_xmm), 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::G_E_xmm), 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_xmm), 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_xmm), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_xmm), 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVDQU), OperandCode::G_U_xmm), 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_xmm), 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_xmm), 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_xmm), 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::G_E_xmm), 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_xmm), 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_xmm), 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_xmm), 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), } } else { match opcode { 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f00), 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f01), 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::LAR), OperandCode::Gv_Ew), 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::LSL), OperandCode::Gv_Ew_LSL), 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSCALL), OperandCode::Nothing), 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::CLTS), OperandCode::Nothing), 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSRET), OperandCode::Nothing), 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::INVD), OperandCode::Nothing), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::WBINVD), OperandCode::Nothing), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::UD2), OperandCode::Nothing), 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0d), 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::FEMMS), OperandCode::Nothing), 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f0f), 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::G_E_xmm), 0x11 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVUPS), OperandCode::E_G_xmm), 0x12 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f12), 0x13 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVLPS), OperandCode::M_G_xmm), 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKLPS), OperandCode::G_E_xmm), 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::UNPCKHPS), OperandCode::G_E_xmm), 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f16), 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVHPS), OperandCode::PMOVX_E_G_xmm), 0x18 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f18), 0x19 => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1a => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1b => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x1f => OpcodeRecord(Interpretation::Instruction(Opcode::NOP), OperandCode::Ev), 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Cq_0), 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Rq_Dq_0), 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Cq_Rq_0), 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::MOV), OperandCode::Dq_Rq_0), 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x26 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x27 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPS), OperandCode::G_E_xmm), 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVAPS), OperandCode::E_G_xmm), 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPI2PS), OperandCode::G_xmm_E_mm), 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTPS), OperandCode::M_G_xmm), 0x2c => OpcodeRecord(Interpretation::Instruction(Opcode::CVTTPS2PI), OperandCode::G_mm_E_xmm), 0x2d => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2PI), OperandCode::G_mm_E_xmm), 0x2e => OpcodeRecord(Interpretation::Instruction(Opcode::UCOMISS), OperandCode::PMOVX_G_E_xmm), 0x2f => OpcodeRecord(Interpretation::Instruction(Opcode::COMISS), OperandCode::PMOVX_G_E_xmm), // 0x30 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::WRMSR), OperandCode::Nothing), 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::RDTSC), OperandCode::Nothing), 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::RDMSR), OperandCode::Nothing), 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::RDPMC), OperandCode::Nothing), 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSENTER), OperandCode::Nothing), 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::SYSEXIT), OperandCode::Nothing), 0x36 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::GETSEC), OperandCode::Nothing), 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // handled before getting to `read_0f_opcode` 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // 0x40 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVO), OperandCode::Gv_Ev), 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNO), OperandCode::Gv_Ev), 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVB), OperandCode::Gv_Ev), 0x43 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNB), OperandCode::Gv_Ev), 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVZ), OperandCode::Gv_Ev), 0x45 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNZ), OperandCode::Gv_Ev), 0x46 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNA), OperandCode::Gv_Ev), 0x47 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVA), OperandCode::Gv_Ev), 0x48 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVS), OperandCode::Gv_Ev), 0x49 => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNS), OperandCode::Gv_Ev), 0x4a => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVP), OperandCode::Gv_Ev), 0x4b => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVNP), OperandCode::Gv_Ev), 0x4c => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVL), OperandCode::Gv_Ev), 0x4d => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVGE), OperandCode::Gv_Ev), 0x4e => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVLE), OperandCode::Gv_Ev), 0x4f => OpcodeRecord(Interpretation::Instruction(Opcode::CMOVG), OperandCode::Gv_Ev), // 0x50 0x50 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVMSKPS), OperandCode::Gd_U_xmm), 0x51 => OpcodeRecord(Interpretation::Instruction(Opcode::SQRTPS), OperandCode::G_E_xmm), 0x52 => OpcodeRecord(Interpretation::Instruction(Opcode::RSQRTPS), OperandCode::G_E_xmm), 0x53 => OpcodeRecord(Interpretation::Instruction(Opcode::RCPPS), OperandCode::G_E_xmm), 0x54 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDPS), OperandCode::G_E_xmm), 0x55 => OpcodeRecord(Interpretation::Instruction(Opcode::ANDNPS), OperandCode::G_E_xmm), 0x56 => OpcodeRecord(Interpretation::Instruction(Opcode::ORPS), OperandCode::G_E_xmm), 0x57 => OpcodeRecord(Interpretation::Instruction(Opcode::XORPS), OperandCode::G_E_xmm), 0x58 => OpcodeRecord(Interpretation::Instruction(Opcode::ADDPS), OperandCode::G_E_xmm), 0x59 => OpcodeRecord(Interpretation::Instruction(Opcode::MULPS), OperandCode::G_E_xmm), 0x5a => OpcodeRecord(Interpretation::Instruction(Opcode::CVTPS2PD), OperandCode::PMOVX_G_E_xmm), 0x5b => OpcodeRecord(Interpretation::Instruction(Opcode::CVTDQ2PS), OperandCode::G_E_xmm), 0x5c => OpcodeRecord(Interpretation::Instruction(Opcode::SUBPS), OperandCode::G_E_xmm), 0x5d => OpcodeRecord(Interpretation::Instruction(Opcode::MINPS), OperandCode::G_E_xmm), 0x5e => OpcodeRecord(Interpretation::Instruction(Opcode::DIVPS), OperandCode::G_E_xmm), 0x5f => OpcodeRecord(Interpretation::Instruction(Opcode::MAXPS), OperandCode::G_E_xmm), // 0x60 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLBW), OperandCode::G_E_mm), 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLWD), OperandCode::G_E_mm), 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKLDQ), OperandCode::G_E_mm), 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSWB), OperandCode::G_E_mm), 0x64 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTB), OperandCode::G_E_mm), 0x65 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTW), OperandCode::G_E_mm), 0x66 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTD), OperandCode::G_E_mm), 0x67 => OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSWB), OperandCode::G_E_mm), 0x68 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHBW), OperandCode::G_E_mm), 0x69 => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHWD), OperandCode::G_E_mm), 0x6a => OpcodeRecord(Interpretation::Instruction(Opcode::PUNPCKHDQ), OperandCode::G_E_mm), 0x6b => OpcodeRecord(Interpretation::Instruction(Opcode::PACKSSDW), OperandCode::G_E_mm), 0x6c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x6e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::G_mm_Ed), 0x6f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::G_mm_E), // 0x70 0x70 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFW), OperandCode::G_E_mm_Ib), 0x71 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f71), 0x72 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f72), 0x73 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0f73), 0x74 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQB), OperandCode::G_E_mm), 0x75 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQW), OperandCode::G_E_mm), 0x76 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQD), OperandCode::G_E_mm), 0x77 => OpcodeRecord(Interpretation::Instruction(Opcode::EMMS), OperandCode::Nothing), 0x78 => OpcodeRecord(Interpretation::Instruction(Opcode::VMREAD), OperandCode::E_G_q), 0x79 => OpcodeRecord(Interpretation::Instruction(Opcode::VMWRITE), OperandCode::G_E_q), 0x7a => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7b => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7c => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7d => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0x7e => OpcodeRecord(Interpretation::Instruction(Opcode::MOVD), OperandCode::Ed_G_mm), 0x7f => OpcodeRecord(Interpretation::Instruction(Opcode::MOVQ), OperandCode::E_G_mm), // 0x80 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::JO), OperandCode::Jvds), 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::JNO), OperandCode::Jvds), 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::JB), OperandCode::Jvds), 0x83 => OpcodeRecord(Interpretation::Instruction(Opcode::JNB), OperandCode::Jvds), 0x84 => OpcodeRecord(Interpretation::Instruction(Opcode::JZ), OperandCode::Jvds), 0x85 => OpcodeRecord(Interpretation::Instruction(Opcode::JNZ), OperandCode::Jvds), 0x86 => OpcodeRecord(Interpretation::Instruction(Opcode::JNA), OperandCode::Jvds), 0x87 => OpcodeRecord(Interpretation::Instruction(Opcode::JA), OperandCode::Jvds), 0x88 => OpcodeRecord(Interpretation::Instruction(Opcode::JS), OperandCode::Jvds), 0x89 => OpcodeRecord(Interpretation::Instruction(Opcode::JNS), OperandCode::Jvds), 0x8a => OpcodeRecord(Interpretation::Instruction(Opcode::JP), OperandCode::Jvds), 0x8b => OpcodeRecord(Interpretation::Instruction(Opcode::JNP), OperandCode::Jvds), 0x8c => OpcodeRecord(Interpretation::Instruction(Opcode::JL), OperandCode::Jvds), 0x8d => OpcodeRecord(Interpretation::Instruction(Opcode::JGE), OperandCode::Jvds), 0x8e => OpcodeRecord(Interpretation::Instruction(Opcode::JLE), OperandCode::Jvds), 0x8f => OpcodeRecord(Interpretation::Instruction(Opcode::JG), OperandCode::Jvds), // 0x90 0x90 => OpcodeRecord(Interpretation::Instruction(Opcode::SETO), OperandCode::Eb_R0), 0x91 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNO), OperandCode::Eb_R0), 0x92 => OpcodeRecord(Interpretation::Instruction(Opcode::SETB), OperandCode::Eb_R0), 0x93 => OpcodeRecord(Interpretation::Instruction(Opcode::SETAE), OperandCode::Eb_R0), 0x94 => OpcodeRecord(Interpretation::Instruction(Opcode::SETZ), OperandCode::Eb_R0), 0x95 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNZ), OperandCode::Eb_R0), 0x96 => OpcodeRecord(Interpretation::Instruction(Opcode::SETBE), OperandCode::Eb_R0), 0x97 => OpcodeRecord(Interpretation::Instruction(Opcode::SETA), OperandCode::Eb_R0), 0x98 => OpcodeRecord(Interpretation::Instruction(Opcode::SETS), OperandCode::Eb_R0), 0x99 => OpcodeRecord(Interpretation::Instruction(Opcode::SETNS), OperandCode::Eb_R0), 0x9a => OpcodeRecord(Interpretation::Instruction(Opcode::SETP), OperandCode::Eb_R0), 0x9b => OpcodeRecord(Interpretation::Instruction(Opcode::SETNP), OperandCode::Eb_R0), 0x9c => OpcodeRecord(Interpretation::Instruction(Opcode::SETL), OperandCode::Eb_R0), 0x9d => OpcodeRecord(Interpretation::Instruction(Opcode::SETGE), OperandCode::Eb_R0), 0x9e => OpcodeRecord(Interpretation::Instruction(Opcode::SETLE), OperandCode::Eb_R0), 0x9f => OpcodeRecord(Interpretation::Instruction(Opcode::SETG), OperandCode::Eb_R0), // 0xa0 0xa0 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::FS), 0xa1 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::FS), 0xa2 => OpcodeRecord(Interpretation::Instruction(Opcode::CPUID), OperandCode::Nothing), 0xa3 => OpcodeRecord(Interpretation::Instruction(Opcode::BT), OperandCode::Ev_Gv), 0xa4 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_Ib), 0xa5 => OpcodeRecord(Interpretation::Instruction(Opcode::SHLD), OperandCode::Ev_Gv_CL), 0xa6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xa8 => OpcodeRecord(Interpretation::Instruction(Opcode::PUSH), OperandCode::GS), 0xa9 => OpcodeRecord(Interpretation::Instruction(Opcode::POP), OperandCode::GS), 0xaa => OpcodeRecord(Interpretation::Instruction(Opcode::RSM), OperandCode::Nothing), 0xab => OpcodeRecord(Interpretation::Instruction(Opcode::BTS), OperandCode::Ev_Gv), 0xac => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_Ib), 0xad => OpcodeRecord(Interpretation::Instruction(Opcode::SHRD), OperandCode::Ev_Gv_CL), 0xae => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fae), 0xaf => OpcodeRecord(Interpretation::Instruction(Opcode::IMUL), OperandCode::Gv_Ev), // 0xb0 0xb0 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Eb_Gb), 0xb1 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPXCHG), OperandCode::Ev_Gv), 0xb2 => OpcodeRecord(Interpretation::Instruction(Opcode::LSS), OperandCode::INV_Gv_M), 0xb3 => OpcodeRecord(Interpretation::Instruction(Opcode::BTR), OperandCode::Ev_Gv), 0xb4 => OpcodeRecord(Interpretation::Instruction(Opcode::LFS), OperandCode::INV_Gv_M), 0xb5 => OpcodeRecord(Interpretation::Instruction(Opcode::LGS), OperandCode::INV_Gv_M), 0xb6 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Eb), 0xb7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVZX), OperandCode::Gv_Ew), 0xb8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), // JMPE, ITANIUM 0xb9 => OpcodeRecord(Interpretation::Instruction(Opcode::UD1), OperandCode::Gv_Ev), 0xba => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fba), 0xbb => OpcodeRecord(Interpretation::Instruction(Opcode::BTC), OperandCode::Ev_Gv), 0xbc => OpcodeRecord(Interpretation::Instruction(Opcode::BSF), OperandCode::Gv_Ev), 0xbd => OpcodeRecord(Interpretation::Instruction(Opcode::BSR), OperandCode::Gv_Ev), 0xbe => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Eb), 0xbf => OpcodeRecord(Interpretation::Instruction(Opcode::MOVSX), OperandCode::Gv_Ew), // 0xc0 0xc0 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Eb_Gb), 0xc1 => OpcodeRecord(Interpretation::Instruction(Opcode::XADD), OperandCode::Ev_Gv), 0xc2 => OpcodeRecord(Interpretation::Instruction(Opcode::CMPPS), OperandCode::G_E_xmm_Ib), 0xc3 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTI), OperandCode::Md_Gd), 0xc4 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRW), OperandCode::G_mm_Ew_Ib), 0xc5 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::Rv_Gmm_Ib), 0xc6 => OpcodeRecord(Interpretation::Instruction(Opcode::SHUFPS), OperandCode::G_E_xmm_Ib), 0xc7 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x0fc7), 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R0), 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R1), 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R2), 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R3), 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R4), 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R5), 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R6), 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::BSWAP), OperandCode::Zv_R7), // 0xd0 0xd0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLW), OperandCode::G_E_mm), 0xd2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLD), OperandCode::G_E_mm), 0xd3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRLQ), OperandCode::G_E_mm), 0xd4 => OpcodeRecord(Interpretation::Instruction(Opcode::PADDQ), OperandCode::G_E_mm), 0xd5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULLW), OperandCode::G_E_mm), 0xd6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xd7 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVMSKB), OperandCode::G_U_mm), 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSB), OperandCode::G_E_mm), 0xd9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBUSW), OperandCode::G_E_mm), 0xda => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUB), OperandCode::G_E_mm), 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::PAND), OperandCode::G_E_mm), 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSB), OperandCode::G_E_mm), 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDUSW), OperandCode::G_E_mm), 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUB), OperandCode::G_E_mm), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::PANDN), OperandCode::G_E_mm), // 0xe0 0xe0 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGB), OperandCode::G_E_mm), 0xe1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAW), OperandCode::G_E_mm), 0xe2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSRAD), OperandCode::G_E_mm), 0xe3 => OpcodeRecord(Interpretation::Instruction(Opcode::PAVGW), OperandCode::G_E_mm), 0xe4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHUW), OperandCode::G_E_mm), 0xe5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHW), OperandCode::G_E_mm), 0xe6 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xe7 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTQ), OperandCode::G_Mq_mm), 0xe8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSB), OperandCode::G_E_mm), 0xe9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBSW), OperandCode::G_E_mm), 0xea => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSW), OperandCode::G_E_mm), 0xeb => OpcodeRecord(Interpretation::Instruction(Opcode::POR), OperandCode::G_E_mm), 0xec => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSB), OperandCode::G_E_mm), 0xed => OpcodeRecord(Interpretation::Instruction(Opcode::PADDSW), OperandCode::G_E_mm), 0xee => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSW), OperandCode::G_E_mm), 0xef => OpcodeRecord(Interpretation::Instruction(Opcode::PXOR), OperandCode::G_E_mm), // 0xf0 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLW), OperandCode::G_E_mm), 0xf2 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLD), OperandCode::G_E_mm), 0xf3 => OpcodeRecord(Interpretation::Instruction(Opcode::PSLLQ), OperandCode::G_E_mm), 0xf4 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULUDQ), OperandCode::G_E_mm), 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDWD), OperandCode::G_E_mm), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::PSADBW), OperandCode::G_E_mm), 0xf7 => OpcodeRecord(Interpretation::Instruction(Opcode::MASKMOVQ), OperandCode::G_mm_U_mm), 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBB), OperandCode::G_E_mm), 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBW), OperandCode::G_E_mm), 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBD), OperandCode::G_E_mm), 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::PSUBQ), OperandCode::G_E_mm), 0xfc => OpcodeRecord(Interpretation::Instruction(Opcode::PADDB), OperandCode::G_E_mm), 0xfd => OpcodeRecord(Interpretation::Instruction(Opcode::PADDW), OperandCode::G_E_mm), 0xfe => OpcodeRecord(Interpretation::Instruction(Opcode::PADDD), OperandCode::G_E_mm), 0xff => OpcodeRecord(Interpretation::Instruction(Opcode::UD0), OperandCode::Gd_Ed), } } } fn read_0f38_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { if prefixes.rep() { return match opcode { 0xd8 => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38d8), 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38dc), 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38dd), 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38de), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38df), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::ADOX), OperandCode::Gv_Ev), 0xf8 => { prefixes.unset_operand_size(); OpcodeRecord(Interpretation::Instruction(Opcode::ENQCMDS), OperandCode::INV_Gv_M) }, 0xfa => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38fa), 0xfb => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30f38fb), _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } if prefixes.repnz() { return match opcode { 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::CRC32), OperandCode::Gv_Eb), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::CRC32), OperandCode::Gd_Ev), 0xf8 => { prefixes.unset_operand_size(); OpcodeRecord(Interpretation::Instruction(Opcode::ENQCMD), OperandCode::INV_Gv_M) }, _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } if prefixes.operand_size() { // leave operand size present for `movbe` if opcode != 0xf0 && opcode != 0xf1 { prefixes.unset_operand_size(); } return match opcode { 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFB), OperandCode::G_E_xmm), 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDW), OperandCode::G_E_xmm), 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDD), OperandCode::G_E_xmm), 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDSW), OperandCode::G_E_xmm), 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDUBSW), OperandCode::G_E_xmm), 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBW), OperandCode::G_E_xmm), 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBD), OperandCode::G_E_xmm), 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBSW), OperandCode::G_E_xmm), 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNB), OperandCode::G_E_xmm), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNW), OperandCode::G_E_xmm), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGND), OperandCode::G_E_xmm), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHRSW), OperandCode::G_E_xmm), 0x10 => OpcodeRecord(Interpretation::Instruction(Opcode::PBLENDVB), OperandCode::G_E_xmm), 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDVPS), OperandCode::G_E_xmm), 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDVPD), OperandCode::G_E_xmm), 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::PTEST), OperandCode::G_E_xmm), 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::PABSB), OperandCode::G_E_xmm), 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::PABSW), OperandCode::G_E_xmm), 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::PABSD), OperandCode::G_E_xmm), 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXBW), OperandCode::PMOVX_G_E_xmm), 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXBD), OperandCode::PMOVX_G_E_xmm), 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXBQ), OperandCode::PMOVX_G_E_xmm), 0x23 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXWD), OperandCode::PMOVX_G_E_xmm), 0x24 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXWQ), OperandCode::PMOVX_G_E_xmm), 0x25 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVSXDQ), OperandCode::PMOVX_G_E_xmm), 0x28 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULDQ), OperandCode::G_E_xmm), 0x29 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPEQQ), OperandCode::G_E_xmm), 0x2a => OpcodeRecord(Interpretation::Instruction(Opcode::MOVNTDQA), OperandCode::G_M_xmm), 0x2b => OpcodeRecord(Interpretation::Instruction(Opcode::PACKUSDW), OperandCode::G_E_xmm), 0x30 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXBW), OperandCode::PMOVX_G_E_xmm), 0x31 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXBD), OperandCode::PMOVX_G_E_xmm), 0x32 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXBQ), OperandCode::PMOVX_G_E_xmm), 0x33 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXWD), OperandCode::PMOVX_G_E_xmm), 0x34 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXWQ), OperandCode::PMOVX_G_E_xmm), 0x35 => OpcodeRecord(Interpretation::Instruction(Opcode::PMOVZXDQ), OperandCode::PMOVX_G_E_xmm), 0x37 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPGTQ), OperandCode::G_E_xmm), 0x38 => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSB), OperandCode::G_E_xmm), 0x39 => OpcodeRecord(Interpretation::Instruction(Opcode::PMINSD), OperandCode::G_E_xmm), 0x3a => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUW), OperandCode::G_E_xmm), 0x3b => OpcodeRecord(Interpretation::Instruction(Opcode::PMINUD), OperandCode::G_E_xmm), 0x3c => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSB), OperandCode::G_E_xmm), 0x3d => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXSD), OperandCode::G_E_xmm), 0x3e => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUW), OperandCode::G_E_xmm), 0x3f => OpcodeRecord(Interpretation::Instruction(Opcode::PMAXUD), OperandCode::G_E_xmm), 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::PMULLD), OperandCode::G_E_xmm), 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::PHMINPOSUW), OperandCode::G_E_xmm), 0x80 => OpcodeRecord(Interpretation::Instruction(Opcode::INVEPT), OperandCode::INV_Gv_M), 0x81 => OpcodeRecord(Interpretation::Instruction(Opcode::INVVPID), OperandCode::INV_Gv_M), 0x82 => OpcodeRecord(Interpretation::Instruction(Opcode::INVPCID), OperandCode::INV_Gv_M), 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::GF2P8MULB), OperandCode::G_E_xmm), 0xdb => OpcodeRecord(Interpretation::Instruction(Opcode::AESIMC), OperandCode::G_E_xmm), 0xdc => OpcodeRecord(Interpretation::Instruction(Opcode::AESENC), OperandCode::G_E_xmm), 0xdd => OpcodeRecord(Interpretation::Instruction(Opcode::AESENCLAST), OperandCode::G_E_xmm), 0xde => OpcodeRecord(Interpretation::Instruction(Opcode::AESDEC), OperandCode::G_E_xmm), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::AESDECLAST), OperandCode::G_E_xmm), 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::Gv_M), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::M_Gv), 0xf5 => OpcodeRecord(Interpretation::Instruction(Opcode::WRUSS), OperandCode::Md_Gd), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::ADCX), OperandCode::Gv_Ev), 0xf8 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDIR64B), OperandCode::MOVDIR64B), _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } else { return match opcode { 0x00 => OpcodeRecord(Interpretation::Instruction(Opcode::PSHUFB), OperandCode::G_E_mm), 0x01 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDW), OperandCode::G_E_mm), 0x02 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDD), OperandCode::G_E_mm), 0x03 => OpcodeRecord(Interpretation::Instruction(Opcode::PHADDSW), OperandCode::G_E_mm), 0x04 => OpcodeRecord(Interpretation::Instruction(Opcode::PMADDUBSW), OperandCode::G_E_mm), 0x05 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBW), OperandCode::G_E_mm), 0x06 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBD), OperandCode::G_E_mm), 0x07 => OpcodeRecord(Interpretation::Instruction(Opcode::PHSUBSW), OperandCode::G_E_mm), 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNB), OperandCode::G_E_mm), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGNW), OperandCode::G_E_mm), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::PSIGND), OperandCode::G_E_mm), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::PMULHRSW), OperandCode::G_E_mm), 0x1c => OpcodeRecord(Interpretation::Instruction(Opcode::PABSB), OperandCode::G_E_mm), 0x1d => OpcodeRecord(Interpretation::Instruction(Opcode::PABSW), OperandCode::G_E_mm), 0x1e => OpcodeRecord(Interpretation::Instruction(Opcode::PABSD), OperandCode::G_E_mm), 0xc8 => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1NEXTE), OperandCode::G_E_xmm), 0xc9 => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1MSG1), OperandCode::G_E_xmm), 0xca => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1MSG2), OperandCode::G_E_xmm), 0xcb => OpcodeRecord(Interpretation::Instruction(Opcode::SHA256RNDS2), OperandCode::G_E_xmm), 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::SHA256MSG1), OperandCode::G_E_xmm), 0xcd => OpcodeRecord(Interpretation::Instruction(Opcode::SHA256MSG2), OperandCode::G_E_xmm), 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::Gv_M), 0xf1 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVBE), OperandCode::M_Gv), 0xf6 => OpcodeRecord(Interpretation::Instruction(Opcode::WRSS), OperandCode::Md_Gd), 0xf9 => OpcodeRecord(Interpretation::Instruction(Opcode::MOVDIRI), OperandCode::Md_Gd), _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } } fn read_0f3a_opcode(opcode: u8, prefixes: &mut Prefixes) -> OpcodeRecord { if prefixes.rep() { if prefixes != &Prefixes::new(0x10) { return OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing); } return match opcode { 0xf0 => OpcodeRecord(Interpretation::Instruction(Opcode::HRESET), OperandCode::ModRM_0xf30f3af0), _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } if prefixes.repnz() { return OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing); } if prefixes.operand_size() { return match opcode { 0x08 => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDPS), OperandCode::G_E_xmm_Ib), 0x09 => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDPD), OperandCode::G_E_xmm_Ib), 0x0a => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDSS), OperandCode::G_E_xmm_Ib), 0x0b => OpcodeRecord(Interpretation::Instruction(Opcode::ROUNDSD), OperandCode::G_E_xmm_Ib), 0x0c => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDPS), OperandCode::G_E_xmm_Ib), 0x0d => OpcodeRecord(Interpretation::Instruction(Opcode::BLENDPD), OperandCode::G_E_xmm_Ib), 0x0e => OpcodeRecord(Interpretation::Instruction(Opcode::PBLENDW), OperandCode::G_E_xmm_Ib), 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::PALIGNR), OperandCode::G_E_xmm_Ib), 0x14 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRB), OperandCode::G_Ev_xmm_Ib), 0x15 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRW), OperandCode::G_Ev_xmm_Ib), 0x16 => OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRD), OperandCode::G_Ev_xmm_Ib), 0x17 => OpcodeRecord(Interpretation::Instruction(Opcode::EXTRACTPS), OperandCode::G_Ev_xmm_Ib), 0x20 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRB), OperandCode::G_Ev_xmm_Ib), 0x21 => OpcodeRecord(Interpretation::Instruction(Opcode::INSERTPS), OperandCode::G_Ev_xmm_Ib), 0x22 => OpcodeRecord(Interpretation::Instruction(Opcode::PINSRD), OperandCode::G_Ev_xmm_Ib), 0x40 => OpcodeRecord(Interpretation::Instruction(Opcode::DPPS), OperandCode::G_E_xmm_Ib), 0x41 => OpcodeRecord(Interpretation::Instruction(Opcode::DPPD), OperandCode::G_E_xmm_Ib), 0x42 => OpcodeRecord(Interpretation::Instruction(Opcode::MPSADBW), OperandCode::G_E_xmm_Ib), 0x44 => OpcodeRecord(Interpretation::Instruction(Opcode::PCLMULQDQ), OperandCode::G_E_xmm_Ib), 0x60 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPESTRM), OperandCode::G_E_xmm_Ib), 0x61 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPESTRI), OperandCode::G_E_xmm_Ib), 0x62 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPISTRM), OperandCode::G_E_xmm_Ib), 0x63 => OpcodeRecord(Interpretation::Instruction(Opcode::PCMPISTRI), OperandCode::G_E_xmm_Ib), 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1RNDS4), OperandCode::G_E_xmm_Ib), 0xce => OpcodeRecord(Interpretation::Instruction(Opcode::GF2P8AFFINEQB), OperandCode::G_E_xmm_Ub), 0xcf => OpcodeRecord(Interpretation::Instruction(Opcode::GF2P8AFFINEINVQB), OperandCode::G_E_xmm_Ub), 0xdf => OpcodeRecord(Interpretation::Instruction(Opcode::AESKEYGENASSIST), OperandCode::G_E_xmm_Ub), _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } return match opcode { 0xcc => OpcodeRecord(Interpretation::Instruction(Opcode::SHA1RNDS4), OperandCode::G_E_xmm_Ub), 0x0f => OpcodeRecord(Interpretation::Instruction(Opcode::PALIGNR), OperandCode::G_E_mm_Ib), _ => OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), }; } fn read_instr::Address, ::Word>>(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction) -> Result<(), DecodeError> { words.mark(); let mut nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; let mut next_rec = OPCODES[nextb as usize]; let mut prefixes = Prefixes::new(0); // default registers to `[eax; 4]` instruction.regs = unsafe { core::mem::transmute(0u64) }; instruction.mem_size = 0; // default operands to [RegRRR, Nothing, Nothing, Nothing] instruction.operands = unsafe { core::mem::transmute(0x00_00_00_01) }; instruction.operand_count = 2; let record: OpcodeRecord = loop { let record = next_rec; if let Interpretation::Instruction(_) = record.0 { break record; } else { let b = nextb; if words.offset() >= 15 { return Err(DecodeError::TooLong); } if b == 0x0f { let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; if b == 0x38 { let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; break read_0f38_opcode(b, &mut prefixes); } else if b == 0x3a { let b = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; break read_0f3a_opcode(b, &mut prefixes); } else { break read_0f_opcode(b, &mut prefixes); } } nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; next_rec = unsafe { core::ptr::read_volatile(&OPCODES[nextb as usize]) }; match b { 0x26 => { prefixes.set_es(); }, 0x2e => { prefixes.set_cs(); }, 0x36 => { prefixes.set_ss(); }, 0x3e => { prefixes.set_ds(); }, 0x64 => { prefixes.set_fs(); }, 0x65 => { prefixes.set_gs(); }, 0x66 => { prefixes.set_operand_size(); }, 0x67 => { prefixes.set_address_size(); }, 0xf0 => { prefixes.set_lock(); }, 0xf2 => { prefixes.set_repnz(); }, 0xf3 => { prefixes.set_rep(); }, _ => { unsafe { unreachable_unchecked(); } } } } }; 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(); } } instruction.prefixes = prefixes; read_operands(decoder, words, instruction, record.1)?; instruction.length = words.offset() as u8; if instruction.length > 15 { return Err(DecodeError::TooLong); } if instruction.prefixes.lock() { if !LOCKABLE_INSTRUCTIONS.contains(&instruction.opcode) || !instruction.operands[0].is_memory() { return Err(DecodeError::InvalidPrefixes); } } if decoder != &InstDecoder::default() { // we might have to fix up or reject this instruction under whatever cpu features we need to // pretend to have. decoder.revise_instruction(instruction)?; } Ok(()) } /* 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 */ fn read_operands::Address, ::Word>>(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode) -> Result<(), DecodeError> { 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.regs[0] = RegSpec::from_parts(reg, bank); instruction.operand_count = 1; } 1 => { // Zv_AX let bank = if !instruction.prefixes.operand_size() { RegisterBank::D } else { RegisterBank::W }; instruction.regs[0] = RegSpec::from_parts(0, bank); instruction.operands[1] = OperandSpec::RegMMM; instruction.regs[1] = RegSpec::from_parts(reg, bank); instruction.operand_count = 2; } 2 => { // these are Zb_Ib_R instruction.regs[0] = RegSpec::from_parts(reg, RegisterBank::B); instruction.imm = read_imm_unsigned(words, 1)?; instruction.operands[1] = OperandSpec::ImmU8; } 3 => { // category == 3, Zv_Iv_R if !instruction.prefixes.operand_size() { instruction.regs[0] = RegSpec::from_parts(reg, RegisterBank::D); instruction.imm = read_imm_unsigned(words, 4)?; instruction.operands[1] = OperandSpec::ImmI32; } else { instruction.regs[0] = RegSpec::from_parts(reg, RegisterBank::W); instruction.imm = read_imm_unsigned(words, 2)?; 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. _ => {} } } let mut modrm = 0; let bank: RegisterBank; let mut mem_oper = OperandSpec::Nothing; if operand_code.has_read_E() { // cool! we can precompute opwidth and know we need to read_E. if !operand_code.has_byte_operands() { // further, this is an vd E if !instruction.prefixes.operand_size() { instruction.mem_size = 4; bank = RegisterBank::D; } else { instruction.mem_size = 2; bank = RegisterBank::W; } } else { instruction.mem_size = 1; bank = RegisterBank::B; }; modrm = read_modrm(words)?; instruction.regs[0].bank = bank; instruction.regs[0].num = (modrm >> 3) & 7; 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 { read_M(words, instruction, modrm)? }; instruction.operands[1] = mem_oper; } if let Some((only_imm, immsz)) = operand_code.has_imm() { instruction.imm = read_imm_signed(words, 1 << (immsz * 2))? 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 => { instruction.operands[0] = mem_oper; instruction.operand_count = 1; }, 1 => { instruction.opcode = base_opcode_map((modrm >> 3) & 7); instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::ImmI8; instruction.operand_count = 2; } 2 => { instruction.operands[0] = mem_oper; let numwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; instruction.imm = read_imm_signed(words, numwidth)? as u32; instruction.opcode = base_opcode_map((modrm >> 3) & 7); instruction.operands[1] = match numwidth { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, _ => unsafe { unreachable_unchecked() } }; instruction.operand_count = 2; }, 3 => { // ModRM_0xc6_Eb_Ib if modrm == 0xf8 { instruction.opcode = Opcode::XABORT; instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[0] = OperandSpec::ImmI8; instruction.operand_count = 1; return Ok(()); } if (modrm & 0b00111000) != 0 { return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string()); } instruction.operands[0] = mem_oper; instruction.opcode = Opcode::MOV; instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[1] = OperandSpec::ImmI8; instruction.operand_count = 2; } 4 => { // ModRM_0xc7_Ev_Iv if modrm == 0xf8 { instruction.opcode = Opcode::XBEGIN; instruction.imm = if instruction.prefixes.operand_size() { read_imm_signed(words, 2)? as i16 as i32 as u32 } else { read_imm_signed(words, 4)? as i32 as u32 }; instruction.operands[0] = OperandSpec::ImmI32; instruction.operand_count = 1; return Ok(()); } if (modrm & 0b00111000) != 0 { return Err(DecodeError::InvalidOperand); // Err("Invalid modr/m for opcode 0xc7".to_string()); } instruction.operands[0] = mem_oper; instruction.opcode = Opcode::MOV; if instruction.prefixes.operand_size() { instruction.imm = read_imm_signed(words, 2)? as u32; instruction.operands[1] = OperandSpec::ImmI16; } else { instruction.imm = read_imm_signed(words, 4)? as u32; instruction.operands[1] = OperandSpec::ImmI32; } }, 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 op == 10 { instruction.regs[0] = RegSpec::cl(); instruction.operands[1] = OperandSpec::RegRRR; } else if op == 9 { instruction.regs[0] = RegSpec::cl(); instruction.operands[1] = OperandSpec::RegRRR; } else { let num = match op { 5 | 6 => { read_num(words, 1)? } _ => { // these are the _1 variants, everything else is unreachable 1 } }; instruction.imm = num; instruction.operands[1] = OperandSpec::ImmI8; } instruction.operand_count = 2; }, op @ 11 | op @ 12 => { let opwidth = if op == 11 { 1 } else { if instruction.prefixes.operand_size() { 2 } else { 4 } }; instruction.operands[0] = mem_oper; const TABLE: [Opcode; 8] = [ Opcode::TEST, Opcode::TEST, Opcode::NOT, Opcode::NEG, Opcode::MUL, Opcode::IMUL, Opcode::DIV, Opcode::IDIV, ]; let rrr = (modrm >> 3) & 7; instruction.opcode = TABLE[rrr as usize]; if rrr < 2 { instruction.opcode = Opcode::TEST; let numwidth = if opwidth == 8 { 4 } else { opwidth }; instruction.imm = read_imm_signed(words, numwidth)? as u32; instruction.operands[1] = match opwidth { 1 => OperandSpec::ImmI8, 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, _ => unsafe { unreachable_unchecked() } }; } else { instruction.operand_count = 1; } }, 13 => { instruction.operands[0] = mem_oper; let r = (modrm >> 3) & 7; if r >= 2 { return Err(DecodeError::InvalidOpcode); } instruction.opcode = [ Opcode::INC, Opcode::DEC, ][r as usize]; instruction.operand_count = 1; } 14 => { instruction.operands[0] = mem_oper; let r = (modrm >> 3) & 7; if r == 7 { return Err(DecodeError::InvalidOpcode); } let opcode = [ Opcode::INC, Opcode::DEC, Opcode::CALL, Opcode::CALLF, Opcode::JMP, Opcode::JMPF, Opcode::PUSH, ][r as usize]; if instruction.operands[0] == OperandSpec::RegMMM { if opcode == Opcode::CALL || opcode == Opcode::JMP { instruction.regs[1].bank = RegisterBank::D; } else if opcode == Opcode::CALLF || opcode == Opcode::JMPF { return Err(DecodeError::InvalidOperand); } } else { if opcode == Opcode::CALL || opcode == Opcode::JMP || opcode == Opcode::PUSH || opcode == Opcode::POP { instruction.mem_size = 4; } else if opcode == Opcode::CALLF || opcode == Opcode::JMPF { instruction.mem_size = 6; } } instruction.opcode = opcode; instruction.operand_count = 1; } 15 => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E(words, instruction, modrm, 1)?; instruction.regs[0] = if instruction.prefixes.operand_size() { RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W) } else { RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D) }; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 1; } instruction.operand_count = 2; }, 16 => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E(words, instruction, modrm, 2)?; instruction.regs[0] = if instruction.prefixes.operand_size() { RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W) } else { RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D) }; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 2; } instruction.operand_count = 2; }, 18 => { instruction.operands[0] = mem_oper; instruction.operand_count = 1; }, 19 => { instruction.regs[0].bank = RegisterBank::X; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; if instruction.operands[0] == OperandSpec::RegMMM { // fix the register to XMM instruction.regs[1].bank = RegisterBank::X; } else { instruction.mem_size = 16; } }, op @ 20 | op @ 21 => { instruction.regs[0].bank = RegisterBank::X; instruction.operand_count = 2; if instruction.operands[1] == OperandSpec::RegMMM { if op == 20 { return Err(DecodeError::InvalidOperand); } else { // fix the register to XMM instruction.regs[1].bank = RegisterBank::X; } } else { if instruction.opcode == Opcode::MOVDDUP { instruction.mem_size = 8; } else { instruction.mem_size = 16; } } }, 22 => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u32; if instruction.operands[1] != OperandSpec::RegMMM { if instruction.opcode == Opcode::CMPSS { instruction.mem_size = 4; } else if instruction.opcode == Opcode::CMPSD { instruction.mem_size = 8; } else { instruction.mem_size = 16; } } instruction.operands[2] = OperandSpec::ImmI8; instruction.operand_count = 3; }, 23 => { instruction.regs[0] = RegSpec::al(); instruction.operands[1] = OperandSpec::ImmI8; instruction.operand_count = 2; } 24 => { let opwidth = if instruction.prefixes.operand_size() { instruction.regs[0] = RegSpec::from_parts(0, RegisterBank::W); 2 } else { instruction.regs[0] = RegSpec::from_parts(0, RegisterBank::D); 4 }; instruction.imm = read_imm_signed(words, opwidth)? as u32; instruction.operands[1] = match opwidth { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, _ => unsafe { unreachable_unchecked() } }; instruction.operand_count = 2; } 25 => { let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; instruction.imm = read_imm_unsigned(words, opwidth)?; instruction.operands[0] = match opwidth { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, _ => unsafe { unreachable_unchecked() } }; instruction.operand_count = 1; }, 26 => { instruction.operands[0] = mem_oper; instruction.opcode = base_opcode_map((modrm >> 3) & 7); instruction.operands[1] = OperandSpec::ImmI8; instruction.operand_count = 2; }, 27 => { instruction.imm = 3; instruction.operands[0] = OperandSpec::ImmU8; instruction.operand_count = 1; } 28 => { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Ok(()); }, 29 => { instruction.regs[0].bank = RegisterBank::X; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; if instruction.operands[0] == OperandSpec::RegMMM { // fix the register to XMM if instruction.opcode == Opcode::MOVD { instruction.regs[1].bank = RegisterBank::D; } else { instruction.regs[1].bank = RegisterBank::X; } } else { instruction.mem_size = 4; } }, 30 => { instruction.operands[0] = mem_oper; let r = (modrm >> 3) & 7; if r >= 1 { // TODO: this is where XOP decoding would occur return Err(DecodeError::IncompleteDecoder); } instruction.opcode = [ Opcode::POP, ][r as usize]; instruction.operand_count = 1; } 31 => { instruction.regs[0].bank = RegisterBank::X; instruction.operand_count = 2; if instruction.operands[1] == OperandSpec::RegMMM { // fix the register to XMM instruction.regs[1].bank = RegisterBank::X; } else { instruction.mem_size = 4; } }, _ => { let operand_code: OperandCode = unsafe { core::mem::transmute(operand_code.bits()) }; unlikely_operands(decoder, words, instruction, operand_code, mem_oper)?; } }; } Ok(()) } fn unlikely_operands::Address, ::Word>>(decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, mem_oper: OperandSpec) -> Result<(), DecodeError> { match operand_code { OperandCode::G_E_mm_Ib => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E_mm(words, instruction, modrm)?; instruction.regs[0] = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 }; if instruction.operands[1] == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::MM; } else { instruction.mem_size = 8; } instruction.imm = read_num(words, 1)? as u8 as u32; instruction.operands[2] = OperandSpec::ImmI8; instruction.operand_count = 3; } OperandCode::G_Ev_xmm_Ib => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; instruction.regs[0] = RegSpec { bank: RegisterBank::X, num: (modrm >> 3) & 7 }; instruction.imm = read_num(words, 1)? as u8 as u32; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = match instruction.opcode { Opcode::PEXTRB => 1, Opcode::PEXTRW => 2, Opcode::PEXTRD => 4, Opcode::EXTRACTPS => 4, Opcode::INSERTPS => 4, Opcode::PINSRB => 1, Opcode::PINSRW => 2, Opcode::PINSRD => 4, _ => 8, }; } instruction.operands[2] = OperandSpec::ImmI8; instruction.operand_count = 3; } OperandCode::PMOVX_E_G_xmm => { let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec { bank: RegisterBank::X, num: (modrm >> 3) & 7 }; instruction.operands[1] = OperandSpec::RegRRR; instruction.operands[0] = read_E_xmm(words, instruction, modrm)?; if instruction.operands[0] != OperandSpec::RegMMM { if [].contains(&instruction.opcode) { instruction.mem_size = 2; } else { instruction.mem_size = 8; } } else { if instruction.opcode == Opcode::MOVLPD || instruction.opcode == Opcode::MOVHPD || instruction.opcode == Opcode::MOVHPS { return Err(DecodeError::InvalidOperand); } } } OperandCode::PMOVX_G_E_xmm => { let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec { bank: RegisterBank::X, num: (modrm >> 3) & 7 }; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; if instruction.opcode == Opcode::CVTTSD2SI || instruction.opcode == Opcode::CVTSD2SI { instruction.regs[0].bank = RegisterBank::D; } if instruction.operands[1] != OperandSpec::RegMMM { if [Opcode::PMOVSXBQ, Opcode::PMOVZXBQ].contains(&instruction.opcode) { instruction.mem_size = 2; } else if [Opcode::PMOVZXBD, Opcode::UCOMISS, Opcode::COMISS, Opcode::CVTSS2SD].contains(&instruction.opcode) { instruction.mem_size = 4; } else { instruction.mem_size = 8; } } else { if instruction.opcode == Opcode::MOVLPD || instruction.opcode == Opcode::MOVHPD { return Err(DecodeError::InvalidOperand); } } } OperandCode::INV_Gv_M => { let modrm = read_modrm(words)?; if modrm >= 0xc0 { return Err(DecodeError::InvalidOperand); } instruction.regs[0] = RegSpec { bank: RegisterBank::D, num: (modrm >> 3) & 7 }; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = read_M(words, instruction, modrm)?; if [Opcode::LFS, Opcode::LGS, Opcode::LSS].contains(&instruction.opcode) { if instruction.prefixes.operand_size() { instruction.mem_size = 4; } else { instruction.mem_size = 6; } } else if [Opcode::ENQCMD, Opcode::ENQCMDS].contains(&instruction.opcode) { instruction.mem_size = 64; } else { instruction.mem_size = 16; } } OperandCode::ModRM_0xc4 => { let modrm = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; 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. return Err(DecodeError::InvalidPrefixes); } else { vex::three_byte_vex(words, modrm, instruction)?; if decoder != &InstDecoder::default() { decoder.revise_instruction(instruction)?; } return Ok(()); } } else { // LES instruction.regs[0] = 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(words, instruction, modrm)?; if instruction.prefixes.operand_size() { instruction.mem_size = 4; } else { instruction.mem_size = 6; } } }, OperandCode::ModRM_0xc5 => { let modrm = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; 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. return Err(DecodeError::InvalidPrefixes); } else { vex::two_byte_vex(words, modrm, instruction)?; if decoder != &InstDecoder::default() { decoder.revise_instruction(instruction)?; } return Ok(()); } } else { // LDS instruction.regs[0] = 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(words, instruction, modrm)?; if instruction.prefixes.operand_size() { instruction.mem_size = 4; } else { instruction.mem_size = 6; } } }, OperandCode::G_U_xmm_Ub => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; if instruction.operands[1] != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); instruction.imm = read_num(words, 1)? as u8 as u32; instruction.operands[2] = OperandSpec::ImmU8; instruction.operand_count = 3; } OperandCode::ModRM_0xf20f78 => { instruction.opcode = Opcode::INSERTQ; let modrm = read_modrm(words)?; if modrm < 0b11_000_000 { return Err(DecodeError::InvalidOperand); } instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); instruction.operands[1] = OperandSpec::RegMMM; instruction.regs[1] = RegSpec::from_parts(modrm & 7, RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u32; instruction.disp = read_num(words, 1)? as u8 as u32; instruction.operands[2] = OperandSpec::ImmU8; instruction.operands[3] = OperandSpec::ImmInDispField; instruction.operand_count = 4; } OperandCode::ModRM_0x660f78 => { instruction.opcode = Opcode::EXTRQ; let modrm = read_modrm(words)?; if modrm < 0b11_000_000 { return Err(DecodeError::InvalidOperand); } if modrm >= 0b11_001_000 { return Err(DecodeError::InvalidOperand); } instruction.operands[0] = OperandSpec::RegMMM; instruction.regs[1] = RegSpec::from_parts(modrm & 7, RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u32; instruction.disp = read_num(words, 1)? as u8 as u32; instruction.operands[1] = OperandSpec::ImmU8; instruction.operands[2] = OperandSpec::ImmInDispField; instruction.operand_count = 3; } OperandCode::G_E_xmm_Ub => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u32; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 16; } instruction.operands[2] = OperandSpec::ImmU8; instruction.operand_count = 3; } OperandCode::Gd_Ed => { instruction.regs[0].bank = RegisterBank::D; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } instruction.operands[1] = mem_oper; instruction.operand_count = 2; } OperandCode::Md_Gd => { instruction.regs[0].bank = RegisterBank::D; if mem_oper == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = mem_oper; instruction.operand_count = 2; } OperandCode::G_U_xmm => { instruction.regs[0].bank = RegisterBank::X; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.regs[1].bank = RegisterBank::X; instruction.operand_count = 2; }, OperandCode::Gv_Ev_Ib => { instruction.operands[2] = OperandSpec::ImmI8; instruction.operand_count = 3; } OperandCode::Gv_Ev_Iv => { let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; instruction.imm = read_imm_signed(words, opwidth)? as u32; instruction.operands[2] = match opwidth { 2 => OperandSpec::ImmI16, 4 => OperandSpec::ImmI32, _ => unsafe { unreachable_unchecked() } }; instruction.operand_count = 3; } OperandCode::Ev_Gv_Ib => { instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[2] = OperandSpec::ImmI8; instruction.operand_count = 3; } OperandCode::Ev_Gv_CL => { instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; instruction.operands[2] = OperandSpec::RegVex; instruction.regs[3] = RegSpec::cl(); instruction.operand_count = 3; } OperandCode::G_mm_Ew_Ib => { let modrm = read_modrm(words)?; instruction.operands[1] = read_E(words, instruction, modrm, 4)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::MM); if instruction.operands[1] == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 2; } instruction.imm = read_num(words, 1)? as u8 as u32; instruction.operands[2] = OperandSpec::ImmI8; instruction.operand_count = 3; } OperandCode::G_E_mm => { instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; } else { if [Opcode::PUNPCKLBW, Opcode::PUNPCKLWD, Opcode::PUNPCKLDQ].contains(&instruction.opcode) { instruction.mem_size = 4; } else { instruction.mem_size = 8; } } instruction.operand_count = 2; }, OperandCode::G_U_mm => { instruction.regs[0].bank = RegisterBank::D; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; instruction.operand_count = 2; }, OperandCode::Gv_Ew_LSL => { let modrm = read_modrm(words)?; if instruction.prefixes.operand_size() { instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::W); } else { instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); }; instruction.operands[1] = read_E(words, instruction, modrm, 2)?; // lsl is weird. the full register width is written, but only the low 16 bits are used. if instruction.operands[1] == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 2; } instruction.operand_count = 2; }, OperandCode::Gd_Ev => { let modrm = read_modrm(words)?; let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; instruction.operands[1] = read_E(words, instruction, modrm, opwidth)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); instruction.operand_count = 2; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = opwidth; } }, op @ OperandCode::AL_Ob | op @ OperandCode::AX_Ov => { instruction.regs[0] = match op { OperandCode::AL_Ob => { instruction.mem_size = 1; RegSpec::al() }, OperandCode::AX_Ov => { if instruction.prefixes.operand_size() { instruction.mem_size = 2; RegSpec::ax() } else { instruction.mem_size = 4; RegSpec::eax() } } _ => { unsafe { unreachable_unchecked() } } }; let addr_width = if instruction.prefixes.address_size() { 2 } else { 4 }; let imm = read_num(words, 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.regs[0] = match op { OperandCode::Ob_AL => { instruction.mem_size = 1; RegSpec::al() }, OperandCode::Ov_AX => { if instruction.prefixes.operand_size() { instruction.mem_size = 2; RegSpec::ax() } else { instruction.mem_size = 4; RegSpec::eax() } } _ => { unsafe { unreachable_unchecked() } } }; let addr_width = if instruction.prefixes.address_size() { 2 } else { 4 }; let imm = read_num(words, 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(words, 2)?; instruction.imm = read_num(words, 1)?; instruction.operands[0] = OperandSpec::ImmInDispField; instruction.operands[1] = OperandSpec::ImmU8; instruction.operand_count = 2; } OperandCode::Fw => { if instruction.prefixes.operand_size() { instruction.opcode = Opcode::IRET; } else { instruction.opcode = Opcode::IRETD; } instruction.operand_count = 0; } OperandCode::G_mm_U_mm => { instruction.regs[0].bank = RegisterBank::MM; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; instruction.regs[0].num &= 0b111; instruction.operand_count = 2; }, OperandCode::E_G_q => { if instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOpcode); } let modrm = read_modrm(words)?; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); instruction.operand_count = 2; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 8; } } OperandCode::G_E_q => { if instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOpcode); } let modrm = read_modrm(words)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::D); instruction.operands[1] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 8; } instruction.operand_count = 2; } OperandCode::G_Mq_mm => { instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = mem_oper; instruction.regs[0].bank = RegisterBank::MM; if mem_oper == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 8; } instruction.regs[0].num &= 0b111; instruction.operand_count = 2; }, OperandCode::MOVQ_f30f => { instruction.operand_count = 2; let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec::from_parts((modrm >> 3) & 7, RegisterBank::X); instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 8; } } OperandCode::ModRM_0x0f0d => { let modrm = read_modrm(words)?; let r = (modrm >> 3) & 0b111; let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; match r { 1 => { instruction.opcode = Opcode::PREFETCHW; } _ => { instruction.opcode = Opcode::NOP; } } instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 64; } instruction.operand_count = 1; } OperandCode::ModRM_0x0f0f => { // 3dnow instructions are WILD, the opcode is encoded as an imm8 trailing the // instruction. let modrm = read_modrm(words)?; instruction.operands[1] = read_E_mm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec { bank: RegisterBank::MM, num: (modrm >> 3) & 7 }; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 8; } let opcode = read_modrm(words)?; match opcode { 0x0c => { instruction.opcode = Opcode::PI2FW; } 0x0d => { instruction.opcode = Opcode::PI2FD; } 0x1c => { instruction.opcode = Opcode::PF2IW; } 0x1d => { instruction.opcode = Opcode::PF2ID; } 0x8a => { instruction.opcode = Opcode::PFNACC; } 0x8e => { instruction.opcode = Opcode::PFPNACC; } 0x90 => { instruction.opcode = Opcode::PFCMPGE; } 0x94 => { instruction.opcode = Opcode::PFMIN; } 0x96 => { instruction.opcode = Opcode::PFRCP; } 0x97 => { instruction.opcode = Opcode::PFRSQRT; } 0x9a => { instruction.opcode = Opcode::PFSUB; } 0x9e => { instruction.opcode = Opcode::PFADD; } 0xa0 => { instruction.opcode = Opcode::PFCMPGT; } 0xa4 => { instruction.opcode = Opcode::PFMAX; } 0xa6 => { instruction.opcode = Opcode::PFRCPIT1; } 0xa7 => { instruction.opcode = Opcode::PFRSQIT1; } 0xaa => { instruction.opcode = Opcode::PFSUBR; } 0xae => { instruction.opcode = Opcode::PFACC; } 0xb0 => { instruction.opcode = Opcode::PFCMPEQ; } 0xb4 => { instruction.opcode = Opcode::PFMUL; } 0xb6 => { instruction.opcode = Opcode::PFRCPIT2; } 0xb7 => { instruction.opcode = Opcode::PMULHRW; } 0xbb => { instruction.opcode = Opcode::PSWAPD; } 0xbf => { instruction.opcode = Opcode::PAVGUSB; } _ => { return Err(DecodeError::InvalidOpcode); } } } OperandCode::ModRM_0x0fc7 => { if instruction.prefixes.repnz() { let modrm = read_modrm(words)?; let is_reg = (modrm & 0xc0) == 0xc0; let r = (modrm >> 3) & 7; match r { 1 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.opcode = Opcode::CMPXCHG8B; instruction.mem_size = 8; instruction.operand_count = 1; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; } return Ok(()); } _ => { return Err(DecodeError::InvalidOperand); } } } if instruction.prefixes.operand_size() { let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; let modrm = read_modrm(words)?; let is_reg = (modrm & 0xc0) == 0xc0; let r = (modrm >> 3) & 7; match r { 1 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.opcode = Opcode::CMPXCHG8B; instruction.mem_size = 8; instruction.operand_count = 1; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; } return Ok(()); } 6 => { instruction.opcode = Opcode::VMCLEAR; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; if instruction.operands[0] == OperandSpec::RegMMM { // this would be invalid as `vmclear`, so fall back to the parse as // 66-prefixed rdrand. this is a register operand, so just demote it to the // word-form operand: instruction.regs[1] = RegSpec { bank: RegisterBank::W, num: instruction.regs[1].num }; instruction.opcode = Opcode::RDRAND; } else { instruction.mem_size = 8; } instruction.operand_count = 1; return Ok(()); } 7 => { instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; if instruction.operands[0] == OperandSpec::RegMMM { // this would be invalid as `vmclear`, so fall back to the parse as // 66-prefixed rdrand. this is a register operand, so just demote it to the // word-form operand: instruction.regs[1] = RegSpec { bank: RegisterBank::W, num: instruction.regs[1].num }; instruction.opcode = Opcode::RDSEED; } else { return Err(DecodeError::InvalidOpcode); } instruction.operand_count = 1; return Ok(()); } _ => { return Err(DecodeError::InvalidOpcode); } } } if instruction.prefixes.rep() { let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; let modrm = read_modrm(words)?; let is_reg = (modrm & 0xc0) == 0xc0; let r = (modrm >> 3) & 7; match r { 1 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.opcode = Opcode::CMPXCHG8B; instruction.mem_size = 8; instruction.operand_count = 1; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; } } 6 => { instruction.opcode = Opcode::VMXON; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; if instruction.operands[0] == OperandSpec::RegMMM { // invalid as `vmxon`, reg-form is `senduipi` instruction.opcode = Opcode::SENDUIPI; // and the operand is always a dword register instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 8; } instruction.operand_count = 1; } 7 => { instruction.opcode = Opcode::RDPID; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.operand_count = 1; } _ => { return Err(DecodeError::InvalidOpcode); } } return Ok(()); } let modrm = read_modrm(words)?; let is_reg = (modrm & 0xc0) == 0xc0; let r = (modrm >> 3) & 0b111; let opcode = match r { 0b001 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 8; Opcode::CMPXCHG8B } } 0b011 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 63; Opcode::XRSTORS } } 0b100 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 63; Opcode::XSAVEC } } 0b101 => { if is_reg { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 63; Opcode::XSAVES } } 0b110 => { if is_reg { Opcode::RDRAND } else { instruction.mem_size = 8; Opcode::VMPTRLD } } 0b111 => { if is_reg { Opcode::RDSEED } else { instruction.mem_size = 8; Opcode::VMPTRST } } _ => { return Err(DecodeError::InvalidOperand); } }; instruction.opcode = opcode; instruction.operand_count = 1; let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; }, OperandCode::ModRM_0x0f71 => { if instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOperand); } instruction.operand_count = 2; let modrm = read_modrm(words)?; if modrm & 0xc0 != 0xc0 { return Err(DecodeError::InvalidOperand); } let r = (modrm >> 3) & 7; match r { 2 => { instruction.opcode = Opcode::PSRLW; } 4 => { instruction.opcode = Opcode::PSRAW; } 6 => { instruction.opcode = Opcode::PSLLW; } _ => { return Err(DecodeError::InvalidOpcode); } } if instruction.prefixes.operand_size() { instruction.regs[1] = RegSpec { bank: RegisterBank::X, num: modrm & 7 }; } else { instruction.regs[1] = RegSpec { bank: RegisterBank::MM, num: modrm & 7 }; } instruction.operands[0] = OperandSpec::RegMMM; instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[1] = OperandSpec::ImmU8; }, OperandCode::ModRM_0x0f72 => { if instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOperand); } instruction.operand_count = 2; let modrm = read_modrm(words)?; if modrm & 0xc0 != 0xc0 { return Err(DecodeError::InvalidOperand); } let r = (modrm >> 3) & 7; match r { 2 => { instruction.opcode = Opcode::PSRLD; } 4 => { instruction.opcode = Opcode::PSRAD; } 6 => { instruction.opcode = Opcode::PSLLD; } _ => { return Err(DecodeError::InvalidOpcode); } } if instruction.prefixes.operand_size() { instruction.regs[1] = RegSpec { bank: RegisterBank::X, num: modrm & 7 }; } else { instruction.regs[1] = RegSpec { bank: RegisterBank::MM, num: modrm & 7 }; } instruction.operands[0] = OperandSpec::RegMMM; instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[1] = OperandSpec::ImmU8; }, OperandCode::ModRM_0x0f73 => { if instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOperand); } instruction.operand_count = 2; let modrm = read_modrm(words)?; if modrm & 0xc0 != 0xc0 { return Err(DecodeError::InvalidOperand); } let r = (modrm >> 3) & 7; match r { 2 => { instruction.opcode = Opcode::PSRLQ; } 3 => { if !instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::PSRLDQ; } 6 => { instruction.opcode = Opcode::PSLLQ; } 7 => { if !instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::PSLLDQ; } _ => { return Err(DecodeError::InvalidOpcode); } } if instruction.prefixes.operand_size() { instruction.regs[1] = RegSpec { bank: RegisterBank::X, num: modrm & 7 }; } else { instruction.regs[1] = RegSpec { bank: RegisterBank::MM, num: modrm & 7 }; } instruction.operands[0] = OperandSpec::RegMMM; instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[1] = OperandSpec::ImmU8; }, OperandCode::ModRM_0xf30f38d8 => { let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; instruction.mem_size = 63; match r { 0b000 => { if modrm >= 0b11_000_000 { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 48; instruction.opcode = Opcode::AESENCWIDE128KL; instruction.operands[0] = read_M(words, instruction, modrm)?; return Ok(()); } 0b001 => { if modrm >= 0b11_000_000 { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 48; instruction.opcode = Opcode::AESDECWIDE128KL; instruction.operands[0] = read_M(words, instruction, modrm)?; return Ok(()); } 0b010 => { if modrm >= 0b11_000_000 { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 64; instruction.opcode = Opcode::AESENCWIDE256KL; instruction.operands[0] = read_M(words, instruction, modrm)?; return Ok(()); } 0b011 => { if modrm >= 0b11_000_000 { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 64; instruction.opcode = Opcode::AESDECWIDE256KL; instruction.operands[0] = read_M(words, instruction, modrm)?; return Ok(()); } _ => { return Err(DecodeError::InvalidOpcode); } } } OperandCode::ModRM_0xf30f38dc => { read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; if let OperandSpec::RegMMM = instruction.operands[1] { instruction.opcode = Opcode::LOADIWKEY; } else { instruction.mem_size = 48; instruction.opcode = Opcode::AESENC128KL; } } OperandCode::ModRM_0xf30f38dd => { read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; if let OperandSpec::RegMMM = instruction.operands[1] { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 48; instruction.opcode = Opcode::AESDEC128KL; } } OperandCode::ModRM_0xf30f38de => { read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; if let OperandSpec::RegMMM = instruction.operands[1] { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 64; instruction.opcode = Opcode::AESENC256KL; } } OperandCode::ModRM_0xf30f38df => { read_operands(decoder, words, instruction, OperandCode::G_E_xmm)?; if let OperandSpec::RegMMM = instruction.operands[1] { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 64; instruction.opcode = Opcode::AESDEC256KL; } } OperandCode::ModRM_0xf30f38fa => { instruction.opcode = Opcode::ENCODEKEY128; read_operands(decoder, words, instruction, OperandCode::G_U_xmm)?; instruction.regs[0].bank = RegisterBank::D; instruction.regs[1].bank = RegisterBank::D; } OperandCode::ModRM_0xf30f38fb => { instruction.opcode = Opcode::ENCODEKEY256; read_operands(decoder, words, instruction, OperandCode::G_U_xmm)?; instruction.regs[0].bank = RegisterBank::D; instruction.regs[1].bank = RegisterBank::D; } OperandCode::ModRM_0xf30f3af0 => { let modrm = words.next().ok().ok_or(DecodeError::ExhaustedInput)?; if modrm & 0xc0 != 0xc0 { return Err(DecodeError::InvalidOpcode); // invalid } instruction.opcode = Opcode::HRESET; instruction.imm = read_num(words, 1)?; instruction.operands[0] = OperandSpec::ImmU8; } OperandCode::G_mm_Ed => { instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 4; } } OperandCode::G_mm_E => { instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; } else { instruction.mem_size = 8; } } OperandCode::Ed_G_mm => { instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = mem_oper; instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 4; } } OperandCode::Ed_G_xmm => { instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = mem_oper; instruction.regs[0].bank = RegisterBank::Y; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 4; } } OperandCode::E_G_mm => { instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = mem_oper; instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; } else { instruction.mem_size = 8; } } OperandCode::G_xmm_Ew_Ib => { instruction.operands[2] = OperandSpec::ImmU8; instruction.operand_count = 3; instruction.imm = read_num(words, 1)?; instruction.regs[0].bank = RegisterBank::X; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 2; } }, OperandCode::G_xmm_Ed => { instruction.regs[0].bank = RegisterBank::X; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::D; } else { instruction.mem_size = 4; } }, OperandCode::G_mm_E_xmm => { instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::X; } else { instruction.mem_size = 16; } }, op @ OperandCode::G_xmm_U_mm | op @ OperandCode::G_xmm_E_mm => { instruction.regs[0].bank = RegisterBank::X; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; } else { if op == OperandCode::G_xmm_U_mm { return Err(DecodeError::InvalidOperand); } else { instruction.mem_size = 8; } } }, OperandCode::Rv_Gmm_Ib => { instruction.operands[2] = OperandSpec::ImmU8; instruction.operand_count = 3; instruction.imm = read_num(words, 1)?; instruction.regs[0].bank = RegisterBank::D; if mem_oper == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::MM; instruction.regs[1].num &= 0b111; } else { return Err(DecodeError::InvalidOperand); } } OperandCode::U_mm_G_xmm => { instruction.regs[1].bank = RegisterBank::X; if mem_oper == OperandSpec::RegMMM { instruction.regs[0].bank = RegisterBank::MM; instruction.regs[0].num &= 0b111; } else { return Err(DecodeError::InvalidOperand); } } // sure hope these aren't backwards huh OperandCode::AL_Xb => { instruction.regs[0] = RegSpec::al(); if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::si(); } else { instruction.regs[1] = RegSpec::esi(); } instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::Deref; instruction.mem_size = 1; instruction.operand_count = 2; } OperandCode::Yb_Xb => { if instruction.prefixes.address_size() { instruction.operands[0] = OperandSpec::Deref_di; instruction.operands[1] = OperandSpec::Deref_si; } else { instruction.operands[0] = OperandSpec::Deref_edi; instruction.operands[1] = OperandSpec::Deref_esi; } instruction.mem_size = 1; instruction.operand_count = 2; } OperandCode::Yb_AL => { instruction.regs[0] = RegSpec::al(); if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::di(); } else { instruction.regs[1] = RegSpec::edi(); } instruction.operands[0] = OperandSpec::Deref; instruction.operands[1] = OperandSpec::RegRRR; instruction.mem_size = 1; instruction.operand_count = 2; } OperandCode::AX_Xv => { instruction.regs[0] = if instruction.prefixes.operand_size() { instruction.mem_size = 2; RegSpec::ax() } else { instruction.mem_size = 4; RegSpec::eax() }; if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::si(); } else { instruction.regs[1] = RegSpec::esi(); } instruction.operands[1] = OperandSpec::Deref; } OperandCode::Yv_AX => { instruction.regs[0] = if instruction.prefixes.operand_size() { instruction.mem_size = 2; RegSpec::ax() } else { instruction.mem_size = 4; RegSpec::eax() }; if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::di(); } else { instruction.regs[1] = RegSpec::edi(); } instruction.operands[0] = OperandSpec::Deref; instruction.operands[1] = OperandSpec::RegRRR; } OperandCode::Yv_Xv => { instruction.mem_size = if instruction.prefixes.operand_size() { 2 } else { 4 }; if instruction.prefixes.address_size() { instruction.operands[0] = OperandSpec::Deref_di; instruction.operands[1] = OperandSpec::Deref_si; } else { instruction.operands[0] = OperandSpec::Deref_edi; instruction.operands[1] = OperandSpec::Deref_esi; } } OperandCode::ModRM_0x0f12 => { instruction.regs[0].bank = RegisterBank::X; instruction.operands[1] = mem_oper; if instruction.operands[1] == OperandSpec::RegMMM { if instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOpcode); } instruction.regs[1].bank = RegisterBank::X; instruction.opcode = Opcode::MOVHLPS; } else { instruction.mem_size = 8; if instruction.prefixes.operand_size() { instruction.opcode = Opcode::MOVLPD; } else { instruction.opcode = Opcode::MOVLPS; } } } OperandCode::ModRM_0x0f16 => { instruction.regs[0].bank = RegisterBank::X; instruction.operands[1] = mem_oper; if instruction.operands[1] == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::X; if instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::MOVLHPS; } else { instruction.mem_size = 8; if instruction.prefixes.operand_size() { instruction.opcode = Opcode::MOVHPD; } else { instruction.opcode = Opcode::MOVHPS; } } } OperandCode::ModRM_0x0f18 => { let rrr = instruction.regs[0].num & 0b111; instruction.operands[0] = mem_oper; instruction.operand_count = 1; instruction.opcode = if mem_oper == OperandSpec::RegMMM && rrr < 4 { Opcode::NOP } else { match rrr { 0 => Opcode::PREFETCHNTA, 1 => Opcode::PREFETCH0, 2 => Opcode::PREFETCH1, 3 => Opcode::PREFETCH2, _ => Opcode::NOP, } }; if mem_oper != OperandSpec::RegMMM { instruction.mem_size = 64; } } OperandCode::Gd_U_xmm => { if instruction.operands[1] != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.regs[0].bank = RegisterBank::D; instruction.regs[1].bank = RegisterBank::X; } OperandCode::Gv_E_xmm => { if instruction.operands[1] == OperandSpec::RegMMM { instruction.regs[1].bank = RegisterBank::X; } else { instruction.mem_size = 4; } } OperandCode::M_G_xmm => { instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = mem_oper; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } else { if instruction.opcode == Opcode::MOVNTSS { instruction.mem_size = 4; } else if instruction.opcode == Opcode::MOVNTPD || instruction.opcode == Opcode::MOVNTDQ || instruction.opcode == Opcode::MOVNTPS { instruction.mem_size = 16; } else { instruction.mem_size = 8; } } instruction.regs[0].bank = RegisterBank::X; } OperandCode::Ew_Gw => { let modrm = read_modrm(words)?; instruction.regs[0] = RegSpec { bank: RegisterBank::W, num: (modrm >> 3) & 7 }; instruction.operands[0] = read_E(words, instruction, modrm, 2)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.mem_size = 2; instruction.operand_count = 2; }, OperandCode::Ew_Sw => { let opwidth = 2; let modrm = read_modrm(words)?; // check r if ((modrm >> 3) & 7) > 5 { // return Err(()); //Err("Invalid r".to_owned()); return Err(DecodeError::InvalidOperand); } instruction.regs[0] = RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; let mod_bits = modrm >> 6; if mod_bits == 0b11 { instruction.regs[1] = RegSpec { bank: RegisterBank::W, num: modrm & 7}; instruction.operands[0] = OperandSpec::RegMMM; } else { instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; instruction.mem_size = 2; } }, OperandCode::Sw_Ew => { let modrm = read_modrm(words)?; // check r if ((modrm >> 3) & 7) > 5 { // return Err(()); // Err("Invalid r".to_owned()); return Err(DecodeError::InvalidOperand); } instruction.regs[0] = RegSpec { bank: RegisterBank::S, num: (modrm >> 3) & 7 }; // quoth the manual: // ``` // The MOV instruction cannot be used to load the CS register. Attempting to do so // results in an invalid opcode excep-tion (#UD). To load the CS register, use the far // JMP, CALL, or RET instruction. // ``` if instruction.regs[0].num == 1 { return Err(DecodeError::InvalidOperand); } instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 2; let mod_bits = modrm >> 6; if mod_bits == 0b11 { instruction.regs[1] = RegSpec { bank: RegisterBank::W, num: modrm & 7}; instruction.operands[1] = OperandSpec::RegMMM; } else { instruction.operands[1] = read_M(words, instruction, modrm)?; instruction.mem_size = 2; } }, OperandCode::CVT_AA => { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; instruction.opcode = if !instruction.prefixes.operand_size() { Opcode::CWDE } else { Opcode::CBW }; } OperandCode::CVT_DA => { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; instruction.opcode = if !instruction.prefixes.operand_size() { Opcode::CDQ } else { Opcode::CWD }; } OperandCode::Ib => { instruction.operands[0] = OperandSpec::ImmU8; instruction.operand_count = 1; } OperandCode::Iw => { instruction.imm = read_imm_unsigned(words, 2)?; instruction.operands[0] = OperandSpec::ImmU16; instruction.operand_count = 1; } OperandCode::ModRM_0x0f00 => { instruction.operand_count = 1; let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; if r == 0 { instruction.opcode = Opcode::SLDT; } else if r == 1 { instruction.opcode = Opcode::STR; } else if r == 2 { instruction.opcode = Opcode::LLDT; } else if r == 3 { instruction.opcode = Opcode::LTR; } else if r == 4 { instruction.opcode = Opcode::VERR; } else if r == 5 { instruction.opcode = Opcode::VERW; } else if r == 6 { // TODO: this would be jmpe for x86-on-itanium systems. instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOperand); } else if r == 7 { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOperand); } else { unreachable!("r <= 8"); } instruction.operands[0] = read_E(words, instruction, modrm, 2)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 2; } } OperandCode::ModRM_0x0f01 => { let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; if r == 0 { let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { if instruction.prefixes.rep() || instruction.prefixes.repnz() || instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; match m { 0b000 => { instruction.opcode = Opcode::ENCLV; }, 0b001 => { instruction.opcode = Opcode::VMCALL; }, 0b010 => { instruction.opcode = Opcode::VMLAUNCH; }, 0b011 => { instruction.opcode = Opcode::VMRESUME; }, 0b100 => { instruction.opcode = Opcode::VMXOFF; }, _ => { return Err(DecodeError::InvalidOpcode); } } } else { instruction.opcode = Opcode::SGDT; instruction.operand_count = 1; instruction.mem_size = 63; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; } } else if r == 1 { let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; if instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOpcode); } if instruction.prefixes.operand_size() { match m { 0b100 => { instruction.opcode = Opcode::TDCALL; } 0b101 => { instruction.opcode = Opcode::SEAMRET; } 0b110 => { instruction.opcode = Opcode::SEAMOPS; } 0b111 => { instruction.opcode = Opcode::SEAMCALL; } _ => { return Err(DecodeError::InvalidOpcode); } } } else { match m { 0b000 => { instruction.opcode = Opcode::MONITOR; } 0b001 => { instruction.opcode = Opcode::MWAIT; }, 0b010 => { instruction.opcode = Opcode::CLAC; } 0b011 => { instruction.opcode = Opcode::STAC; } 0b111 => { instruction.opcode = Opcode::ENCLS; } _ => { return Err(DecodeError::InvalidOpcode); } } } } else { instruction.opcode = Opcode::SIDT; instruction.operand_count = 1; instruction.mem_size = 63; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; } } else if r == 2 { let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { if instruction.prefixes.rep() || instruction.prefixes.repnz() || instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; match m { 0b000 => { instruction.opcode = Opcode::XGETBV; } 0b001 => { instruction.opcode = Opcode::XSETBV; } 0b100 => { instruction.opcode = Opcode::VMFUNC; } 0b101 => { instruction.opcode = Opcode::XEND; } 0b110 => { instruction.opcode = Opcode::XTEST; } 0b111 => { instruction.opcode = Opcode::ENCLU; } _ => { return Err(DecodeError::InvalidOpcode); } } } else { instruction.opcode = Opcode::LGDT; instruction.operand_count = 1; instruction.mem_size = 63; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; } } else if r == 3 { let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { match m { 0b000 => { instruction.opcode = Opcode::VMRUN; instruction.operand_count = 1; instruction.regs[0] = RegSpec::eax(); instruction.operands[0] = OperandSpec::RegRRR; }, 0b001 => { instruction.opcode = Opcode::VMMCALL; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; }, 0b010 => { instruction.opcode = Opcode::VMLOAD; instruction.operand_count = 1; instruction.regs[0] = RegSpec::eax(); instruction.operands[0] = OperandSpec::RegRRR; }, 0b011 => { instruction.opcode = Opcode::VMSAVE; instruction.operand_count = 1; instruction.regs[0] = RegSpec::eax(); instruction.operands[0] = OperandSpec::RegRRR; }, 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 => { instruction.opcode = Opcode::SKINIT; instruction.operand_count = 1; instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::eax(); }, 0b111 => { instruction.opcode = Opcode::INVLPGA; instruction.operand_count = 2; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegMMM; instruction.regs[0] = RegSpec::eax(); instruction.regs[1] = RegSpec::ecx(); }, _ => { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOperand); } } } else { instruction.opcode = Opcode::LIDT; instruction.operand_count = 1; instruction.mem_size = 63; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; } } else if r == 4 { // TODO: this permits storing only to word-size registers // spec suggets this might do something different for f.ex rdi? instruction.opcode = Opcode::SMSW; instruction.operand_count = 1; instruction.mem_size = 2; instruction.operands[0] = read_E(words, instruction, modrm, 2)?; } else if r == 5 { let mod_bits = modrm >> 6; if mod_bits != 0b11 { if !instruction.prefixes.rep() { return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::RSTORSSP; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; instruction.mem_size = 8; instruction.operand_count = 1; return Ok(()); } let m = modrm & 7; match m { 0b000 => { if instruction.prefixes.repnz() { instruction.opcode = Opcode::XSUSLDTRK; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Ok(()); } if !instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::SETSSBSY; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } 0b001 => { if instruction.prefixes.repnz() { instruction.opcode = Opcode::XRESLDTRK; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Ok(()); } else { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOpcode); } } 0b010 => { if !instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::SAVEPREVSSP; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } 0b100 => { if instruction.prefixes.rep() { instruction.opcode = Opcode::UIRET; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOpcode); } } 0b101 => { if instruction.prefixes.rep() { instruction.opcode = Opcode::TESTUI; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOpcode); } } 0b110 => { if instruction.prefixes.rep() { instruction.opcode = Opcode::CLUI; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Ok(()); } else if instruction.prefixes.operand_size() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::RDPKRU; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } 0b111 => { if instruction.prefixes.rep() { instruction.opcode = Opcode::STUI; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Ok(()); } else if instruction.prefixes.operand_size() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::WRPKRU; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } _ => { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; return Err(DecodeError::InvalidOpcode); } } } else if r == 6 { instruction.opcode = Opcode::LMSW; instruction.operand_count = 1; instruction.mem_size = 2; instruction.operands[0] = read_E(words, instruction, modrm, 2)?; } else if r == 7 { let mod_bits = modrm >> 6; let m = modrm & 7; if mod_bits == 0b11 { if m == 0 { // swapgs is not valid in modes other than 64-bit return Err(DecodeError::InvalidOpcode); } else if m == 1 { instruction.opcode = Opcode::RDTSCP; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else if m == 2 { instruction.opcode = Opcode::MONITORX; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else if m == 3 { instruction.opcode = Opcode::MWAITX; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else if m == 4 { instruction.opcode = Opcode::CLZERO; instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } else if m == 5 { instruction.opcode = Opcode::RDPRU; instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::ecx(); instruction.operand_count = 1; } else if m == 6 { if instruction.prefixes.rep() { if instruction.prefixes.repnz() || instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::RMPADJUST; instruction.operand_count = 0; return Ok(()); } else if instruction.prefixes.repnz() { if instruction.prefixes.rep() || instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::RMPUPDATE; instruction.operand_count = 0; return Ok(()); } else if instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::INVLPGB; instruction.operand_count = 3; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegMMM; instruction.operands[2] = OperandSpec::RegVex; instruction.regs[0] = RegSpec::eax(); instruction.regs[1] = RegSpec::edx(); instruction.regs[3] = RegSpec::ecx(); } else if m == 7 { if instruction.prefixes.rep() { if instruction.prefixes.repnz() || instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::PSMASH; instruction.operand_count = 0; return Ok(()); } else if instruction.prefixes.repnz() { if instruction.prefixes.rep() || instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::PVALIDATE; instruction.operand_count = 0; return Ok(()); } else if instruction.prefixes.operand_size() { return Err(DecodeError::InvalidOperand); } instruction.opcode = Opcode::TLBSYNC; instruction.operand_count = 0; } else { return Err(DecodeError::InvalidOpcode); } } else { instruction.opcode = Opcode::INVLPG; instruction.operand_count = 1; instruction.mem_size = 1; instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; } } else { unreachable!("r <= 8"); } } OperandCode::ModRM_0x0fae => { let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; let m = modrm & 7; if instruction.prefixes.operand_size() && !(instruction.prefixes.rep() || instruction.prefixes.repnz()) { instruction.prefixes.unset_operand_size(); if modrm < 0xc0 { instruction.opcode = match (modrm >> 3) & 7 { 6 => { Opcode::CLWB } 7 => { Opcode::CLFLUSHOPT } _ => { return Err(DecodeError::InvalidOpcode); } }; instruction.operands[0] = read_E(words, instruction, modrm, 1 /* opwidth */)?; instruction.mem_size = 64; instruction.operand_count = 1; } else { instruction.opcode = match (modrm >> 3) & 7 { 6 => { Opcode::TPAUSE } _ => { return Err(DecodeError::InvalidOpcode); } }; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; instruction.operand_count = 1; } return Ok(()); } if instruction.prefixes.repnz() { if (modrm & 0xc0) == 0xc0 { match r { 6 => { instruction.opcode = Opcode::UMWAIT; instruction.regs[0] = RegSpec { bank: RegisterBank::D, num: m, }; instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } _ => { return Err(DecodeError::InvalidOpcode); } } return Ok(()); } } if instruction.prefixes.rep() { if r == 4 { if instruction.prefixes.operand_size() { // xed specifically rejects this. seeems out of line since rep takes // precedence elsewhere, but ok i guess return Err(DecodeError::InvalidOpcode); } instruction.opcode = Opcode::PTWRITE; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 4; } instruction.operand_count = 1; return Ok(()); } if (modrm & 0xc0) == 0xc0 { match r { 0 => { instruction.opcode = Opcode::RDFSBASE; instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 1 => { instruction.opcode = Opcode::RDGSBASE; instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 2 => { instruction.opcode = Opcode::WRFSBASE; instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 3 => { instruction.opcode = Opcode::WRGSBASE; instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 5 => { instruction.opcode = Opcode::INCSSP; instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 6 => { instruction.opcode = Opcode::UMONITOR; if instruction.prefixes.address_size() { instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::W); } else { instruction.regs[1] = RegSpec::from_parts(m, RegisterBank::D); }; instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } _ => { return Err(DecodeError::InvalidOpcode); } } return Ok(()); } else { match r { 6 => { instruction.opcode = Opcode::CLRSSBSY; instruction.operands[0] = read_E(words, instruction, modrm, 4)?; instruction.operand_count = 1; instruction.mem_size = 8; return Ok(()); } _ => { return Err(DecodeError::InvalidOperand); } } } } let mod_bits = modrm >> 6; // all the 0b11 instructions are err or no-operands if mod_bits == 0b11 { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; match r { // invalid rrr for 0x0fae, mod: 11 0 | 1 | 2 | 3 | 4 => { return Err(DecodeError::InvalidOpcode); }, 5 => { instruction.opcode = Opcode::LFENCE; // Intel's manual accepts m != 0, AMD supports m != 0 though the manual // doesn't say (tested on threadripper) if !decoder.amd_quirks() && !decoder.intel_quirks() { if m != 0 { return Err(DecodeError::InvalidOperand); } } }, 6 => { instruction.opcode = Opcode::MFENCE; // Intel's manual accepts m != 0, AMD supports m != 0 though the manual // doesn't say (tested on threadripper) if !decoder.amd_quirks() && !decoder.intel_quirks() { if m != 0 { return Err(DecodeError::InvalidOperand); } } }, 7 => { instruction.opcode = Opcode::SFENCE; // Intel's manual accepts m != 0, AMD supports m != 0 though the manual // doesn't say (tested on threadripper) if !decoder.amd_quirks() && !decoder.intel_quirks() { if m != 0 { return Err(DecodeError::InvalidOperand); } } }, _ => { unsafe { unreachable_unchecked() } /* r <=7 */ } } } else { // these can't be prefixed, so says `xed` i guess. if instruction.prefixes.operand_size() || instruction.prefixes.rep() || instruction.prefixes.repnz() { return Err(DecodeError::InvalidOperand); } instruction.operand_count = 1; let (opcode, mem_size) = [ (Opcode::FXSAVE, 63), (Opcode::FXRSTOR, 63), (Opcode::LDMXCSR, 4), (Opcode::STMXCSR, 4), (Opcode::XSAVE, 63), (Opcode::XRSTOR, 63), (Opcode::XSAVEOPT, 63), (Opcode::CLFLUSH, 64), ][r as usize]; instruction.opcode = opcode; instruction.mem_size = mem_size; instruction.operands[0] = read_M(words, instruction, modrm)?; } }, OperandCode::ModRM_0x0fba => { let opwidth = if instruction.prefixes.operand_size() { 2 } else { 4 }; let modrm = read_modrm(words)?; let r = (modrm >> 3) & 7; match r { 0 | 1 | 2 | 3 => { return Err(DecodeError::InvalidOpcode); }, 4 => { instruction.opcode = Opcode::BT; } 5 => { instruction.opcode = Opcode::BTS; } 6 => { instruction.opcode = Opcode::BTR; } 7 => { instruction.opcode = Opcode::BTC; } _ => { unreachable!("r < 8"); } } instruction.operands[0] = read_E(words, instruction, modrm, opwidth)?; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = opwidth; } instruction.imm = read_imm_signed(words, 1)? as u32; instruction.operands[1] = OperandSpec::ImmI8; instruction.operand_count = 2; } op @ OperandCode::Rq_Cq_0 | op @ OperandCode::Rq_Dq_0 | op @ OperandCode::Cq_Rq_0 | op @ OperandCode::Dq_Rq_0 => { let modrm = read_modrm(words)?; let m = modrm & 7; let r = (modrm >> 3) & 7; let bank = match op { OperandCode::Rq_Cq_0 | OperandCode::Cq_Rq_0 => { if r != 0 && r != 2 && r != 3 && r != 4 { return Err(DecodeError::InvalidOperand); } RegisterBank::CR }, OperandCode::Rq_Dq_0 | OperandCode::Dq_Rq_0 => { if r > 7 { // unreachable but mirrors x86_64 code return Err(DecodeError::InvalidOperand); } RegisterBank::DR }, _ => unsafe { unreachable_unchecked() } }; let (rrr, mmm) = match op { OperandCode::Rq_Cq_0 | OperandCode::Rq_Dq_0 => (1, 0), OperandCode::Cq_Rq_0 | OperandCode::Dq_Rq_0 => (0, 1), _ => unsafe { unreachable_unchecked() } }; instruction.regs[0] = RegSpec { bank: bank, num: r }; instruction.regs[1] = RegSpec { bank: RegisterBank::D, num: m }; instruction.operands[mmm] = OperandSpec::RegMMM; instruction.operands[rrr] = OperandSpec::RegRRR; instruction.operand_count = 2; } OperandCode::FS => { instruction.regs[0] = RegSpec::fs(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } OperandCode::GS => { instruction.regs[0] = RegSpec::gs(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } OperandCode::CS => { instruction.regs[0] = RegSpec::cs(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } OperandCode::DS => { instruction.regs[0] = RegSpec::ds(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } OperandCode::ES => { instruction.regs[0] = RegSpec::es(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } OperandCode::SS => { instruction.regs[0] = RegSpec::ss(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; } OperandCode::AL_Ib => { instruction.regs[0] = RegSpec::al(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::ImmU8; instruction.operand_count = 2; } OperandCode::AX_Ib => { instruction.regs[0] = if !instruction.prefixes.operand_size() { RegSpec::eax() } else { RegSpec::ax() }; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::ImmU8; instruction.operand_count = 2; } OperandCode::Ib_AL => { instruction.regs[0] = RegSpec::al(); instruction.operands[0] = OperandSpec::ImmU8; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } OperandCode::Ib_AX => { instruction.regs[0] = if !instruction.prefixes.operand_size() { RegSpec::eax() } else { RegSpec::ax() }; instruction.operands[0] = OperandSpec::ImmU8; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } OperandCode::AX_DX => { instruction.regs[0] = if !instruction.prefixes.operand_size() { RegSpec::eax() } else { RegSpec::ax() }; instruction.regs[1] = RegSpec::dx(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegMMM; instruction.operand_count = 2; } OperandCode::AL_DX => { instruction.regs[0] = RegSpec::al(); instruction.regs[1] = RegSpec::dx(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegMMM; instruction.operand_count = 2; } OperandCode::DX_AX => { instruction.regs[0] = if !instruction.prefixes.operand_size() { RegSpec::eax() } else { RegSpec::ax() }; instruction.regs[1] = RegSpec::dx(); instruction.operands[0] = OperandSpec::RegMMM; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } OperandCode::DX_AL => { instruction.regs[0] = RegSpec::al(); instruction.regs[1] = RegSpec::dx(); instruction.operands[0] = OperandSpec::RegMMM; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; } OperandCode::Yb_DX => { instruction.regs[0] = RegSpec::dl(); instruction.regs[1] = RegSpec::edi(); instruction.operands[0] = OperandSpec::Deref; instruction.operands[1] = OperandSpec::RegRRR; instruction.operand_count = 2; instruction.mem_size = 1; } OperandCode::Yv_DX => { instruction.regs[0] = RegSpec::dx(); instruction.regs[1] = RegSpec::edi(); instruction.operands[0] = OperandSpec::Deref; instruction.operands[1] = OperandSpec::RegRRR; if instruction.prefixes.operand_size() { instruction.mem_size = 2; } else { instruction.mem_size = 4; } instruction.operand_count = 2; } OperandCode::DX_Xb => { instruction.regs[0] = RegSpec::dl(); instruction.regs[1] = RegSpec::esi(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::Deref; instruction.operand_count = 2; instruction.mem_size = 1; } OperandCode::AH => { instruction.operands[0] = OperandSpec::Nothing; instruction.operand_count = 0; } OperandCode::DX_Xv => { instruction.regs[0] = RegSpec::dx(); instruction.regs[1] = RegSpec::esi(); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::Deref; if instruction.prefixes.operand_size() { instruction.mem_size = 2; } else { instruction.mem_size = 4; } 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(words, instruction, operand_code); } OperandCode::M_Gv => { // `lea` operands (`Gv_M`) opportunistically reject a register form of `mmm` early, but // leaves `M_Gv` to test memory-ness of the `mmm` operand directly. also, swap // operands. if let OperandSpec::RegMMM = instruction.operands[1] { return Err(DecodeError::InvalidOperand); } let temp = instruction.operands[1]; instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = temp; } OperandCode::ModRM_0x62 => { let modrm = read_modrm(words)?; if modrm < 0xc0 { instruction.regs[0] = RegSpec { bank: RegisterBank::D, num: (modrm >> 3) & 7 }; if instruction.prefixes.operand_size() { instruction.regs[0].bank = RegisterBank::W; instruction.mem_size = 4; } else { instruction.mem_size = 8; } instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = read_M(words, instruction, modrm)?; instruction.operand_count = 2; } else { let prefixes = &instruction.prefixes; if prefixes.lock() || prefixes.operand_size() || prefixes.rep_any() { return Err(DecodeError::InvalidPrefixes); } else { evex::read_evex(words, instruction, Some(modrm))?; } } } _ => { // 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; return Err(DecodeError::InvalidOperand); } }; Ok(()) } fn decode_x87::Address, ::Word>>(words: &mut T, instruction: &mut Instruction, operand_code: OperandCode) -> Result<(), DecodeError> { #[allow(non_camel_case_types)] enum OperandCodeX87 { Est, St_Est, St_Edst, St_Eqst, St_Ew, St_Mw, St_Md, St_Mq, St_Mm, Ew, Est_St, Edst_St, Eqst_St, Ed_St, Mw_St, Md_St, Mq_St, Mm_St, Ex87S, Nothing, } // every x87 instruction is conditional on rrr bits let modrm = read_modrm(words)?; let r = (modrm >> 3) & 0b111; let (opcode, x87_operands) = match operand_code { OperandCode::x87_d8 => { match r { 0 => (Opcode::FADD, OperandCodeX87::St_Edst), 1 => (Opcode::FMUL, OperandCodeX87::St_Edst), 2 => (Opcode::FCOM, OperandCodeX87::St_Edst), 3 => (Opcode::FCOMP, OperandCodeX87::St_Edst), 4 => (Opcode::FSUB, OperandCodeX87::St_Edst), 5 => (Opcode::FSUBR, OperandCodeX87::St_Edst), 6 => (Opcode::FDIV, OperandCodeX87::St_Edst), 7 => (Opcode::FDIVR, OperandCodeX87::St_Edst), _ => { unreachable!("impossible r"); } } } OperandCode::x87_d9 => { match r { 0 => (Opcode::FLD, OperandCodeX87::St_Edst), 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::Edst_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_Mm), // 80bit 7 => (Opcode::FSTP, OperandCodeX87::Mm_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::Eqst_St), 1 => (Opcode::FMUL, OperandCodeX87::Eqst_St), 2 => (Opcode::FCOM, OperandCodeX87::St_Eqst), 3 => (Opcode::FCOMP, OperandCodeX87::St_Eqst), 4 => (Opcode::FSUBR, OperandCodeX87::Eqst_St), 5 => (Opcode::FSUB, OperandCodeX87::Eqst_St), 6 => (Opcode::FDIVR, OperandCodeX87::Eqst_St), 7 => (Opcode::FDIV, OperandCodeX87::Eqst_St), _ => { unreachable!("impossible r"); } } } else { match r { 0 => (Opcode::FADD, OperandCodeX87::St_Eqst), 1 => (Opcode::FMUL, OperandCodeX87::St_Eqst), 2 => (Opcode::FCOM, OperandCodeX87::St_Eqst), 3 => (Opcode::FCOMP, OperandCodeX87::St_Eqst), 4 => (Opcode::FSUB, OperandCodeX87::St_Eqst), 5 => (Opcode::FSUBR, OperandCodeX87::St_Eqst), 6 => (Opcode::FDIV, OperandCodeX87::St_Eqst), 7 => (Opcode::FDIVR, OperandCodeX87::St_Eqst), _ => { 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_Eqst), 1 => (Opcode::FISTTP, OperandCodeX87::Eqst_St), 2 => (Opcode::FST, OperandCodeX87::Eqst_St), 3 => (Opcode::FSTP, OperandCodeX87::Eqst_St), 4 => (Opcode::FRSTOR, OperandCodeX87::Ex87S), 5 => (Opcode::Invalid, OperandCodeX87::Nothing), 6 => (Opcode::FNSAVE, OperandCodeX87::Ex87S), 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_Mw), 1 => (Opcode::FISTTP, OperandCodeX87::Mw_St), 2 => (Opcode::FIST, OperandCodeX87::Mw_St), 3 => (Opcode::FISTP, OperandCodeX87::Mw_St), 4 => (Opcode::FBLD, OperandCodeX87::St_Mm), 5 => (Opcode::FILD, OperandCodeX87::St_Mq), 6 => (Opcode::FBSTP, OperandCodeX87::Mm_St), 7 => (Opcode::FISTP, OperandCodeX87::Mq_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); } match x87_operands { OperandCodeX87::Est => { instruction.operands[0] = read_E_st(words, instruction, modrm)?; instruction.operand_count = 1; } OperandCodeX87::St_Est => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E_st(words, instruction, modrm)?; instruction.operand_count = 2; } OperandCodeX87::St_Edst => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E_st(words, instruction, modrm)?; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 4; } instruction.operand_count = 2; } OperandCodeX87::St_Eqst => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E_st(words, instruction, modrm)?; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 8; } instruction.operand_count = 2; } OperandCodeX87::St_Ew => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E(words, instruction, modrm, 2)?; if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = 2; } instruction.operand_count = 2; } OperandCodeX87::St_Mm => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E(words, instruction, modrm, 4)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 10; instruction.operand_count = 2; } OperandCodeX87::St_Mq => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E(words, instruction, modrm, 4)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 8; instruction.operand_count = 2; } OperandCodeX87::St_Md => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E(words, instruction, modrm, 4)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 4; instruction.operand_count = 2; } OperandCodeX87::St_Mw => { instruction.operands[0] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operands[1] = read_E(words, instruction, modrm, 4)?; if instruction.operands[1] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 2; instruction.operand_count = 2; } OperandCodeX87::Ew => { instruction.operands[0] = read_E(words, instruction, modrm, 2)?; instruction.operand_count = 1; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 2; } } OperandCodeX87::Est_St => { instruction.operands[0] = read_E_st(words, instruction, modrm)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; } OperandCodeX87::Edst_St => { instruction.operands[0] = read_E_st(words, instruction, modrm)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 4; } } OperandCodeX87::Eqst_St => { instruction.operands[0] = read_E_st(words, instruction, modrm)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 8; } } OperandCodeX87::Ed_St => { instruction.operands[0] = read_E_st(words, instruction, modrm)?; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 4; } instruction.operand_count = 2; } OperandCodeX87::Mm_St => { instruction.operands[0] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 10; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; } OperandCodeX87::Mq_St => { instruction.operands[0] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 8; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; } OperandCodeX87::Md_St => { instruction.operands[0] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 4; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; } OperandCodeX87::Mw_St => { instruction.operands[0] = read_E(words, instruction, modrm, 4)?; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 2; instruction.operands[1] = OperandSpec::RegRRR; instruction.regs[0] = RegSpec::st(0); instruction.operand_count = 2; } OperandCodeX87::Ex87S => { instruction.operands[0] = read_E(words, instruction, modrm, 4)?; instruction.operand_count = 1; if instruction.operands[0] == OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); } instruction.mem_size = 63; } OperandCodeX87::Nothing => { instruction.operand_count = 0; }, } Ok(()) } #[inline] fn read_num::Address, ::Word>>(bytes: &mut T, width: u8) -> Result { match width { 1 => { bytes.next().ok().ok_or(DecodeError::ExhaustedInput).map(|x| x as u32) } 2 => { let mut buf = [0u8; 2]; bytes.next_n(&mut buf).ok().ok_or(DecodeError::ExhaustedInput)?; Ok(u16::from_le_bytes(buf) as u32) } 4 => { let mut buf = [0u8; 4]; bytes.next_n(&mut buf).ok().ok_or(DecodeError::ExhaustedInput)?; Ok(u32::from_le_bytes(buf) as u32) } _ => { unsafe { unreachable_unchecked(); } } } } #[inline] fn read_imm_signed::Address, ::Word>>(bytes: &mut T, num_width: u8) -> Result { if num_width == 1 { Ok(read_num(bytes, 1)? as i8 as i32) } else if num_width == 2 { Ok(read_num(bytes, 2)? as i16 as i32) } else { Ok(read_num(bytes, 4)? as i32) } } #[inline] fn read_imm_unsigned::Address, ::Word>>(bytes: &mut T, width: u8) -> Result { read_num(bytes, width) } #[inline] fn read_modrm::Address, ::Word>>(words: &mut T) -> Result { words.next().ok().ok_or(DecodeError::ExhaustedInput) }