From 0cb220f953c5cd8f0ecfc1ac3480d35ed7481c96 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 3 Jul 2021 19:57:41 -0700 Subject: document public members in long_mode --- src/long_mode/display.rs | 8 +- src/long_mode/mod.rs | 437 ++++++++++++++++++++++++++++++------------ src/long_mode/vex.rs | 252 ++++++++++++------------ src/protected_mode/display.rs | 4 +- src/protected_mode/mod.rs | 59 +++++- 5 files changed, 505 insertions(+), 255 deletions(-) (limited to 'src') diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index f4d7a2c..948df53 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -123,10 +123,10 @@ const REG_NAMES: &[&'static str] = &[ "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", - "eip", "k1", "k2", "k3", "k4", "k5", "k6", "k7", - "rip", "k1", "k2", "k3", "k4", "k5", "k6", "k7", - "eflags", "k1", "k2", "k3", "k4", "k5", "k6", "k7", - "rflags", "k1", "k2", "k3", "k4", "k5", "k6", "k7", + "eip", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "rip", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "eflags", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "rflags", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", ]; pub(crate) fn regspec_label(spec: &RegSpec) -> &'static str { diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index c0125f4..64b8a4d 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -28,6 +28,17 @@ impl fmt::Display for DecodeError { } } +/// an `x86_64` 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: `rip`, `eip`, `rflags`, and +/// `eflags`. #[cfg_attr(feature="use-serde", derive(Serialize, Deserialize))] #[derive(Copy, Clone, Debug, PartialOrd, Ord, Eq, PartialEq)] pub struct RegSpec { @@ -44,7 +55,15 @@ impl Hash for RegSpec { } } -#[derive(Debug)] +/// 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, @@ -69,10 +88,20 @@ impl RegSpec { /// the register `rip`. this register is in the class `rip`, which contains only it. pub const RIP: RegSpec = RegSpec::rip(); + /// 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 } } @@ -84,6 +113,7 @@ impl RegSpec { display::regspec_label(self) } + /// construct a `RegSpec` for x87 register `st(num)` #[inline] pub fn st(num: u8) -> RegSpec { if num >= 8 { @@ -423,7 +453,7 @@ impl RegSpec { RegSpec { bank: RegisterBank::MM, num: 0 } } - /// return the size of this register, in bytes + /// return the size of this register, in bytes. #[inline] pub fn width(&self) -> u8 { self.class().width() @@ -439,39 +469,102 @@ enum SizeCode { vqp } +/// an operand for an `x86_64` 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, Eq)] #[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), - ImmediateU32(u32), + /// a sign-extended dword ImmediateI32(i32), - ImmediateU64(u64), + /// a zero-extended dword + ImmediateU32(u32), + /// a sign-extended qword ImmediateI64(i64), + /// a zero-extended qword + ImmediateU64(u64), + /// 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 dword address. it's extremely rare that a well-formed x86 + /// instruction uses this mode. as an example, `[0x1133]` DisplacementU32(u32), + /// 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, `gs:[0x14]`. segment overrides, + /// however, are maintained on the instruction itself. DisplacementU64(u64), + /// a simple dereference of the address held in some register. for example: `[rsi]`. RegDeref(RegSpec), + /// a dereference of the address held in some register with offset. for example: `[rsi + 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: `[rdx * 4]`. RegScale(RegSpec, u8), + /// a dereference of the address from summing two registers. for example: `[rbp + rax]` RegIndexBase(RegSpec, RegSpec), + /// a dereference of the address from summing two registers with offset. for example: `[rdi + rcx + 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: `[rax * 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: `[rsi + rcx * 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: `[rsi + rcx * 4 + 0x1234]` RegIndexBaseScaleDisp(RegSpec, RegSpec, u8, i32), + /// an `avx512` dereference of register with optional masking. for example: `[rdx]{k3}` RegDerefMasked(RegSpec, RegSpec), + /// an `avx512` dereference of register plus offset, with optional masking. for example: `[rsp + 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: `[rsi * 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: `[rsi + rax * 4]{k6}` RegIndexBaseMasked(RegSpec, RegSpec, RegSpec), + /// an `avx512` dereference of a register plus offset, with optional masking. for example: + /// `[rsi + rax + 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: `[rsi * + /// 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: `[rsi + rax * 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: `[rsi + rax * 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, } @@ -490,7 +583,7 @@ impl OperandSpec { o => o, } } - pub fn is_memory(&self) -> bool { + fn is_memory(&self) -> bool { match self { OperandSpec::DispU32 | OperandSpec::DispU64 | @@ -533,6 +626,12 @@ impl OperandSpec { } } } + +/// 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, @@ -547,6 +646,7 @@ impl From for MergeMode { } } } +/// an `avx512` custom rounding mode. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum SaeMode { RoundNearest, @@ -561,6 +661,16 @@ const SAE_MODES: [SaeMode; 4] = [ 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}", @@ -722,6 +832,10 @@ impl Operand { } } + /// 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::DisplacementU32(_) | @@ -805,6 +919,10 @@ fn operand_size() { // assert_eq!(core::mem::size_of::(), 40); } +/// an `x86_64` 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 { @@ -925,7 +1043,7 @@ pub mod register_class { 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. + /// `avx512` mask registers k0 through k7. pub const K: RegisterClass = RegisterClass { kind: RegisterBank::K }; /// the full instruction pointer register. pub const RIP: RegisterClass = RegisterClass { kind: RegisterBank::RIP }; @@ -1005,6 +1123,11 @@ enum RegisterBank { K = 29, // 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 @@ -1044,6 +1167,7 @@ const XSAVE: [Opcode; 10] = [ Opcode::XSETBV, ]; +/// an `x86_64` opcode. there sure are a lot of these. #[allow(non_camel_case_types)] #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] @@ -2556,7 +2680,12 @@ impl PartialEq for Instruction { } } -#[derive(Debug, Clone, Eq)] +/// an `x86_64` 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, /* @@ -2661,8 +2790,10 @@ enum OperandSpec { // Foo for T == x86_64. 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)] +#[derive(Hash, Eq, PartialEq, Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub struct Arch; @@ -2687,7 +2818,15 @@ impl LengthedInstruction for Instruction { } } -#[derive(PartialEq)] +/// an `x86_64` 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 @@ -3183,6 +3322,7 @@ impl InstDecoder { self } + /// returns `true` if this `InstDecoder` has **all** `avx512` features enabled. pub fn avx512(&self) -> bool { let avx512_mask = (1 << 19) | @@ -3203,6 +3343,9 @@ impl InstDecoder { (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) | @@ -3420,7 +3563,7 @@ impl InstDecoder { self } - /// Optionally reject or reinterpret instruction according to the decoder's + /// 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() { @@ -4144,6 +4287,8 @@ impl Decoder for InstDecoder { } 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 | @@ -4206,6 +4351,7 @@ impl Default for Instruction { } impl Instruction { + /// get the `Opcode` of this instruction. pub fn opcode(&self) -> Opcode { self.opcode } @@ -4239,6 +4385,11 @@ impl Instruction { } } + /// 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 }) @@ -4252,7 +4403,7 @@ impl Instruction { pub fn invalid() -> Instruction { Instruction { prefixes: Prefixes::new(0), - opcode: Opcode::Invalid, + opcode: Opcode::NOP, mem_size: 0, regs: [RegSpec::rax(); 4], scale: 0, @@ -4264,13 +4415,10 @@ impl Instruction { } } - pub fn is_invalid(&self) -> bool { - match self.opcode { - Opcode::Invalid => true, - _ => false - } - } - + /// 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 => { @@ -4318,6 +4466,18 @@ impl Instruction { } #[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, @@ -4327,11 +4487,15 @@ impl Instruction { } #[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct EvexData { +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. `rex`, +/// `vex`, and `evex` prefixes are available through their associated helpers. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Prefixes { bits: u8, @@ -4340,6 +4504,7 @@ pub struct Prefixes { evex_data: EvexData, } +/// the `avx512`-related data from an [`evex`](https://en.wikipedia.org/wiki/EVEX_prefix) prefix. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PrefixEvex { vex: PrefixVex, @@ -4350,26 +4515,32 @@ impl PrefixEvex { fn present(&self) -> bool { self.evex_data.present() } - fn vex(&self) -> &PrefixVex { - &self.vex + /// the `evex` prefix's parts that overlap with `vex` definitions - `L`, `W`, `R`, `X`, and `B` + /// bits. + pub fn vex(&self) -> PrefixVex { + self.vex } - fn mask_reg(&self) -> u8 { + /// the `avx512` mask register in use. `0` indicates "no mask register". + pub fn mask_reg(&self) -> u8 { self.evex_data.aaa() } - fn broadcast(&self) -> bool { + pub fn broadcast(&self) -> bool { self.evex_data.b() } - fn merge(&self) -> bool { + pub fn merge(&self) -> bool { self.evex_data.z() } - fn lp(&self) -> bool { + /// the `evex` `L'` bit. + pub fn lp(&self) -> bool { self.evex_data.lp() } - fn rp(&self) -> bool { + /// 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, @@ -4378,19 +4549,23 @@ pub struct PrefixVex { #[allow(dead_code)] impl PrefixVex { #[inline] - fn b(&self) -> bool { (self.bits & 0x01) == 0x01 } + fn present(&self) -> bool { (self.bits & 0x80) == 0x80 } + #[inline] + pub fn b(&self) -> bool { (self.bits & 0x01) == 0x01 } #[inline] - fn x(&self) -> bool { (self.bits & 0x02) == 0x02 } + pub fn x(&self) -> bool { (self.bits & 0x02) == 0x02 } #[inline] - fn r(&self) -> bool { (self.bits & 0x04) == 0x04 } + pub fn r(&self) -> bool { (self.bits & 0x04) == 0x04 } #[inline] - fn w(&self) -> bool { (self.bits & 0x08) == 0x08 } + pub fn w(&self) -> bool { (self.bits & 0x08) == 0x08 } #[inline] - fn l(&self) -> bool { (self.bits & 0x10) == 0x10 } + pub fn l(&self) -> bool { (self.bits & 0x10) == 0x10 } #[inline] fn compressed_disp(&self) -> bool { (self.bits & 0x20) == 0x20 } } +/// bits specified in an x86_64 +/// [`rex`](https://wiki.osdev.org/X86-64_Instruction_Encoding#REX_prefix) prefix. #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct PrefixRex { bits: u8 @@ -4446,13 +4621,31 @@ impl Prefixes { #[inline] pub fn ss(&self) -> bool { self.segment == Segment::SS } #[inline] - fn rex(&self) -> &PrefixRex { &self.rex } + fn rex_unchecked(&self) -> PrefixRex { self.rex } + #[inline] + pub fn rex(&self) -> Option { + let rex = self.rex_unchecked(); + if rex.present() { + Some(rex) + } else { + None + } + } + #[inline] + fn vex_unchecked(&self) -> PrefixVex { PrefixVex { bits: self.rex.bits } } #[inline] - fn vex(&self) -> PrefixVex { PrefixVex { bits: self.rex.bits } } + 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.rex.bits }, evex_data: self.evex_data } } #[inline] - fn evex(&self) -> Option { + pub fn evex(&self) -> Option { let evex = self.evex_unchecked(); if evex.present() { Some(evex) @@ -4557,13 +4750,13 @@ impl PrefixRex { #[inline] fn present(&self) -> bool { (self.bits & 0xc0) == 0x40 } #[inline] - fn b(&self) -> bool { (self.bits & 0x01) == 0x01 } + pub fn b(&self) -> bool { (self.bits & 0x01) == 0x01 } #[inline] - fn x(&self) -> bool { (self.bits & 0x02) == 0x02 } + pub fn x(&self) -> bool { (self.bits & 0x02) == 0x02 } #[inline] - fn r(&self) -> bool { (self.bits & 0x04) == 0x04 } + pub fn r(&self) -> bool { (self.bits & 0x04) == 0x04 } #[inline] - fn w(&self) -> bool { (self.bits & 0x08) == 0x08 } + pub fn w(&self) -> bool { (self.bits & 0x08) == 0x08 } #[inline] fn from(&mut self, prefix: u8) { self.bits = prefix; @@ -5454,7 +5647,7 @@ const OPCODES: [OpcodeRecord; 256] = [ #[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, instr.prefixes.rex().present()); + let bank = width_to_gp_reg_bank(width, instr.prefixes.rex_unchecked().present()); if modrm >= 0b11000000 { read_modrm_reg(instr, modrm, bank) } else { @@ -5510,7 +5703,7 @@ pub(self) fn read_E_vex::Address, Result { - instr.regs[1] = RegSpec::from_parts(modrm & 7, instr.prefixes.rex().b(), reg_bank); + instr.regs[1] = RegSpec::from_parts(modrm & 7, instr.prefixes.rex_unchecked().b(), reg_bank); Ok(OperandSpec::RegMMM) } @@ -5540,10 +5733,10 @@ fn read_sib::Address, > 3) & 7) == 0b100 { - if modbits == 0b00 && !instr.prefixes.rex().x() { + if modbits == 0b00 && !instr.prefixes.rex_unchecked().x() { OperandSpec::DispU32 } else { - if instr.prefixes.rex().x() { + if instr.prefixes.rex_unchecked().x() { if modbits == 0 { OperandSpec::RegScale } else { @@ -5562,7 +5755,7 @@ fn read_sib::Address, > 3) & 7) == 0b100 { - if instr.prefixes.rex().x() { + if instr.prefixes.rex_unchecked().x() { OperandSpec::RegIndexBaseScale } else { OperandSpec::Deref @@ -5575,10 +5768,10 @@ fn read_sib::Address, > 3) & 7) == 0b100 { - if modbits == 0b00 && !instr.prefixes.rex().x() { + if modbits == 0b00 && !instr.prefixes.rex_unchecked().x() { OperandSpec::DispU32 } else { - if instr.prefixes.rex().x() { + if instr.prefixes.rex_unchecked().x() { if modbits == 0 { OperandSpec::RegScaleDisp } else { @@ -5597,7 +5790,7 @@ fn read_sib::Address, > 3) & 7) == 0b100 { - if instr.prefixes.rex().x() { + if instr.prefixes.rex_unchecked().x() { OperandSpec::RegIndexBaseScaleDisp } else { OperandSpec::RegDisp @@ -5624,12 +5817,12 @@ fn read_M::Address, > 6; let mmm = modrm & 7; let op_spec = if mmm == 4 { - if instr.prefixes.rex().b() { + if instr.prefixes.rex_unchecked().b() { instr.regs[1].num = 0b1000; } else { instr.regs[1].num = 0; } - if instr.prefixes.rex().x() { + if instr.prefixes.rex_unchecked().x() { instr.regs[2].num = 0b1000; } else { instr.regs[2].num = 0; @@ -5646,7 +5839,7 @@ fn read_M::Address, OpcodeRecord { } if prefixes.operand_size() { - if opcode == 0x16 && prefixes.rex().w() { + if opcode == 0x16 && prefixes.rex_unchecked().w() { return OpcodeRecord(Interpretation::Instruction(Opcode::PEXTRQ), OperandCode::G_Ev_xmm_Ib); - } else if opcode == 0x22 && prefixes.rex().w() { + } else if opcode == 0x22 && prefixes.rex_unchecked().w() { return OpcodeRecord(Interpretation::Instruction(Opcode::PINSRQ), OperandCode::G_Ev_xmm_Ib); } @@ -7054,7 +7247,7 @@ fn read_instr::Address, ::Address, ::Address, ::Address, ::Address, > 3) & 7) + if instruction.prefixes.rex().r() { 0b1000 } else { 0 }; + instruction.regs[0].num = ((modrm >> 3) & 7) + if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; mem_oper = if modrm >= 0b11000000 { // special-case here to handle `lea`. there *is* an `M_Gv` but it's only for a @@ -7244,7 +7437,7 @@ fn read_operands::Address, ::Address, > 3) & 7) + if instruction.prefixes.rex().r() { 0b1000 } else { 0 }; + instruction.regs[0].num = ((modrm >> 3) & 7) + if instruction.prefixes.rex_unchecked().r() { 0b1000 } else { 0 }; mem_oper = if modrm >= 0b11000000 { read_modrm_reg(instruction, modrm, bank)? @@ -7292,7 +7485,7 @@ fn read_operands::Address, { @@ -7306,15 +7499,15 @@ fn read_operands::Address, { // these are Zb_Ib_R instruction.regs[0] = - RegSpec::gp_from_parts(reg, instruction.prefixes.rex().b(), 1, instruction.prefixes.rex().present()); + RegSpec::gp_from_parts(reg, instruction.prefixes.rex_unchecked().b(), 1, instruction.prefixes.rex_unchecked().present()); instruction.imm = read_imm_unsigned(words, 1)?; instruction.operands[1] = OperandSpec::ImmU8; @@ -7330,7 +7523,7 @@ fn read_operands::Address, ::Address, > 3) & 7, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present()); + RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); if instruction.operands[1] != OperandSpec::RegMMM { instruction.mem_size = w; } @@ -7526,7 +7719,7 @@ fn read_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present()); + RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); }, 19 => { instruction.regs[0].bank = RegisterBank::X; @@ -7562,7 +7755,7 @@ fn read_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u64; if instruction.operands[1] != OperandSpec::RegMMM { @@ -7698,7 +7891,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u64; if instruction.operands[1] != OperandSpec::RegMMM { @@ -7721,7 +7914,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.operands[1] = OperandSpec::RegRRR; instruction.operands[0] = read_E_xmm(words, instruction, modrm)?; if instruction.operands[0] != OperandSpec::RegMMM { @@ -7740,7 +7933,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; if instruction.operands[1] != OperandSpec::RegMMM { @@ -7764,11 +7957,11 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::Q); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::Q); 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.rex().w() { + if instruction.prefixes.rex_unchecked().w() { instruction.mem_size = 10; } else { instruction.mem_size = 4; @@ -7787,7 +7980,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::D); instruction.imm = read_num(words, 1)? as u8 as u64; instruction.operands[2] = OperandSpec::ImmU8; @@ -7804,10 +7997,10 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.operands[1] = OperandSpec::RegMMM; instruction.regs[1] = - RegSpec::from_parts(modrm & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts(modrm & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u64; instruction.disp = @@ -7831,7 +8024,7 @@ fn unlikely_operands::Address, ::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.imm = read_num(words, 1)? as u8 as u64; if instruction.operands[1] != OperandSpec::RegMMM { @@ -7874,7 +8067,7 @@ fn unlikely_operands::Address, { - let bank = if instruction.prefixes.rex().w() { + let bank = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D @@ -7978,7 +8171,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present()); + RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); }, OperandCode::Gdq_Ev => { let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes); @@ -7997,7 +8190,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), regwidth, instruction.prefixes.rex().present()); + RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), regwidth, instruction.prefixes.rex_unchecked().present()); instruction.operand_count = 2; }, op @ OperandCode::AL_Ob | @@ -8015,7 +8208,7 @@ fn unlikely_operands::Address, ::Address, ::Address, { - if instruction.prefixes.rex().w() { + if instruction.prefixes.rex_unchecked().w() { instruction.opcode = Opcode::IRETQ; } else if instruction.prefixes.operand_size() { instruction.opcode = Opcode::IRET; @@ -8077,7 +8270,7 @@ fn unlikely_operands::Address, { - let opwidth = if instruction.prefixes.rex().w() { 8 } else { 4 }; + let opwidth = if instruction.prefixes.rex_unchecked().w() { 8 } else { 4 }; let modrm = read_modrm(words)?; instruction.operands[1] = instruction.operands[0]; @@ -8088,7 +8281,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), opwidth, instruction.prefixes.rex().present()); + RegSpec::gp_from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), opwidth, instruction.prefixes.rex_unchecked().present()); instruction.operand_count = 2; } @@ -8112,7 +8305,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::Q); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::Q); instruction.operand_count = 2; if instruction.operands[0] != OperandSpec::RegMMM { instruction.mem_size = 8; @@ -8127,7 +8320,7 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::Q); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::Q); instruction.operands[1] = read_E(words, instruction, modrm, 8)?; instruction.operand_count = 2; if instruction.operands[1] != OperandSpec::RegMMM { @@ -8157,9 +8350,9 @@ fn unlikely_operands::Address, > 3) & 7, instruction.prefixes.rex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.rex_unchecked().r(), RegisterBank::X); instruction.operands[1] = read_E_xmm(words, instruction, modrm)?; - if instruction.prefixes.rex().w() { + if instruction.prefixes.rex_unchecked().w() { let op = instruction.operands[0]; instruction.operands[0] = instruction.operands[1]; instruction.operands[1] = op; @@ -8169,7 +8362,7 @@ fn unlikely_operands::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, { instruction.regs[0].bank = RegisterBank::X; if mem_oper == OperandSpec::RegMMM { - if instruction.prefixes.rex().w() { + if instruction.prefixes.rex_unchecked().w() { instruction.regs[1].bank = RegisterBank::Q; } else { instruction.regs[1].bank = RegisterBank::D; @@ -8861,7 +9054,7 @@ fn unlikely_operands::Address, ::Address, ::Address, { instruction.opcode = Opcode::UMWAIT; instruction.regs[0] = RegSpec { - bank: if instruction.prefixes.rex().w() { RegisterBank::Q } else { RegisterBank::D }, - num: m + if instruction.prefixes.rex().x() { 0b1000 } else { 0 }, + bank: if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }, + num: m + if instruction.prefixes.rex_unchecked().x() { 0b1000 } else { 0 }, }; instruction.operands[0] = OperandSpec::RegRRR; instruction.operand_count = 1; @@ -9628,7 +9821,7 @@ fn unlikely_operands::Address, ::Address, { instruction.opcode = Opcode::RDFSBASE; - let opwidth = if instruction.prefixes.rex().w() { + let opwidth = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; - instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); + instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex_unchecked().x(), opwidth); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 1 => { instruction.opcode = Opcode::RDGSBASE; - let opwidth = if instruction.prefixes.rex().w() { + let opwidth = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; - instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); + instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex_unchecked().x(), opwidth); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 2 => { instruction.opcode = Opcode::WRFSBASE; - let opwidth = if instruction.prefixes.rex().w() { + let opwidth = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; - instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); + instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex_unchecked().x(), opwidth); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 3 => { instruction.opcode = Opcode::WRGSBASE; - let opwidth = if instruction.prefixes.rex().w() { + let opwidth = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; - instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); + instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex_unchecked().x(), opwidth); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 5 => { instruction.opcode = Opcode::INCSSP; - let opwidth = if instruction.prefixes.rex().w() { + let opwidth = if instruction.prefixes.rex_unchecked().w() { RegisterBank::Q } else { RegisterBank::D }; - instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth); + instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex_unchecked().x(), opwidth); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } 6 => { instruction.opcode = Opcode::UMONITOR; - instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex().x(), RegisterBank::Q); + instruction.regs[1] = RegSpec::from_parts(m, instruction.prefixes.rex_unchecked().x(), RegisterBank::Q); instruction.operands[0] = OperandSpec::RegMMM; instruction.operand_count = 1; } @@ -9830,10 +10023,10 @@ fn unlikely_operands::Address, > 3) & 7; - if instruction.prefixes.rex().r() { + if instruction.prefixes.rex_unchecked().r() { r += 0b1000; } - if instruction.prefixes.rex().b() { + if instruction.prefixes.rex_unchecked().b() { m += 0b1000; } @@ -10633,7 +10826,7 @@ fn imm_width_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> u match interpretation { SizeCode::b => 1, SizeCode::vd => { - if prefixes.rex().w() || !prefixes.operand_size() { 4 } else { 2 } + if prefixes.rex_unchecked().w() || !prefixes.operand_size() { 4 } else { 2 } }, SizeCode::vq => { if prefixes.operand_size() { @@ -10643,7 +10836,7 @@ fn imm_width_from_prefixes_64(interpretation: SizeCode, prefixes: Prefixes) -> u } }, SizeCode::vqp => { - if prefixes.rex().w() { + if prefixes.rex_unchecked().w() { 8 } else if prefixes.operand_size() { 2 diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs index d69a411..67c4965 100644 --- a/src/long_mode/vex.rs +++ b/src/long_mode/vex.rs @@ -173,7 +173,7 @@ fn read_vex_operands::Address, ::Address, ::Address, ::Address, ::Address, ::Address, ::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; match mem_oper { @@ -380,7 +380,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[2] = OperandSpec::RegRRR; match mem_oper { @@ -415,7 +415,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = read_E_xmm(words, instruction, modrm)?; @@ -431,7 +431,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; instruction.operands[2] = read_E_xmm(words, instruction, modrm)?; @@ -449,7 +449,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 4)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; @@ -484,7 +484,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 8)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -501,7 +501,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 4)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -518,7 +518,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 8)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; @@ -535,7 +535,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 4)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; @@ -552,7 +552,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); let mem_oper = read_E(words, instruction, modrm, 4)?; if let OperandSpec::RegMMM = mem_oper { instruction.regs[1].bank = RegisterBank::X; @@ -571,7 +571,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Q); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Q); let mem_oper = read_E(words, instruction, modrm, 4)?; if let OperandSpec::RegMMM = mem_oper { instruction.regs[1].bank = RegisterBank::X; @@ -595,7 +595,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; match (op, mem_oper) { (VEXOperandCode::E_G_xmm, OperandSpec::RegMMM) => { @@ -628,7 +628,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); let mem_oper = read_E_xmm(words, instruction, modrm)?; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); @@ -645,7 +645,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); let mem_oper = read_E_ymm(words, instruction, modrm)?; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); @@ -662,7 +662,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); let mem_oper = read_E_xmm(words, instruction, modrm)?; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); @@ -681,7 +681,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; @@ -700,7 +700,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; @@ -720,7 +720,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); let mem_oper = read_E_xmm(words, instruction, modrm)?; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); @@ -737,7 +737,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::D); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::D); let mem_oper = read_E_ymm(words, instruction, modrm)?; if mem_oper != OperandSpec::RegMMM { return Err(DecodeError::InvalidOperand); @@ -770,7 +770,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -793,7 +793,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -810,7 +810,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -833,7 +833,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -856,7 +856,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -884,7 +884,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegRRR; @@ -912,7 +912,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -931,7 +931,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); instruction.regs[3].bank = RegisterBank::Y; let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -946,7 +946,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); instruction.regs[3].bank = RegisterBank::Y; let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -966,7 +966,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); instruction.regs[3].bank = RegisterBank::Y; let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = mem_oper; @@ -984,7 +984,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; @@ -1002,7 +1002,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; @@ -1022,7 +1022,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 4)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; @@ -1036,7 +1036,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E(words, instruction, modrm, 8)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; @@ -1050,7 +1050,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = OperandSpec::RegVex; @@ -1066,7 +1066,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); instruction.regs[3].bank = RegisterBank::Y; let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -1087,7 +1087,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = mem_oper; instruction.operands[1] = OperandSpec::RegVex; @@ -1102,7 +1102,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.regs[2].bank = RegisterBank::X; instruction.operands[0] = OperandSpec::RegRRR; @@ -1117,7 +1117,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.regs[3].bank = RegisterBank::X; instruction.regs[2].bank = RegisterBank::Y; @@ -1133,7 +1133,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.regs[3].bank = RegisterBank::Y; instruction.regs[2].bank = RegisterBank::Y; @@ -1152,13 +1152,13 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; - let (opwidth, bank) = if instruction.prefixes.vex().w() { + let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { (8, RegisterBank::Q) } else { (4, RegisterBank::D) }; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); instruction.regs[3].bank = bank; let mem_oper = read_E(words, instruction, modrm, opwidth)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -1172,13 +1172,13 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; - let (opwidth, bank) = if instruction.prefixes.vex().w() { + let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { (8, RegisterBank::Q) } else { (4, RegisterBank::D) }; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); instruction.regs[3].bank = bank; let mem_oper = read_E(words, instruction, modrm, opwidth)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -1192,13 +1192,13 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; - let (opwidth, bank) = if instruction.prefixes.vex().w() { + let (opwidth, bank) = if instruction.prefixes.vex_unchecked().w() { (8, RegisterBank::Q) } else { (4, RegisterBank::D) }; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); let mem_oper = read_E(words, instruction, modrm, opwidth)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -1227,13 +1227,13 @@ fn read_vex_operands::Address, > 3) & 7,instruction.prefixes.vex().x(), bank); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), bank); let mem_oper = read_E(words, instruction, modrm, opwidth)?; instruction.operands[0] = OperandSpec::RegVex; instruction.operands[1] = mem_oper; @@ -1275,7 +1275,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::X); let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -1293,7 +1293,7 @@ fn read_vex_operands::Address, > 3) & 7, instruction.prefixes.vex().r(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7, instruction.prefixes.vex_unchecked().r(), RegisterBank::Y); let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; instruction.operands[1] = mem_oper; @@ -1308,7 +1308,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), RegisterBank::Y); instruction.regs[3].bank = RegisterBank::Y; let mem_oper = read_E_ymm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -1325,7 +1325,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), RegisterBank::X); instruction.regs[3].bank = RegisterBank::X; let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -1342,7 +1342,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), RegisterBank::Y); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), RegisterBank::Y); instruction.regs[3].bank = RegisterBank::Y; let mem_oper = read_E_xmm(words, instruction, modrm)?; instruction.operands[0] = OperandSpec::RegRRR; @@ -1357,7 +1357,7 @@ fn read_vex_operands::Address, { let modrm = read_modrm(words)?; instruction.regs[0] = - RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), RegisterBank::X); + RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex_unchecked().x(), RegisterBank::X); instruction.regs[3].bank = RegisterBank::X; // TODO: but the memory access is word-sized let mem_oper = read_E(words, instruction, modrm, 4)?; @@ -1397,10 +1397,10 @@ fn read_vex_instruction::Address, ::Address, if instruction.prefixes.vex().w() { + 0x6E => if instruction.prefixes.vex_unchecked().w() { (Opcode::VMOVQ, if L { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -1832,7 +1832,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x7E => if instruction.prefixes.vex_unchecked().w() { (Opcode::VMOVQ, if L { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -2121,17 +2121,17 @@ fn read_vex_instruction::Address, (Opcode::VCVTSI2SD, if instruction.prefixes.vex().w() { + 0x2a => (Opcode::VCVTSI2SD, if instruction.prefixes.vex_unchecked().w() { VEXOperandCode::G_V_xmm_Eq // 64-bit last operand } else { VEXOperandCode::G_V_xmm_Ed // 32-bit last operand }), - 0x2c => (Opcode::VCVTTSD2SI, if instruction.prefixes.vex().w() { + 0x2c => (Opcode::VCVTTSD2SI, if instruction.prefixes.vex_unchecked().w() { VEXOperandCode::VCVT_Gq_Eq_xmm // 64-bit } else { VEXOperandCode::VCVT_Gd_Ed_xmm // 32-bit }), - 0x2d => (Opcode::VCVTSD2SI, if instruction.prefixes.vex().w() { + 0x2d => (Opcode::VCVTSD2SI, if instruction.prefixes.vex_unchecked().w() { VEXOperandCode::VCVT_Gq_Eq_xmm // 64-bit } else { VEXOperandCode::VCVT_Gd_Ed_xmm // 32-bit @@ -2187,17 +2187,17 @@ fn read_vex_instruction::Address, (Opcode::VMOVSS, VEXOperandCode::VMOVSS_11), 0x12 => (Opcode::VMOVSLDUP, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }), 0x16 => (Opcode::VMOVSHDUP, if L { VEXOperandCode::G_E_ymm } else { VEXOperandCode::G_E_xmm }), - 0x2a => (Opcode::VCVTSI2SS, if instruction.prefixes.vex().w() { + 0x2a => (Opcode::VCVTSI2SS, if instruction.prefixes.vex_unchecked().w() { VEXOperandCode::G_V_xmm_Eq } else { VEXOperandCode::G_V_xmm_Ed }), - 0x2c => (Opcode::VCVTTSS2SI, if instruction.prefixes.vex().w() { + 0x2c => (Opcode::VCVTTSS2SI, if instruction.prefixes.vex_unchecked().w() { VEXOperandCode::VCVT_Gq_Eq_xmm } else { VEXOperandCode::VCVT_Gd_Ed_xmm }), - 0x2d => (Opcode::VCVTSS2SI, if instruction.prefixes.vex().w() { + 0x2d => (Opcode::VCVTSS2SI, if instruction.prefixes.vex_unchecked().w() { VEXOperandCode::VCVT_Gq_Eq_xmm } else { VEXOperandCode::VCVT_Gd_Ed_xmm @@ -2322,7 +2322,7 @@ fn read_vex_instruction::Address, (Opcode::VPERMPS, if L { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_ymm @@ -2335,7 +2335,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x18 => if instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { @@ -2345,7 +2345,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x19 => if instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { @@ -2538,7 +2538,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x45 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VPSRLVQ, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2552,17 +2552,17 @@ fn read_vex_instruction::Address, (Opcode::VPSRAVD, if L { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_ymm } else { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_xmm }), - 0x47 => if instruction.prefixes.vex().w() { + 0x47 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VPSLLVQ, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2586,7 +2586,7 @@ fn read_vex_instruction::Address, (Opcode::VBROADCASTI128, if L { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_ymm_M_xmm @@ -2605,7 +2605,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VPMASKMOVQ, if L { VEXOperandCode::G_V_M_ymm } else { @@ -2620,7 +2620,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VPMASKMOVQ, if L { VEXOperandCode::M_V_G_ymm } else { @@ -2635,7 +2635,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VPGATHERDQ, if L { VEXOperandCode::G_Ey_V_ymm } else { @@ -2650,7 +2650,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VPGATHERQQ, if L { VEXOperandCode::G_Ey_V_ymm } else { @@ -2665,7 +2665,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VGATHERDPD, if L { VEXOperandCode::G_Ey_V_ymm } else { @@ -2680,7 +2680,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VGATHERQPD, if L { VEXOperandCode::G_Ey_V_ymm } else { @@ -2695,7 +2695,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADDSUB132PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2710,7 +2710,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUBADD132PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2725,7 +2725,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADD132PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2739,13 +2739,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x99 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADD132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFMADD132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0x9A => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUB132PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2759,13 +2759,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x9B => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUB132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFMSUB132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0x9C => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMADD132PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2779,13 +2779,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x9D => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMADD132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFNMADD132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0x9E => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMSUB132PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2799,13 +2799,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x9F => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMSUB132SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFNMSUB132SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xA6 => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADDSUB213PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2820,7 +2820,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUBADD213PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2835,7 +2835,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADD213PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2849,13 +2849,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xA9 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xAA => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUB213PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2869,13 +2869,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xAB => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xAC => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMADD213PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2889,13 +2889,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xAD => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMADD213SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFNMADD213SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xAE => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMSUB213PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2909,13 +2909,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xAF => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMSUB213SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFNMSUB213SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xB6 => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADDSUB231PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2930,7 +2930,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUBADD231PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2945,7 +2945,7 @@ fn read_vex_instruction::Address, { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADD231PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2959,13 +2959,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xB9 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xBA => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUB231PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2979,13 +2979,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xBB => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xBC => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMADD231PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -2999,13 +2999,13 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xBD => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMADD231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFNMADD231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) }, 0xBE => { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMSUB231PD, if L { VEXOperandCode::G_V_E_ymm } else { @@ -3019,7 +3019,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0xBF => if instruction.prefixes.vex_unchecked().w() { (Opcode::VFNMSUB231SD, VEXOperandCode::G_V_E_xmm /* 64bit */) } else { (Opcode::VFNMSUB231SS, VEXOperandCode::G_V_E_xmm /* 64bit */) @@ -3143,7 +3143,7 @@ fn read_vex_instruction::Address, (Opcode::VPERMQ, if L { - if !instruction.prefixes.vex().w() { + if !instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_E_ymm_imm8 @@ -3152,7 +3152,7 @@ fn read_vex_instruction::Address, (Opcode::VPERMPD, if L { - if !instruction.prefixes.vex().w() { + if !instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_E_ymm_imm8 @@ -3161,12 +3161,12 @@ fn read_vex_instruction::Address, (Opcode::VPBLENDD, if L { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_ymm_imm8 } else { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_xmm_imm8 @@ -3182,7 +3182,7 @@ fn read_vex_instruction::Address, (Opcode::VPERM2F128, if L { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_ymm_imm8 @@ -3230,19 +3230,19 @@ fn read_vex_instruction::Address, (Opcode::VPEXTRB, if L || instruction.prefixes.vex().w() { + 0x14 => (Opcode::VPEXTRB, if L || instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { VEXOperandCode::Ev_G_xmm_imm8 }), - 0x15 => (Opcode::VPEXTRW, if L || instruction.prefixes.vex().w() { + 0x15 => (Opcode::VPEXTRW, if L || instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { VEXOperandCode::Ev_G_xmm_imm8 }), - 0x16 => if instruction.prefixes.vex().w() { + 0x16 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VPEXTRQ, if L { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -3264,7 +3264,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x18 => if instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { @@ -3275,7 +3275,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x19 => if instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { @@ -3303,7 +3303,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x22 => if instruction.prefixes.vex_unchecked().w() { (Opcode::VPINSRQ, if L { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); @@ -3353,7 +3353,7 @@ fn read_vex_instruction::Address, (Opcode::VPERM2I128, if L { - if instruction.prefixes.vex().w() { + if instruction.prefixes.vex_unchecked().w() { return Err(DecodeError::InvalidOpcode); } VEXOperandCode::G_V_E_ymm_imm8 @@ -3371,7 +3371,7 @@ fn read_vex_instruction::Address, if instruction.prefixes.vex().w() { + 0x4C => if instruction.prefixes.vex_unchecked().w() { instruction.opcode = Opcode::Invalid; return Err(DecodeError::InvalidOpcode); } else { diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs index 32eeace..baca1a2 100644 --- a/src/protected_mode/display.rs +++ b/src/protected_mode/display.rs @@ -121,8 +121,8 @@ const REG_NAMES: &[&'static str] = &[ "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)", "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7", "k0", "k1", "k2", "k3", "k4", "k5", "k6", "k7", - "eip", "k1", "k2", "k3", "k4", "k5", "k6", "k7", - "eflags", "k1", "k2", "k3", "k4", "k5", "k6", "k7", + "eip", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "eflags", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", ]; pub(crate) fn regspec_label(spec: &RegSpec) -> &'static str { diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index 92b6b49..166358b 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -388,34 +388,91 @@ enum SizeCode { #[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), - ImmediateU32(u32), + /// 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, } -- cgit v1.1