aboutsummaryrefslogtreecommitdiff
path: root/src/long_mode/mod.rs
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2021-06-26 01:32:08 -0700
committeriximeow <me@iximeow.net>2021-06-26 01:39:04 -0700
commitd951f4bbce1102ddab30e3a5f65ddac8ab221ac9 (patch)
tree0de4ae9d1c3368e8d355ed3de3974ac22fbc18d1 /src/long_mode/mod.rs
parenta801fefb208c83a8d32f2be4d88b1f384e3017dc (diff)
add long-mode avx512 support, except for compressed displacements
Diffstat (limited to 'src/long_mode/mod.rs')
-rw-r--r--src/long_mode/mod.rs506
1 files changed, 494 insertions, 12 deletions
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<bool> 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<PrefixEvex> {
+ 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<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut In
read_M(bytes_iter, instr, modrm, length)
}
}
+#[allow(non_snake_case)]
+pub(self) fn read_E_zmm<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8) -> Result<OperandSpec, DecodeError> {
+ if modrm >= 0b11000000 {
+ read_modrm_reg(instr, modrm, RegisterBank::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<OperandSpec, DecodeError> {
@@ -6558,6 +7027,19 @@ fn read_instr<T: Iterator<Item=u8>>(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);