From d951f4bbce1102ddab30e3a5f65ddac8ab221ac9 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 26 Jun 2021 01:32:08 -0700 Subject: add long-mode avx512 support, except for compressed displacements --- src/long_mode/mod.rs | 506 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 494 insertions(+), 12 deletions(-) (limited to 'src/long_mode/mod.rs') diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 88cae67..bbfcd07 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -1,4 +1,5 @@ mod vex; +mod evex; #[cfg(feature = "fmt")] mod display; pub mod uarch; @@ -150,6 +151,19 @@ impl RegSpec { } } + /// construct a `RegSpec` for mask reg `num` + #[inline] + pub fn mask(num: u8) -> RegSpec { + if num >= 8 { + 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 { @@ -440,6 +454,9 @@ pub enum Operand { ImmediateU64(u64), ImmediateI64(i64), Register(RegSpec), + RegisterMaskMerge(RegSpec, RegSpec, MergeMode), + RegisterMaskMergeSae(RegSpec, RegSpec, MergeMode, SaeMode), + RegisterMaskMergeSaeNoround(RegSpec, RegSpec, MergeMode), DisplacementU32(u32), DisplacementU64(u64), RegDeref(RegSpec), @@ -450,10 +467,32 @@ pub enum Operand { RegScaleDisp(RegSpec, u8, i32), RegIndexBaseScale(RegSpec, RegSpec, u8), RegIndexBaseScaleDisp(RegSpec, RegSpec, u8, i32), + RegDerefMasked(RegSpec, RegSpec), + RegDispMasked(RegSpec, i32, RegSpec), + RegScaleMasked(RegSpec, u8, RegSpec), + RegIndexBaseMasked(RegSpec, RegSpec, RegSpec), + RegIndexBaseDispMasked(RegSpec, RegSpec, i32, RegSpec), + RegScaleDispMasked(RegSpec, u8, i32, RegSpec), + RegIndexBaseScaleMasked(RegSpec, RegSpec, u8, RegSpec), + RegIndexBaseScaleDispMasked(RegSpec, RegSpec, u8, i32, RegSpec), 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::RegIndexBaseScale => OperandSpec::RegIndexBaseScale_mask, + OperandSpec::RegIndexBaseScaleDisp => OperandSpec::RegIndexBaseScaleDisp_mask, + o => o, + } + } pub fn is_memory(&self) -> bool { match self { OperandSpec::DispU32 | @@ -465,7 +504,13 @@ impl OperandSpec { OperandSpec::RegScale | OperandSpec::RegScaleDisp | OperandSpec::RegIndexBaseScale | - OperandSpec::RegIndexBaseScaleDisp => { + OperandSpec::RegIndexBaseScaleDisp | + OperandSpec::Deref_mask | + OperandSpec::RegDisp_mask | + OperandSpec::RegScale_mask | + OperandSpec::RegScaleDisp_mask | + OperandSpec::RegIndexBaseScale_mask | + OperandSpec::RegIndexBaseScaleDisp_mask => { true }, OperandSpec::ImmI8 | @@ -475,8 +520,14 @@ impl OperandSpec { 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 => { @@ -485,6 +536,54 @@ impl OperandSpec { } } } +#[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 + } + } +} +#[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 { + 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 { @@ -495,13 +594,56 @@ impl Operand { OperandSpec::RegRRR => { Operand::Register(inst.modrm_rrr) } + OperandSpec::RegRRR_maskmerge => { + Operand::RegisterMaskMerge( + inst.modrm_rrr, + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegRRR_maskmerge_sae => { + Operand::RegisterMaskMergeSae( + inst.modrm_rrr, + 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.modrm_rrr, + 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.modrm_mmm) } + OperandSpec::RegMMM_maskmerge => { + Operand::RegisterMaskMerge( + inst.modrm_mmm, + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } + OperandSpec::RegMMM_maskmerge_sae_noround => { + Operand::RegisterMaskMergeSaeNoround( + inst.modrm_mmm, + RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg()), + MergeMode::from(inst.prefixes.evex_unchecked().merge()), + ) + } OperandSpec::RegVex => { Operand::Register(inst.vex_reg) } + OperandSpec::RegVex_maskmerge => { + Operand::RegisterMaskMerge( + inst.vex_reg, + 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.vex_reg.bank }) } @@ -538,6 +680,48 @@ impl Operand { OperandSpec::RegIndexBaseScaleDisp => { Operand::RegIndexBaseScaleDisp(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32) } + OperandSpec::Deref_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegDerefMasked(inst.modrm_mmm, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegDeref(inst.modrm_mmm) + } + } + OperandSpec::RegDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegDispMasked(inst.modrm_mmm, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegDisp(inst.modrm_mmm, inst.disp as i32) + } + } + OperandSpec::RegScale_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegScaleMasked(inst.sib_index, inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegScale(inst.sib_index, inst.scale) + } + } + OperandSpec::RegScaleDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegScaleDispMasked(inst.sib_index, inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegScaleDisp(inst.sib_index, inst.scale, inst.disp as i32) + } + } + OperandSpec::RegIndexBaseScale_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegIndexBaseScaleMasked(inst.modrm_mmm, inst.sib_index, inst.scale, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegIndexBaseScale(inst.modrm_mmm, inst.sib_index, inst.scale) + } + } + OperandSpec::RegIndexBaseScaleDisp_mask => { + if inst.prefixes.evex_unchecked().mask_reg() != 0 { + Operand::RegIndexBaseScaleDispMasked(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32, RegSpec::mask(inst.prefixes.evex_unchecked().mask_reg())) + } else { + Operand::RegIndexBaseScaleDisp(inst.modrm_mmm, inst.sib_index, inst.scale, inst.disp as i32) + } + } } } @@ -552,7 +736,15 @@ impl Operand { Operand::RegIndexBaseDisp(_, _, _) | Operand::RegScaleDisp(_, _, _) | Operand::RegIndexBaseScale(_, _, _) | - Operand::RegIndexBaseScaleDisp(_, _, _, _) => { + Operand::RegIndexBaseScaleDisp(_, _, _, _) | + Operand::RegDerefMasked(_, _) | + Operand::RegDispMasked(_, _, _) | + Operand::RegScaleMasked(_, _, _) | + Operand::RegIndexBaseMasked(_, _, _) | + Operand::RegIndexBaseDispMasked(_, _, _, _) | + Operand::RegScaleDispMasked(_, _, _, _) | + Operand::RegIndexBaseScaleMasked(_, _, _, _) | + Operand::RegIndexBaseScaleDispMasked(_, _, _, _, _) => { true }, Operand::ImmediateI8(_) | @@ -564,6 +756,9 @@ impl Operand { Operand::ImmediateU64(_) | Operand::ImmediateI64(_) | Operand::Register(_) | + Operand::RegisterMaskMerge(_, _, _) | + Operand::RegisterMaskMergeSae(_, _, _, _) | + Operand::RegisterMaskMergeSaeNoround(_, _, _) | Operand::Nothing => { false } @@ -582,6 +777,9 @@ impl Operand { Operand::Register(reg) => { reg.width() } + Operand::RegisterMaskMerge(reg, _, _) => { + reg.width() + } Operand::ImmediateI8(_) | Operand::ImmediateU8(_) => { 1 @@ -1568,6 +1766,7 @@ pub enum Opcode { VPMULHRSW, VPMULHUW, VPMULHW, + VPMULLQ, VPMULLD, VPMULLW, VPMULUDQ, @@ -2012,6 +2211,7 @@ pub enum Opcode { VGETMANTSS, VINSERTF32X4, VINSERTF64X4, + VINSERTI64X4, VMOVDQA32, VMOVDQA64, VMOVDQU32, @@ -2062,8 +2262,8 @@ pub enum Opcode { VPSRAVQ, VPTESTNMD, VPTESTNMQ, - VPTERLOGD, - VPTERLOGQ, + VPTERNLOGD, + VPTERNLOGQ, VPTESTMD, VPTESTMQ, VRCP14PD, @@ -2072,7 +2272,7 @@ pub enum Opcode { VRCP14SS, VRNDSCALEPD, VRNDSCALEPS, - VRNDCSALESD, + VRNDSCALESD, VRNDSCALESS, VRSQRT14PD, VRSQRT14PS, @@ -2114,7 +2314,6 @@ pub enum Opcode { VPMOVM2Q, VPMOVB2D, VPMOVQ2M, - VPMULLLQ, VRANGEPD, VRANGEPS, VRANGESD, @@ -2251,6 +2450,95 @@ pub enum Opcode { 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, } #[derive(Debug)] @@ -2277,7 +2565,7 @@ impl yaxpeax_arch::Instruction for Instruction { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[non_exhaustive] pub enum DecodeError { ExhaustedInput, @@ -2300,10 +2588,24 @@ 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, @@ -2327,7 +2629,13 @@ enum OperandSpec { RegScale, RegScaleDisp, RegIndexBaseScale, - RegIndexBaseScaleDisp + RegIndexBaseScaleDisp, + Deref_mask, + RegDisp_mask, + RegScale_mask, + RegScaleDisp_mask, + RegIndexBaseScale_mask, + RegIndexBaseScaleDisp_mask, } // the Hash, Eq, and PartialEq impls here are possibly misleading. @@ -2852,6 +3160,47 @@ impl InstDecoder { self } + 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 + } + + 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 } @@ -3051,6 +3400,13 @@ impl InstDecoder { /// 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() { @@ -3493,6 +3849,7 @@ impl InstDecoder { Opcode::VPMULHRSW | Opcode::VPMULHUW | Opcode::VPMULHW | + Opcode::VPMULLQ | Opcode::VPMULLD | Opcode::VPMULLW | Opcode::VPMULUDQ | @@ -3928,11 +4285,47 @@ impl Instruction { } #[derive(Debug, Copy, Clone)] +pub struct EvexData { + // data: present, z, b, Lp, Rp. aaa + bits: u8, +} + +#[derive(Debug, Copy, Clone)] pub struct Prefixes { bits: u8, rex: PrefixRex, segment: Segment, - _pad: u8, + evex_data: EvexData, +} + +#[derive(Debug, Copy, Clone)] +pub struct PrefixEvex { + vex: PrefixVex, + evex_data: EvexData, +} + +impl PrefixEvex { + fn present(&self) -> bool { + self.evex_data.present() + } + fn vex(&self) -> &PrefixVex { + &self.vex + } + fn mask_reg(&self) -> u8 { + self.evex_data.aaa() + } + fn broadcast(&self) -> bool { + self.evex_data.b() + } + fn merge(&self) -> bool { + self.evex_data.z() + } + fn lp(&self) -> bool { + self.evex_data.lp() + } + fn rp(&self) -> bool { + self.evex_data.rp() + } } #[derive(Debug, Copy, Clone)] @@ -3966,7 +4359,7 @@ impl Prefixes { bits: bits, rex: PrefixRex { bits: 0 }, segment: Segment::DS, - _pad: 0, + evex_data: EvexData { bits: 0 }, } } #[inline] @@ -4025,6 +4418,17 @@ impl Prefixes { fn rex(&self) -> &PrefixRex { &self.rex } #[inline] fn vex(&self) -> PrefixVex { PrefixVex { bits: self.rex.bits } } + #[inline] + fn evex_unchecked(&self) -> PrefixEvex { PrefixEvex { vex: PrefixVex { bits: self.rex.bits }, evex_data: self.evex_data } } + #[inline] + fn evex(&self) -> Option { + let evex = self.evex_unchecked(); + if evex.present() { + Some(evex) + } else { + None + } + } #[inline] fn rex_from(&mut self, bits: u8) { @@ -4045,11 +4449,68 @@ impl Prefixes { 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 wrxb = rxb | (w >> 4); let l = (low & 0x04) << 2; let synthetic_rex = wrxb | l | 0x80; self.rex.from(synthetic_rex); } + + #[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_rex = wrxb | l | 0x80; + self.rex.from(synthetic_rex); + + // 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 + } } impl PrefixRex { @@ -4763,7 +5224,7 @@ const OPCODES: [OpcodeRecord; 256] = [ // 0x60 OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::MOVSXD), OperandCode::Gdq_Ed), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), @@ -4987,6 +5448,14 @@ pub(self) fn read_E_ymm>(bytes_iter: &mut T, instr: &mut In read_M(bytes_iter, instr, modrm, length) } } +#[allow(non_snake_case)] +pub(self) fn read_E_zmm>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, RegisterBank::Z) + } else { + read_M(bytes_iter, instr, modrm, length) + } +} #[allow(non_snake_case)] fn read_modrm_reg(instr: &mut Instruction, modrm: u8, reg_bank: RegisterBank) -> Result { @@ -6558,6 +7027,19 @@ fn read_instr>(decoder: &InstDecoder, mut bytes_iter: T, in } return Ok(()); } + } else if b == 0x62 { + if prefixes.rex().present() || prefixes.lock() || prefixes.operand_size() || prefixes.rep() || prefixes.repnz() { + // rex and then evex is invalid! reject it. + instruction.opcode = Opcode::Invalid; + return Err(DecodeError::InvalidPrefixes); + } else { + instruction.prefixes = prefixes; + evex::read_evex(&mut bytes_iter, instruction, length)?; + if decoder != &InstDecoder::default() { + decoder.revise_instruction(instruction)?; + } + return Ok(()); + } } prefixes.rex_from(0); -- cgit v1.1