diff options
Diffstat (limited to 'src/protected_mode')
-rw-r--r-- | src/protected_mode/display.rs | 982 | ||||
-rw-r--r-- | src/protected_mode/evex.rs | 17 | ||||
-rw-r--r-- | src/protected_mode/mod.rs | 834 | ||||
-rw-r--r-- | src/protected_mode/vex.rs | 2 |
4 files changed, 1764 insertions, 71 deletions
diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs index e51d2dc..f258bad 100644 --- a/src/protected_mode/display.rs +++ b/src/protected_mode/display.rs @@ -5,7 +5,7 @@ use core::fmt; use yaxpeax_arch::{Colorize, ShowContextual, NoColors, YaxColors}; use yaxpeax_arch::display::*; -use crate::protected_mode::{RegSpec, Opcode, Operand, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec}; +use crate::protected_mode::{RegSpec, Opcode, Operand, MergeMode, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec}; impl fmt::Display for InstDecoder { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -166,6 +166,44 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand { &Operand::Register(ref spec) => { f.write_str(regspec_label(spec)) } + &Operand::RegisterMaskMerge(ref spec, ref mask, merge_mode) => { + f.write_str(regspec_label(spec))?; + if mask.num != 0 { + f.write_str("{")?; + f.write_str(regspec_label(mask))?; + f.write_str("}")?; + } + if let MergeMode::Zero = merge_mode { + f.write_str("{z}")?; + } + Ok(()) + } + &Operand::RegisterMaskMergeSae(ref spec, ref mask, merge_mode, sae_mode) => { + f.write_str(regspec_label(spec))?; + if mask.num != 0 { + f.write_str("{")?; + f.write_str(regspec_label(mask))?; + f.write_str("}")?; + } + if let MergeMode::Zero = merge_mode { + f.write_str("{z}")?; + } + f.write_str(sae_mode.label())?; + Ok(()) + } + &Operand::RegisterMaskMergeSaeNoround(ref spec, ref mask, merge_mode) => { + f.write_str(regspec_label(spec))?; + if mask.num != 0 { + f.write_str("{")?; + f.write_str(regspec_label(mask))?; + f.write_str("}")?; + } + if let MergeMode::Zero = merge_mode { + f.write_str("{z}")?; + } + f.write_str("{sae}")?; + Ok(()) + } &Operand::DisplacementU16(imm) => { write!(f, "[{}]", colors.address(u16_hex(imm))) } @@ -227,6 +265,69 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand { format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; write!(f, "]") }, + &Operand::RegDispMasked(ref spec, disp, ref mask_reg) => { + write!(f, "[{} ", regspec_label(spec))?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegDerefMasked(ref spec, ref mask_reg) => { + f.write_str("[")?; + f.write_str(regspec_label(spec))?; + f.write_str("]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegScaleMasked(ref spec, scale, ref mask_reg) => { + write!(f, "[{} * {}]", + regspec_label(spec), + colors.number(scale) + )?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegScaleDispMasked(ref spec, scale, disp, ref mask_reg) => { + write!(f, "[{} * {} ", + regspec_label(spec), + colors.number(scale), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegIndexBaseMasked(ref base, ref index, ref mask_reg) => { + f.write_str("[")?; + f.write_str(regspec_label(base))?; + f.write_str(" + ")?; + f.write_str(regspec_label(index))?; + f.write_str("]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + } + &Operand::RegIndexBaseDispMasked(ref base, ref index, disp, ref mask_reg) => { + write!(f, "[{} + {} ", + regspec_label(base), + regspec_label(index), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, + &Operand::RegIndexBaseScaleMasked(ref base, ref index, scale, ref mask_reg) => { + write!(f, "[{} + {} * {}]", + regspec_label(base), + regspec_label(index), + colors.number(scale) + )?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + } + &Operand::RegIndexBaseScaleDispMasked(ref base, ref index, scale, disp, ref mask_reg) => { + write!(f, "[{} + {} * {} ", + regspec_label(base), + regspec_label(index), + colors.number(scale), + )?; + format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?; + write!(f, "]")?; + write!(f, "{{{}}}", regspec_label(mask_reg)) + }, &Operand::Nothing => { Ok(()) }, } } @@ -655,6 +756,7 @@ const MNEMONICS: &[&'static str] = &[ "xorpd", "vmovddup", "vpshuflw", + "vpshufhw", "vhaddps", "vhsubps", "vaddsubps", @@ -826,6 +928,7 @@ const MNEMONICS: &[&'static str] = &[ "vpabsd", "vpabsw", "vpackssdw", + "vpackusdw", "vpacksswb", "vpackuswb", "vpaddb", @@ -837,12 +940,12 @@ const MNEMONICS: &[&'static str] = &[ "vpaddusw", "vpaddw", "vpalignr", - "vandps", "vandpd", - "vorps", + "vandps", "vorpd", - "vandnps", + "vorps", "vandnpd", + "vandnps", "vpand", "vpandn", "vpavgb", @@ -863,6 +966,8 @@ const MNEMONICS: &[&'static str] = &[ "vpcmpgtd", "vpcmpgtq", "vpcmpgtw", + "vpcmpestri", + "vpcmpestrm", "vpcmpistri", "vpcmpistrm", "vperm2f128", @@ -884,7 +989,7 @@ const MNEMONICS: &[&'static str] = &[ "vphaddd", "vphaddsw", "vphaddw", - "vphaddubsw", + "vpmaddubsw", "vphminposuw", "vphsubd", "vphsubsw", @@ -902,8 +1007,11 @@ const MNEMONICS: &[&'static str] = &[ "vpmaxub", "vpmaxuw", "vpmaxud", + "vpminsb", "vpminsw", "vpminsd", + "vpminub", + "vpminuw", "vpminud", "vpmovmskb", "vpmovsxbd", @@ -922,6 +1030,7 @@ const MNEMONICS: &[&'static str] = &[ "vpmulhrsw", "vpmulhuw", "vpmulhw", + "vpmullq", "vpmulld", "vpmullw", "vpmuludq", @@ -992,6 +1101,9 @@ const MNEMONICS: &[&'static str] = &[ "vxorpd", "vxorps", "vzeroupper", + "vzeroall", + "vldmxcsr", + "vstmxcsr", "pclmulqdq", "aeskeygenassist", "aesimc", @@ -1219,6 +1331,7 @@ const MNEMONICS: &[&'static str] = &[ "jrcxz", "pusha", "popa", + "bound", "arpl", "aas", "aaa", @@ -1315,6 +1428,378 @@ const MNEMONICS: &[&'static str] = &[ // TSXLDTRK "xsusldtrk", "xresldtrk", + + // AVX512F + "valignd", + "valignq", + "vblendmpd", + "vblendmps", + "vcompresspd", + "vcompressps", + "vcvtpd2udq", + "vcvttpd2udq", + "vcvtps2udq", + "vcvttps2udq", + "vcvtqq2pd", + "vcvtqq2ps", + "vcvtsd2usi", + "vcvttsd2usi", + "vcvtss2usi", + "vcvttss2usi", + "vcvtudq2pd", + "vcvtudq2ps", + "vcvtusi2usd", + "vcvtusi2uss", + "vexpandpd", + "vexpandps", + "vextractf32x4", + "vextractf64x4", + "vextracti32x4", + "vextracti64x4", + "vfixupimmpd", + "vfixupimmps", + "vfixupimmsd", + "vfixupimmss", + "vgetexppd", + "vgetexpps", + "vgetexpsd", + "vgetexpss", + "vgetmantpd", + "vgetmantps", + "vgetmantsd", + "vgetmantss", + "vinsertf32x4", + "vinsertf64x4", + "vinserti64x4", + "vmovdqa32", + "vmovdqa64", + "vmovdqu32", + "vmovdqu64", + "vpblendmd", + "vpblendmq", + "vpcmpd", + "vpcmpud", + "vpcmpq", + "vpcmpuq", + "vpcompressq", + "vpcompressd", + "vpermi2d", + "vpermi2q", + "vpermi2pd", + "vpermi2ps", + "vpermt2d", + "vpermt2q", + "vpermt2pd", + "vpermt2ps", + "vpmaxsq", + "vpmaxuq", + "vpminsq", + "vpminuq", + "vpmovsqb", + "vpmovusqb", + "vpmovsqw", + "vpmovusqw", + "vpmovsqd", + "vpmovusqd", + "vpmovsdb", + "vpmovusdb", + "vpmovsdw", + "vpmovusdw", + "vprold", + "vprolq", + "vprolvd", + "vprolvq", + "vprord", + "vprorq", + "vprorrd", + "vprorrq", + "vpscatterdd", + "vpscatterdq", + "vpscatterqd", + "vpscatterqq", + "vpsraq", + "vpsravq", + "vptestnmd", + "vptestnmq", + "vpternlogd", + "vpternlogq", + "vptestmd", + "vptestmq", + "vrcp14pd", + "vrcp14ps", + "vrcp14sd", + "vrcp14ss", + "vrndscalepd", + "vrndscaleps", + "vrndscalesd", + "vrndscaless", + "vrsqrt14pd", + "vrsqrt14ps", + "vrsqrt14sd", + "vrsqrt14ss", + "vscaledpd", + "vscaledps", + "vscaledsd", + "vscaledss", + "vscatterdd", + "vscatterdq", + "vscatterqd", + "vscatterqq", + "vshuff32x4", + "vshuff64x2", + "vshufi32x4", + "vshufi64x2", + + // AVX512DQ + "vcvttpd2qq", + "vcvtpd2qq", + "vcvttpd2uqq", + "vcvtpd2uqq", + "vcvttps2qq", + "vcvtps2qq", + "vcvttps2uqq", + "vcvtps2uqq", + "vcvtuqq2pd", + "vcvtuqq2ps", + "vextractf64x2", + "vextracti64x2", + "vfpclasspd", + "vfpclassps", + "vfpclasssd", + "vfpclassss", + "vinsertf64x2", + "vinserti64x2", + "vpmovm2d", + "vpmovm2q", + "vpmovb2d", + "vpmovq2m", + "vrangepd", + "vrangeps", + "vrangesd", + "vrangess", + "vreducepd", + "vreduceps", + "vreducesd", + "vreducess", + + // AVX512BW + "vdbpsadbw", + "vmovdqu8", + "vmovdqu16", + "vpblendmb", + "vpblendmw", + "vpcmpb", + "vpcmpub", + "vpcmpw", + "vpcmpuw", + "vpermw", + "vpermi2b", + "vpermi2w", + "vpmovm2b", + "vpmovm2w", + "vpmovb2m", + "vpmovw2m", + "vpmovswb", + "vpmovuswb", + "vpsllvw", + "vpsravw", + "vpsrlvw", + "vptestnmb", + "vptestnmw", + "vptestmb", + "vptestmw", + + // AVX512CD + "vpbroadcastm", + "vpconflictd", + "vpconflictq", + "vplzcntd", + "vplzcntq", + + "kunpckbw", + "kunpckwd", + "kunpckdq", + + "kaddb", + "kandb", + "kandnb", + "kmovb", + "knotb", + "korb", + "kortestb", + "kshiftlb", + "kshiftrb", + "ktestb", + "kxnorb", + "kxorb", + "kaddw", + "kandw", + "kandnw", + "kmovw", + "knotw", + "korw", + "kortestw", + "kshiftlw", + "kshiftrw", + "ktestw", + "kxnorw", + "kxorw", + "kaddd", + "kandd", + "kandnd", + "kmovd", + "knotd", + "kord", + "kortestd", + "kshiftld", + "kshiftrd", + "ktestd", + "kxnord", + "kxord", + "kaddq", + "kandq", + "kandnq", + "kmovq", + "knotq", + "korq", + "kortestq", + "kshiftlq", + "kshiftrq", + "ktestq", + "kxnorq", + "kxorq", + + // AVX512ER + "vexp2pd", + "vexp2ps", + "vexp2sd", + "vexp2ss", + "vrcp28pd", + "vrcp28ps", + "vrcp28sd", + "vrcp28ss", + "vrsqrt28pd", + "vrsqrt28ps", + "vrsqrt28sd", + "vrsqrt28ss", + + // AVX512PF + "vgatherpf0dpd", + "vgatherpf0dps", + "vgatherpf0qpd", + "vgatherpf0qps", + "vgatherpf1dpd", + "vgatherpf1dps", + "vgatherpf1qpd", + "vgatherpf1qps", + "vscatterpf0dpd", + "vscatterpf0dps", + "vscatterpf0qpd", + "vscatterpf0qps", + "vscatterpf1dpd", + "vscatterpf1dps", + "vscatterpf1qpd", + "vscatterpf1qps", + + // MPX + "bndmk", + "bndcl", + "bndcu", + "bndcn", + "bndmov", + "bndldx", + "bndstx", + + + + "vgf2p8affineqb", + "vgf2p8affineinvqb", + "vpshrdq", + "vpshrdd", + "vpshrdw", + "vpshldq", + "vpshldd", + "vpshldw", + "vbroadcastf32x8", + "vbroadcastf64x4", + "vbroadcastf32x4", + "vbroadcastf64x2", + "vbroadcastf32x2", + "vbroadcasti32x8", + "vbroadcasti64x4", + "vbroadcasti32x4", + "vbroadcasti64x2", + "vbroadcasti32x2", + "vextracti32x8", + "vextractf32x8", + "vinserti32x8", + "vinsertf32x8", + "vinserti32x4", + "v4fnmaddss", + "v4fnmaddps", + "vcvtneps2bf16", + "v4fmaddss", + "v4fmaddps", + "vcvtne2ps2bf16", + "vp2intersectd", + "vp2intersectq", + "vp4dpwssds", + "vp4dpwssd", + "vpdpwssds", + "vpdpwssd", + "vpdpbusds", + "vdpbf16ps", + "vpbroadcastmw2d", + "vpbroadcastmb2q", + "vpmovd2m", + "vpmovqd", + "vpmovwb", + "vpmovdb", + "vpmovdw", + "vpmovqb", + "vpmovqw", + "vgf2p8mulb", + "vpmadd52huq", + "vpmadd52luq", + "vpshufbitqmb", + "vpermb", + "vpexpandd", + "vpexpandq", + "vpabsq", + "vprorvd", + "vprorvq", + "vpmultishiftqb", + "vpermt2b", + "vpermt2w", + "vpshrdvq", + "vpshrdvd", + "vpshrdvw", + "vpshldvq", + "vpshldvd", + "vpshldvw", + "vpcompressb", + "vpcompressw", + "vpexpandb", + "vpexpandw", + "vpopcntd", + "vpopcntq", + "vpopcntb", + "vpopcntw", + "vscalefss", + "vscalefsd", + "vscalefps", + "vscalefpd", + "vpdpbusd", + "vcvtusi2sd", + "vcvtusi2ss", + "vpxord", + "vpxorq", + "vpord", + "vporq", + "vpandnd", + "vpandnq", + "vpandd", + "vpandq", ]; impl Opcode { @@ -1328,6 +1813,95 @@ impl Opcode { impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { fn colorize(&self, colors: &Y, out: &mut T) -> fmt::Result { match self { + Opcode::VGF2P8AFFINEQB | + Opcode::VGF2P8AFFINEINVQB | + Opcode::VPSHRDQ | + Opcode::VPSHRDD | + Opcode::VPSHRDW | + Opcode::VPSHLDQ | + Opcode::VPSHLDD | + Opcode::VPSHLDW | + Opcode::VBROADCASTF32X8 | + Opcode::VBROADCASTF64X4 | + Opcode::VBROADCASTF32X4 | + Opcode::VBROADCASTF64X2 | + Opcode::VBROADCASTF32X2 | + Opcode::VBROADCASTI32X8 | + Opcode::VBROADCASTI64X4 | + Opcode::VBROADCASTI32X4 | + Opcode::VBROADCASTI64X2 | + Opcode::VBROADCASTI32X2 | + Opcode::VEXTRACTI32X8 | + Opcode::VEXTRACTF32X8 | + Opcode::VINSERTI32X8 | + Opcode::VINSERTF32X8 | + Opcode::VINSERTI32X4 | + Opcode::V4FNMADDSS | + Opcode::V4FNMADDPS | + Opcode::VCVTNEPS2BF16 | + Opcode::V4FMADDSS | + Opcode::V4FMADDPS | + Opcode::VCVTNE2PS2BF16 | + Opcode::VP2INTERSECTD | + Opcode::VP2INTERSECTQ | + Opcode::VP4DPWSSDS | + Opcode::VP4DPWSSD | + Opcode::VPDPWSSDS | + Opcode::VPDPWSSD | + Opcode::VPDPBUSDS | + Opcode::VDPBF16PS | + Opcode::VPBROADCASTMW2D | + Opcode::VPBROADCASTMB2Q | + Opcode::VPMOVD2M | + Opcode::VPMOVQD | + Opcode::VPMOVWB | + Opcode::VPMOVDB | + Opcode::VPMOVDW | + Opcode::VPMOVQB | + Opcode::VPMOVQW | + Opcode::VGF2P8MULB | + Opcode::VPMADD52HUQ | + Opcode::VPMADD52LUQ | + Opcode::VPSHUFBITQMB | + Opcode::VPERMB | + Opcode::VPEXPANDD | + Opcode::VPEXPANDQ | + Opcode::VPABSQ | + Opcode::VPRORVD | + Opcode::VPRORVQ | + Opcode::VPMULTISHIFTQB | + Opcode::VPERMT2B | + Opcode::VPERMT2W | + Opcode::VPSHRDVQ | + Opcode::VPSHRDVD | + Opcode::VPSHRDVW | + Opcode::VPSHLDVQ | + Opcode::VPSHLDVD | + Opcode::VPSHLDVW | + Opcode::VPCOMPRESSB | + Opcode::VPCOMPRESSW | + Opcode::VPEXPANDB | + Opcode::VPEXPANDW | + Opcode::VPOPCNTD | + Opcode::VPOPCNTQ | + Opcode::VPOPCNTB | + Opcode::VPOPCNTW | + Opcode::VSCALEFSS | + Opcode::VSCALEFSD | + Opcode::VSCALEFPS | + Opcode::VSCALEFPD | + Opcode::VPDPBUSD | + Opcode::VCVTUSI2SD | + Opcode::VCVTUSI2SS | + Opcode::VPXORD | + Opcode::VPXORQ | + Opcode::VPORD | + Opcode::VPORQ | + Opcode::VPANDND | + Opcode::VPANDNQ | + Opcode::VPANDD | + Opcode::VPANDQ | + Opcode::VHADDPS | Opcode::VHSUBPS | Opcode::VADDSUBPS | @@ -1434,6 +2008,7 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPMULHRSW | Opcode::VPMULHUW | Opcode::VPMULHW | + Opcode::VPMULLQ | Opcode::VPMULLD | Opcode::VPMULLW | Opcode::VPMULUDQ | @@ -1451,6 +2026,34 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPSUBW | Opcode::VROUNDPD | Opcode::VROUNDPS | + Opcode::VEXP2PD | + Opcode::VEXP2PS | + Opcode::VEXP2SD | + Opcode::VEXP2SS | + Opcode::VRCP28PD | + Opcode::VRCP28PS | + Opcode::VRCP28SD | + Opcode::VRCP28SS | + Opcode::VRCP14PD | + Opcode::VRCP14PS | + Opcode::VRCP14SD | + Opcode::VRCP14SS | + Opcode::VRNDSCALEPD | + Opcode::VRNDSCALEPS | + Opcode::VRNDSCALESD | + Opcode::VRNDSCALESS | + Opcode::VRSQRT14PD | + Opcode::VRSQRT14PS | + Opcode::VRSQRT14SD | + Opcode::VRSQRT14SS | + Opcode::VSCALEDPD | + Opcode::VSCALEDPS | + Opcode::VSCALEDSD | + Opcode::VSCALEDSS | + Opcode::VRSQRT28PD | + Opcode::VRSQRT28PS | + Opcode::VRSQRT28SD | + Opcode::VRSQRT28SS | Opcode::VRSQRTPS | Opcode::VSQRTPD | Opcode::VSQRTPS | @@ -1470,13 +2073,14 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VSQRTSS | Opcode::VPSADBW | Opcode::VMPSADBW | + Opcode::VDBPSADBW | Opcode::VPHADDD | Opcode::VPHADDSW | Opcode::VPHADDW | Opcode::VPHSUBD | Opcode::VPHSUBSW | Opcode::VPHSUBW | - Opcode::VPHADDUBSW | + Opcode::VPMADDUBSW | Opcode::VPMADDWD | Opcode::VDPPD | Opcode::VDPPS | @@ -1499,6 +2103,19 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPSLLVD | Opcode::VPSLLVQ | Opcode::VPSLLW | + Opcode::VPROLD | + Opcode::VPROLQ | + Opcode::VPROLVD | + Opcode::VPROLVQ | + Opcode::VPRORD | + Opcode::VPRORQ | + Opcode::VPRORRD | + Opcode::VPRORRQ | + Opcode::VPSLLVW | + Opcode::VPSRAQ | + Opcode::VPSRAVQ | + Opcode::VPSRAVW | + Opcode::VPSRLVW | Opcode::VPSRAD | Opcode::VPSRAVD | Opcode::VPSRAW | @@ -1584,6 +2201,8 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::SUB | Opcode::POPCNT | Opcode::LZCNT | + Opcode::VPLZCNTD | + Opcode::VPLZCNTQ | Opcode::BT | Opcode::BTS | Opcode::BTR | @@ -1702,12 +2321,48 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::FXTRACT | Opcode::FYL2X | Opcode::FYL2XP1 | - Opcode::AAS | Opcode::AAA | + Opcode::AAS | Opcode::DAS | Opcode::DAA | Opcode::ADX | Opcode::AMX | + Opcode::KADDB | + Opcode::KANDB | + Opcode::KANDNB | + Opcode::KNOTB | + Opcode::KORB | + Opcode::KSHIFTLB | + Opcode::KSHIFTRB | + Opcode::KXNORB | + Opcode::KXORB | + Opcode::KADDW | + Opcode::KANDW | + Opcode::KANDNW | + Opcode::KNOTW | + Opcode::KORW | + Opcode::KSHIFTLW | + Opcode::KSHIFTRW | + Opcode::KXNORW | + Opcode::KXORW | + Opcode::KADDD | + Opcode::KANDD | + Opcode::KANDND | + Opcode::KNOTD | + Opcode::KORD | + Opcode::KSHIFTLD | + Opcode::KSHIFTRD | + Opcode::KXNORD | + Opcode::KXORD | + Opcode::KADDQ | + Opcode::KANDQ | + Opcode::KANDNQ | + Opcode::KNOTQ | + Opcode::KORQ | + Opcode::KSHIFTLQ | + Opcode::KSHIFTRQ | + Opcode::KXNORQ | + Opcode::KXORQ | Opcode::IMUL => { write!(out, "{}", colors.arithmetic_op(self)) } Opcode::POPF | Opcode::PUSHF | @@ -1786,12 +2441,43 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VCVTSS2SI | Opcode::VCVTTSD2SI | Opcode::VCVTTSS2SI | + Opcode::VCVTPD2UDQ | + Opcode::VCVTTPD2UDQ | + Opcode::VCVTPS2UDQ | + Opcode::VCVTTPS2UDQ | + Opcode::VCVTQQ2PD | + Opcode::VCVTQQ2PS | + Opcode::VCVTSD2USI | + Opcode::VCVTTSD2USI | + Opcode::VCVTSS2USI | + Opcode::VCVTTSS2USI | + Opcode::VCVTUDQ2PD | + Opcode::VCVTUDQ2PS | + Opcode::VCVTUSI2USD | + Opcode::VCVTUSI2USS | + Opcode::VCVTTPD2QQ | + Opcode::VCVTPD2QQ | + Opcode::VCVTTPD2UQQ | + Opcode::VCVTPD2UQQ | + Opcode::VCVTTPS2QQ | + Opcode::VCVTPS2QQ | + Opcode::VCVTTPS2UQQ | + Opcode::VCVTPS2UQQ | + Opcode::VCVTUQQ2PD | + Opcode::VCVTUQQ2PS | Opcode::VMOVDDUP | Opcode::VPSHUFLW | + Opcode::VPSHUFHW | + Opcode::VBLENDMPD | + Opcode::VBLENDMPS | + Opcode::VPBLENDMD | + Opcode::VPBLENDMQ | Opcode::VBLENDPD | Opcode::VBLENDPS | Opcode::VBLENDVPD | Opcode::VBLENDVPS | + Opcode::VPBLENDMB | + Opcode::VPBLENDMW | Opcode::PBLENDVB | Opcode::PBLENDW | Opcode::BLENDPD | @@ -1803,6 +2489,7 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VBROADCASTI128 | Opcode::VBROADCASTSD | Opcode::VBROADCASTSS | + Opcode::VPBROADCASTM | Opcode::VEXTRACTF128 | Opcode::VEXTRACTI128 | Opcode::VEXTRACTPS | @@ -1811,10 +2498,49 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VGATHERDPS | Opcode::VGATHERQPD | Opcode::VGATHERQPS | + Opcode::VGATHERPF0DPD | + Opcode::VGATHERPF0DPS | + Opcode::VGATHERPF0QPD | + Opcode::VGATHERPF0QPS | + Opcode::VGATHERPF1DPD | + Opcode::VGATHERPF1DPS | + Opcode::VGATHERPF1QPD | + Opcode::VGATHERPF1QPS | + Opcode::VSCATTERDD | + Opcode::VSCATTERDQ | + Opcode::VSCATTERQD | + Opcode::VSCATTERQQ | + Opcode::VPSCATTERDD | + Opcode::VPSCATTERDQ | + Opcode::VPSCATTERQD | + Opcode::VPSCATTERQQ | + Opcode::VSCATTERPF0DPD | + Opcode::VSCATTERPF0DPS | + Opcode::VSCATTERPF0QPD | + Opcode::VSCATTERPF0QPS | + Opcode::VSCATTERPF1DPD | + Opcode::VSCATTERPF1DPS | + Opcode::VSCATTERPF1QPD | + Opcode::VSCATTERPF1QPS | Opcode::VINSERTF128 | Opcode::VINSERTI128 | Opcode::VINSERTPS | Opcode::INSERTPS | + Opcode::VEXTRACTF32X4 | + Opcode::VEXTRACTF64X2 | + Opcode::VEXTRACTF64X4 | + Opcode::VEXTRACTI32X4 | + Opcode::VEXTRACTI64X2 | + Opcode::VEXTRACTI64X4 | + Opcode::VINSERTF32X4 | + Opcode::VINSERTF64X2 | + Opcode::VINSERTF64X4 | + Opcode::VINSERTI64X2 | + Opcode::VINSERTI64X4 | + Opcode::VSHUFF32X4 | + Opcode::VSHUFF64X2 | + Opcode::VSHUFI32X4 | + Opcode::VSHUFI64X2 | Opcode::VMASKMOVDQU | Opcode::VMASKMOVPD | Opcode::VMASKMOVPS | @@ -1845,6 +2571,32 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VMOVUPS | Opcode::VMOVSD | Opcode::VMOVSS | + Opcode::VMOVDQA32 | + Opcode::VMOVDQA64 | + Opcode::VMOVDQU32 | + Opcode::VMOVDQU64 | + Opcode::VPMOVM2B | + Opcode::VPMOVM2W | + Opcode::VPMOVB2M | + Opcode::VPMOVW2M | + Opcode::VPMOVSWB | + Opcode::VPMOVUSWB | + Opcode::VPMOVSQB | + Opcode::VPMOVUSQB | + Opcode::VPMOVSQW | + Opcode::VPMOVUSQW | + Opcode::VPMOVSQD | + Opcode::VPMOVUSQD | + Opcode::VPMOVSDB | + Opcode::VPMOVUSDB | + Opcode::VPMOVSDW | + Opcode::VPMOVUSDW | + Opcode::VPMOVM2D | + Opcode::VPMOVM2Q | + Opcode::VPMOVB2D | + Opcode::VPMOVQ2M | + Opcode::VMOVDQU8 | + Opcode::VMOVDQU16 | Opcode::VPBLENDD | Opcode::VPBLENDVB | @@ -1883,6 +2635,9 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::PMOVZXDQ | Opcode::PMOVZXWD | Opcode::PMOVZXWQ | + Opcode::KUNPCKBW | + Opcode::KUNPCKWD | + Opcode::KUNPCKDQ | Opcode::VUNPCKHPD | Opcode::VUNPCKHPS | Opcode::VUNPCKLPD | @@ -1898,9 +2653,12 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VSHUFPD | Opcode::VSHUFPS | Opcode::VPACKSSDW | + Opcode::VPACKUSDW | Opcode::PACKUSDW | Opcode::VPACKSSWB | Opcode::VPACKUSWB | + Opcode::VALIGND | + Opcode::VALIGNQ | Opcode::VPALIGNR | Opcode::PALIGNR | Opcode::VPERM2F128 | @@ -1911,6 +2669,17 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPERMPD | Opcode::VPERMPS | Opcode::VPERMQ | + Opcode::VPERMI2D | + Opcode::VPERMI2Q | + Opcode::VPERMI2PD | + Opcode::VPERMI2PS | + Opcode::VPERMT2D | + Opcode::VPERMT2Q | + Opcode::VPERMT2PD | + Opcode::VPERMT2PS | + Opcode::VPERMI2B | + Opcode::VPERMI2W | + Opcode::VPERMW | Opcode::VPEXTRB | Opcode::VPEXTRD | Opcode::VPEXTRQ | @@ -1929,11 +2698,34 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPINSRW | Opcode::VPMASKMOVD | Opcode::VPMASKMOVQ | + Opcode::VCOMPRESSPD | + Opcode::VCOMPRESSPS | + Opcode::VPCOMPRESSQ | + Opcode::VPCOMPRESSD | + Opcode::VEXPANDPD | + Opcode::VEXPANDPS | Opcode::VPSHUFB | Opcode::VPSHUFD | Opcode::VPHMINPOSUW | Opcode::PHMINPOSUW | Opcode::VZEROUPPER | + Opcode::VZEROALL | + Opcode::VFIXUPIMMPD | + Opcode::VFIXUPIMMPS | + Opcode::VFIXUPIMMSD | + Opcode::VFIXUPIMMSS | + Opcode::VREDUCEPD | + Opcode::VREDUCEPS | + Opcode::VREDUCESD | + Opcode::VREDUCESS | + Opcode::VGETEXPPD | + Opcode::VGETEXPPS | + Opcode::VGETEXPSD | + Opcode::VGETEXPSS | + Opcode::VGETMANTPD | + Opcode::VGETMANTPS | + Opcode::VGETMANTSD | + Opcode::VGETMANTSS | Opcode::VLDDQU | Opcode::BSWAP | Opcode::CVTDQ2PD | @@ -2001,6 +2793,11 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::SHUFPD | Opcode::SHUFPS | Opcode::PMOVMSKB | + Opcode::KMOVB | + Opcode::KMOVW | + Opcode::KMOVD | + Opcode::KMOVQ | + Opcode::BNDMOV | Opcode::LDDQU | Opcode::CMC | Opcode::CLC | @@ -2117,6 +2914,32 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VCOMISS | Opcode::VUCOMISD | Opcode::VUCOMISS | + Opcode::KORTESTB | + Opcode::KTESTB | + Opcode::KORTESTW | + Opcode::KTESTW | + Opcode::KORTESTD | + Opcode::KTESTD | + Opcode::KORTESTQ | + Opcode::KTESTQ | + Opcode::VPTESTNMD | + Opcode::VPTESTNMQ | + Opcode::VPTERNLOGD | + Opcode::VPTERNLOGQ | + Opcode::VPTESTMD | + Opcode::VPTESTMQ | + Opcode::VPTESTNMB | + Opcode::VPTESTNMW | + Opcode::VPTESTMB | + Opcode::VPTESTMW | + Opcode::VPCMPD | + Opcode::VPCMPUD | + Opcode::VPCMPQ | + Opcode::VPCMPUQ | + Opcode::VPCMPB | + Opcode::VPCMPUB | + Opcode::VPCMPW | + Opcode::VPCMPUW | Opcode::VCMPPD | Opcode::VCMPPS | Opcode::VCMPSD | @@ -2125,6 +2948,10 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VMAXPS | Opcode::VMAXSD | Opcode::VMAXSS | + Opcode::VPMAXSQ | + Opcode::VPMAXUQ | + Opcode::VPMINSQ | + Opcode::VPMINUQ | Opcode::VMINPD | Opcode::VMINPS | Opcode::VMINSD | @@ -2137,6 +2964,8 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPCMPGTD | Opcode::VPCMPGTQ | Opcode::VPCMPGTW | + Opcode::VPCMPESTRI | + Opcode::VPCMPESTRM | Opcode::VPCMPISTRI | Opcode::VPCMPISTRM | Opcode::VPMAXSB | @@ -2145,9 +2974,22 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::VPMAXUB | Opcode::VPMAXUW | Opcode::VPMAXUD | + Opcode::VPMINSB | Opcode::VPMINSW | Opcode::VPMINSD | + Opcode::VPMINUB | + Opcode::VPMINUW | Opcode::VPMINUD | + Opcode::VFPCLASSPD | + Opcode::VFPCLASSPS | + Opcode::VFPCLASSSD | + Opcode::VFPCLASSSS | + Opcode::VRANGEPD | + Opcode::VRANGEPS | + Opcode::VRANGESD | + Opcode::VRANGESS | + Opcode::VPCONFLICTD | + Opcode::VPCONFLICTQ | Opcode::VPTEST | Opcode::VTESTPD | Opcode::VTESTPS | @@ -2228,6 +3070,8 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::FXRSTOR | Opcode::LDMXCSR | Opcode::STMXCSR | + Opcode::VLDMXCSR | + Opcode::VSTMXCSR | Opcode::XSAVE | Opcode::XSAVEC | Opcode::XSAVES | @@ -2337,7 +3181,14 @@ impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Opcode { Opcode::SENDUIPI | Opcode::XSUSLDTRK | Opcode::XRESLDTRK | + Opcode::BOUND | Opcode::ARPL | + Opcode::BNDMK | + Opcode::BNDCL | + Opcode::BNDCU | + Opcode::BNDCN | + Opcode::BNDLDX | + Opcode::BNDSTX | Opcode::LAR => { write!(out, "{}", colors.platform_op(self)) } Opcode::CRC32 | @@ -2462,6 +3313,17 @@ impl Instruction { } } +const MEM_SIZE_STRINGS: [&'static str; 64] = [ + "byte", "word", "BUG", "dword", "BUG", "BUG", "BUG", "qword", + "far", "mword", "BUG", "BUG", "BUG", "BUG", "BUG", "xmmword", + "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "ymmword", + "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", + "BUG", "BUG", "BUG", "BUG", "BUG", "BUG", "ptr", "zmmword", +]; + fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result { if instr.prefixes.lock() { write!(out, "lock ")?; @@ -2469,11 +3331,8 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: if instr.prefixes.rep_any() { if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&instr.opcode) { - // only a few of you actually use the prefix... if instr.prefixes.rep() { write!(out, "rep ")?; - } else if instr.prefixes.repz() { - write!(out, "repz ")?; } else if instr.prefixes.repnz() { write!(out, "repnz ")?; } @@ -2489,53 +3348,19 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: if instr.operand_count > 0 { out.write_str(" ")?; + let x = Operand::from_spec(instr, instr.operands[0]); + if x.is_memory() { + out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize - 1])?; + out.write_str(" ")?; + } + if let Some(prefix) = instr.segment_override_for_op(0) { write!(out, "{}:", prefix)?; } - - let x = Operand::from_spec(instr, instr.operands[0]); x.colorize(colors, out)?; for i in 1..instr.operand_count { match instr.opcode { - Opcode::MOVSX_b | - Opcode::MOVZX_b => { - match &instr.operands[i as usize] { - &OperandSpec::Nothing => { - return Ok(()); - }, - &OperandSpec::RegMMM => { - out.write_str(", ")?; - } - _ => { - out.write_str(", byte ")?; - if let Some(prefix) = instr.segment_override_for_op(i) { - write!(out, "{}:", prefix)?; - } - } - } - let x = Operand::from_spec(instr, instr.operands[i as usize]); - x.colorize(colors, out)? - }, - Opcode::MOVSX_w | - Opcode::MOVZX_w => { - match &instr.operands[i as usize] { - &OperandSpec::Nothing => { - return Ok(()); - }, - &OperandSpec::RegMMM => { - out.write_str(", ")?; - } - _ => { - out.write_str(", word ")?; - if let Some(prefix) = instr.segment_override_for_op(i) { - write!(out, "{}:", prefix)?; - } - } - } - let x = Operand::from_spec(instr, instr.operands[i as usize]); - x.colorize(colors, out)? - }, _ => { match &instr.operands[i as usize] { &OperandSpec::Nothing => { @@ -2543,11 +3368,57 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: }, _ => { out.write_str(", ")?; + let x = Operand::from_spec(instr, instr.operands[i as usize]); + if x.is_memory() { + out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize - 1])?; + out.write_str(" ")?; + } if let Some(prefix) = instr.segment_override_for_op(i) { write!(out, "{}:", prefix)?; } - let x = Operand::from_spec(instr, instr.operands[i as usize]); - x.colorize(colors, out)? + x.colorize(colors, out)?; + if let Some(evex) = instr.prefixes.evex() { + if evex.broadcast() && x.is_memory() { + let scale = if instr.opcode == Opcode::VCVTPD2PS || instr.opcode == Opcode::VCVTTPD2UDQ || instr.opcode == Opcode::VCVTPD2UDQ || instr.opcode == Opcode::VCVTUDQ2PD || instr.opcode == Opcode::VCVTPS2PD || instr.opcode == Opcode::VCVTQQ2PS || instr.opcode == Opcode::VCVTDQ2PD || instr.opcode == Opcode::VCVTTPD2DQ || instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VFPCLASSPD || instr.opcode == Opcode::VCVTNEPS2BF16 || instr.opcode == Opcode::VCVTUQQ2PS || instr.opcode == Opcode::VCVTPD2DQ || instr.opcode == Opcode::VCVTTPS2UQQ || instr.opcode == Opcode::VCVTPS2UQQ || instr.opcode == Opcode::VCVTTPS2QQ || instr.opcode == Opcode::VCVTPS2QQ { + if instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VCVTNEPS2BF16 { + if evex.vex().l() { + 8 + } else if evex.lp() { + 16 + } else { + 4 + } + } else if instr.opcode == Opcode::VFPCLASSPD { + if evex.vex().l() { + 4 + } else if evex.lp() { + 8 + } else { + 2 + } + } else { + // vcvtpd2ps is "cool": in broadcast mode, it can read a + // double-precision float (qword), resize to single-precision, + // then broadcast that to the whole destination register. this + // means we need to show `xmm, qword [addr]{1to4}` if vector + // size is 256. likewise, scale of 8 for the same truncation + // reason if vector size is 512. + // vcvtudq2pd is the same story. + // vfpclassp{s,d} is a mystery to me. + if evex.vex().l() { + 4 + } else if evex.lp() { + 8 + } else { + 2 + } + } + } else { + Operand::from_spec(instr, instr.operands[i as usize - 1]).width() / instr.mem_size + }; + write!(out, "{{1to{}}}", scale)?; + } + } } } } @@ -2578,8 +3449,6 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, _colors: &Y // only a few of you actually use the prefix... if instr.prefixes.rep() { out.write_str("rep ")?; - } else if instr.prefixes.repz() { - out.write_str("repz ")?; } else if instr.prefixes.repnz() { out.write_str("repnz ")?; } // TODO: other rep kinds? @@ -2804,8 +3673,6 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St // only a few of you actually use the prefix... if self.prefixes.rep() { write!(out, "rep ")?; - } else if self.prefixes.repz() { - write!(out, "repz ")?; } else if self.prefixes.repnz() { write!(out, "repnz ")?; } @@ -2831,7 +3698,8 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St x.colorize(colors, out)?; } }; - for i in 1..4 { + for i in 1..self.operand_count { + let i = i as usize; match self.opcode { Opcode::MOVSX_b | Opcode::MOVZX_b => { diff --git a/src/protected_mode/evex.rs b/src/protected_mode/evex.rs new file mode 100644 index 0000000..9d2a093 --- /dev/null +++ b/src/protected_mode/evex.rs @@ -0,0 +1,17 @@ +// use crate::long_mode::{OperandSpec, DecodeError, RegSpec, RegisterBank, Instruction, Opcode}; +use crate::protected_mode::{DecodeError, RegSpec, RegisterBank, Instruction, Opcode}; +use crate::protected_mode::{read_modrm, read_E_vex, read_imm_unsigned}; + +const DEFAULT_EVEX_REGISTER_SIZE: RegisterBank = RegisterBank::D; +const DEFAULT_EVEX_REGISTER_WIDTH: u8 = 4; + +fn isa_has_qwords() -> bool { + false +} + +fn apply_disp_scale(inst: &mut Instruction) { + inst.disp *= inst.mem_size as u32; +} + +include!("../shared/generated_evex.in"); +include!("../shared/evex.in"); diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs index bbcb9cb..dec7c86 100644 --- a/src/protected_mode/mod.rs +++ b/src/protected_mode/mod.rs @@ -1,4 +1,5 @@ mod vex; +mod evex; #[cfg(feature = "fmt")] mod display; pub mod uarch; @@ -131,6 +132,19 @@ impl RegSpec { } } + /// construct a `RegSpec` for mask reg `num` + #[inline] + pub fn mask(num: u8) -> RegSpec { + if num >= 32 { + panic!("invalid x86 mask reg {}", num); + } + + RegSpec { + num, + bank: RegisterBank::K + } + } + /// construct a `RegSpec` for dword reg `num` #[inline] pub fn d(num: u8) -> RegSpec { @@ -378,6 +392,9 @@ pub enum Operand { ImmediateU32(u32), ImmediateI32(i32), Register(RegSpec), + RegisterMaskMerge(RegSpec, RegSpec, MergeMode), + RegisterMaskMergeSae(RegSpec, RegSpec, MergeMode, SaeMode), + RegisterMaskMergeSaeNoround(RegSpec, RegSpec, MergeMode), DisplacementU16(u16), DisplacementU32(u32), RegDeref(RegSpec), @@ -388,10 +405,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::DispU16 | @@ -405,7 +444,13 @@ impl OperandSpec { OperandSpec::RegIndexBaseDisp | 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 | @@ -414,8 +459,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 => { @@ -424,6 +475,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 { @@ -434,13 +533,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 }) } @@ -482,6 +624,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) + } + } } } pub fn is_memory(&self) -> bool { @@ -495,7 +679,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(_) | @@ -505,6 +697,9 @@ impl Operand { Operand::ImmediateU32(_) | Operand::ImmediateI32(_) | Operand::Register(_) | + Operand::RegisterMaskMerge(_, _, _) | + Operand::RegisterMaskMergeSae(_, _, _, _) | + Operand::RegisterMaskMergeSaeNoround(_, _, _) | Operand::Nothing => { false } @@ -523,6 +718,9 @@ impl Operand { Operand::Register(reg) => { reg.width() } + Operand::RegisterMaskMerge(reg, _, _) => { + reg.width() + } Operand::ImmediateI8(_) | Operand::ImmediateU8(_) => { 1 @@ -1186,6 +1384,7 @@ pub enum Opcode { VMOVDDUP, VPSHUFLW, + VPSHUFHW, VHADDPS, VHSUBPS, VADDSUBPS, @@ -1358,6 +1557,7 @@ pub enum Opcode { VPABSD, VPABSW, VPACKSSDW, + VPACKUSDW, VPACKSSWB, VPACKUSWB, VPADDB, @@ -1395,6 +1595,8 @@ pub enum Opcode { VPCMPGTD, VPCMPGTQ, VPCMPGTW, + VPCMPESTRI, + VPCMPESTRM, VPCMPISTRI, VPCMPISTRM, VPERM2F128, @@ -1416,7 +1618,7 @@ pub enum Opcode { VPHADDD, VPHADDSW, VPHADDW, - VPHADDUBSW, + VPMADDUBSW, VPHMINPOSUW, VPHSUBD, VPHSUBSW, @@ -1434,8 +1636,11 @@ pub enum Opcode { VPMAXUB, VPMAXUW, VPMAXUD, + VPMINSB, VPMINSW, VPMINSD, + VPMINUB, + VPMINUW, VPMINUD, VPMOVMSKB, VPMOVSXBD, @@ -1454,6 +1659,7 @@ pub enum Opcode { VPMULHRSW, VPMULHUW, VPMULHW, + VPMULLQ, VPMULLD, VPMULLW, VPMULUDQ, @@ -1524,6 +1730,9 @@ pub enum Opcode { VXORPD, VXORPS, VZEROUPPER, + VZEROALL, + VLDMXCSR, + VSTMXCSR, PCLMULQDQ, AESKEYGENASSIST, @@ -1763,6 +1972,7 @@ pub enum Opcode { PUSHA, POPA, + BOUND, ARPL, AAS, AAA, @@ -1863,6 +2073,376 @@ pub enum Opcode { // TSXLDTRK XSUSLDTRK, XRESLDTRK, + + // AVX512F + VALIGND, + VALIGNQ, + VBLENDMPD, + VBLENDMPS, + VCOMPRESSPD, + VCOMPRESSPS, + VCVTPD2UDQ, + VCVTTPD2UDQ, + VCVTPS2UDQ, + VCVTTPS2UDQ, + VCVTQQ2PD, + VCVTQQ2PS, + VCVTSD2USI, + VCVTTSD2USI, + VCVTSS2USI, + VCVTTSS2USI, + VCVTUDQ2PD, + VCVTUDQ2PS, + VCVTUSI2USD, + VCVTUSI2USS, + VEXPANDPD, + VEXPANDPS, + VEXTRACTF32X4, + VEXTRACTF64X4, + VEXTRACTI32X4, + VEXTRACTI64X4, + VFIXUPIMMPD, + VFIXUPIMMPS, + VFIXUPIMMSD, + VFIXUPIMMSS, + VGETEXPPD, + VGETEXPPS, + VGETEXPSD, + VGETEXPSS, + VGETMANTPD, + VGETMANTPS, + VGETMANTSD, + VGETMANTSS, + VINSERTF32X4, + VINSERTF64X4, + VINSERTI64X4, + VMOVDQA32, + VMOVDQA64, + VMOVDQU32, + VMOVDQU64, + VPBLENDMD, + VPBLENDMQ, + VPCMPD, + VPCMPUD, + VPCMPQ, + VPCMPUQ, + VPCOMPRESSQ, + VPCOMPRESSD, + VPERMI2D, + VPERMI2Q, + VPERMI2PD, + VPERMI2PS, + VPERMT2D, + VPERMT2Q, + VPERMT2PD, + VPERMT2PS, + VPMAXSQ, + VPMAXUQ, + VPMINSQ, + VPMINUQ, + VPMOVSQB, + VPMOVUSQB, + VPMOVSQW, + VPMOVUSQW, + VPMOVSQD, + VPMOVUSQD, + VPMOVSDB, + VPMOVUSDB, + VPMOVSDW, + VPMOVUSDW, + VPROLD, + VPROLQ, + VPROLVD, + VPROLVQ, + VPRORD, + VPRORQ, + VPRORRD, + VPRORRQ, + VPSCATTERDD, + VPSCATTERDQ, + VPSCATTERQD, + VPSCATTERQQ, + VPSRAQ, + VPSRAVQ, + VPTESTNMD, + VPTESTNMQ, + VPTERNLOGD, + VPTERNLOGQ, + VPTESTMD, + VPTESTMQ, + VRCP14PD, + VRCP14PS, + VRCP14SD, + VRCP14SS, + VRNDSCALEPD, + VRNDSCALEPS, + VRNDSCALESD, + VRNDSCALESS, + VRSQRT14PD, + VRSQRT14PS, + VRSQRT14SD, + VRSQRT14SS, + VSCALEDPD, + VSCALEDPS, + VSCALEDSD, + VSCALEDSS, + VSCATTERDD, + VSCATTERDQ, + VSCATTERQD, + VSCATTERQQ, + VSHUFF32X4, + VSHUFF64X2, + VSHUFI32X4, + VSHUFI64X2, + + // AVX512DQ + VCVTTPD2QQ, + VCVTPD2QQ, + VCVTTPD2UQQ, + VCVTPD2UQQ, + VCVTTPS2QQ, + VCVTPS2QQ, + VCVTTPS2UQQ, + VCVTPS2UQQ, + VCVTUQQ2PD, + VCVTUQQ2PS, + VEXTRACTF64X2, + VEXTRACTI64X2, + VFPCLASSPD, + VFPCLASSPS, + VFPCLASSSD, + VFPCLASSSS, + VINSERTF64X2, + VINSERTI64X2, + VPMOVM2D, + VPMOVM2Q, + VPMOVB2D, + VPMOVQ2M, + VRANGEPD, + VRANGEPS, + VRANGESD, + VRANGESS, + VREDUCEPD, + VREDUCEPS, + VREDUCESD, + VREDUCESS, + + // AVX512BW + VDBPSADBW, + VMOVDQU8, + VMOVDQU16, + VPBLENDMB, + VPBLENDMW, + VPCMPB, + VPCMPUB, + VPCMPW, + VPCMPUW, + VPERMW, + VPERMI2B, + VPERMI2W, + VPMOVM2B, + VPMOVM2W, + VPMOVB2M, + VPMOVW2M, + VPMOVSWB, + VPMOVUSWB, + VPSLLVW, + VPSRAVW, + VPSRLVW, + VPTESTNMB, + VPTESTNMW, + VPTESTMB, + VPTESTMW, + + // AVX512CD + VPBROADCASTM, + VPCONFLICTD, + VPCONFLICTQ, + VPLZCNTD, + VPLZCNTQ, + + KUNPCKBW, + KUNPCKWD, + KUNPCKDQ, + + KADDB, + KANDB, + KANDNB, + KMOVB, + KNOTB, + KORB, + KORTESTB, + KSHIFTLB, + KSHIFTRB, + KTESTB, + KXNORB, + KXORB, + KADDW, + KANDW, + KANDNW, + KMOVW, + KNOTW, + KORW, + KORTESTW, + KSHIFTLW, + KSHIFTRW, + KTESTW, + KXNORW, + KXORW, + KADDD, + KANDD, + KANDND, + KMOVD, + KNOTD, + KORD, + KORTESTD, + KSHIFTLD, + KSHIFTRD, + KTESTD, + KXNORD, + KXORD, + KADDQ, + KANDQ, + KANDNQ, + KMOVQ, + KNOTQ, + KORQ, + KORTESTQ, + KSHIFTLQ, + KSHIFTRQ, + KTESTQ, + KXNORQ, + KXORQ, + + // AVX512ER + VEXP2PD, + VEXP2PS, + VEXP2SD, + VEXP2SS, + VRCP28PD, + VRCP28PS, + VRCP28SD, + VRCP28SS, + VRSQRT28PD, + VRSQRT28PS, + VRSQRT28SD, + VRSQRT28SS, + + // AVX512PF + VGATHERPF0DPD, + VGATHERPF0DPS, + VGATHERPF0QPD, + VGATHERPF0QPS, + VGATHERPF1DPD, + VGATHERPF1DPS, + VGATHERPF1QPD, + VGATHERPF1QPS, + VSCATTERPF0DPD, + VSCATTERPF0DPS, + VSCATTERPF0QPD, + VSCATTERPF0QPS, + VSCATTERPF1DPD, + VSCATTERPF1DPS, + VSCATTERPF1QPD, + VSCATTERPF1QPS, + + // MPX + BNDMK, + BNDCL, + BNDCU, + BNDCN, + BNDMOV, + BNDLDX, + BNDSTX, + + VGF2P8AFFINEQB, + VGF2P8AFFINEINVQB, + VPSHRDQ, + VPSHRDD, + VPSHRDW, + VPSHLDQ, + VPSHLDD, + VPSHLDW, + VBROADCASTF32X8, + VBROADCASTF64X4, + VBROADCASTF32X4, + VBROADCASTF64X2, + VBROADCASTF32X2, + VBROADCASTI32X8, + VBROADCASTI64X4, + VBROADCASTI32X4, + VBROADCASTI64X2, + VBROADCASTI32X2, + VEXTRACTI32X8, + VEXTRACTF32X8, + VINSERTI32X8, + VINSERTF32X8, + VINSERTI32X4, + V4FNMADDSS, + V4FNMADDPS, + VCVTNEPS2BF16, + V4FMADDSS, + V4FMADDPS, + VCVTNE2PS2BF16, + VP2INTERSECTD, + VP2INTERSECTQ, + VP4DPWSSDS, + VP4DPWSSD, + VPDPWSSDS, + VPDPWSSD, + VPDPBUSDS, + VDPBF16PS, + VPBROADCASTMW2D, + VPBROADCASTMB2Q, + VPMOVD2M, + VPMOVQD, + VPMOVWB, + VPMOVDB, + VPMOVDW, + VPMOVQB, + VPMOVQW, + VGF2P8MULB, + VPMADD52HUQ, + VPMADD52LUQ, + VPSHUFBITQMB, + VPERMB, + VPEXPANDD, + VPEXPANDQ, + VPABSQ, + VPRORVD, + VPRORVQ, + VPMULTISHIFTQB, + VPERMT2B, + VPERMT2W, + VPSHRDVQ, + VPSHRDVD, + VPSHRDVW, + VPSHLDVQ, + VPSHLDVD, + VPSHLDVW, + VPCOMPRESSB, + VPCOMPRESSW, + VPEXPANDB, + VPEXPANDW, + VPOPCNTD, + VPOPCNTQ, + VPOPCNTB, + VPOPCNTW, + VSCALEFSS, + VSCALEFSD, + VSCALEFPS, + VSCALEFPD, + VPDPBUSD, + VCVTUSI2SD, + VCVTUSI2SS, + VPXORD, + VPXORQ, + VPORD, + VPORQ, + VPANDND, + VPANDNQ, + VPANDD, + VPANDQ, } #[derive(Debug)] @@ -1889,7 +2469,7 @@ impl yaxpeax_arch::Instruction for Instruction { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq, Copy, Clone)] #[non_exhaustive] pub enum DecodeError { ExhaustedInput, @@ -1912,10 +2492,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, @@ -1940,7 +2534,13 @@ enum OperandSpec { RegIndexBaseDisp, 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. @@ -2460,6 +3060,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 } @@ -2659,6 +3300,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() { @@ -2835,6 +3483,7 @@ impl InstDecoder { // AVX... Opcode::VMOVDDUP | Opcode::VPSHUFLW | + Opcode::VPSHUFHW | Opcode::VHADDPS | Opcode::VHSUBPS | Opcode::VADDSUBPS | @@ -2998,6 +3647,7 @@ impl InstDecoder { Opcode::VPABSD | Opcode::VPABSW | Opcode::VPACKSSDW | + Opcode::VPACKUSDW | Opcode::VPACKSSWB | Opcode::VPACKUSWB | Opcode::VPADDB | @@ -3056,7 +3706,7 @@ impl InstDecoder { Opcode::VPHADDD | Opcode::VPHADDSW | Opcode::VPHADDW | - Opcode::VPHADDUBSW | + Opcode::VPMADDUBSW | Opcode::VPHMINPOSUW | Opcode::VPHSUBD | Opcode::VPHSUBSW | @@ -3094,6 +3744,7 @@ impl InstDecoder { Opcode::VPMULHRSW | Opcode::VPMULHUW | Opcode::VPMULHW | + Opcode::VPMULLQ | Opcode::VPMULLD | Opcode::VPMULLW | Opcode::VPMULUDQ | @@ -3525,15 +4176,51 @@ impl Instruction { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct EvexData { + // data: present, z, b, Lp, Rp. aaa + bits: u8, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub struct Prefixes { bits: u8, vex: PrefixVex, segment: Segment, - _pad: u8, + evex_data: EvexData, +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] +pub struct PrefixEvex { + vex: PrefixVex, + evex_data: EvexData, } -#[derive(Debug, Copy, Clone)] +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, Eq, PartialEq)] pub struct PrefixVex { bits: u8, } @@ -3552,6 +4239,8 @@ impl PrefixVex { fn l(&self) -> bool { (self.bits & 0x10) == 0x10 } #[inline] fn present(&self) -> bool { (self.bits & 0x80) == 0x80 } + #[inline] + fn compressed_disp(&self) -> bool { (self.bits & 0x20) == 0x20 } } #[allow(dead_code)] @@ -3561,7 +4250,7 @@ impl Prefixes { bits: bits, vex: PrefixVex { bits: 0 }, segment: Segment::DS, - _pad: 0, + evex_data: EvexData { bits: 0 }, } } fn vex_from(&mut self, bits: u8) { @@ -3623,6 +4312,26 @@ impl Prefixes { fn set_ss(&mut self) { self.segment = Segment::SS } #[inline] fn vex(&self) -> PrefixVex { PrefixVex { bits: self.vex.bits } } + #[inline] + fn evex_unchecked(&self) -> PrefixEvex { PrefixEvex { vex: PrefixVex { bits: self.vex.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 apply_compressed_disp(&mut self, state: bool) { + if state { + self.vex.bits |= 0x20; + } else { + self.vex.bits &= 0xdf; + } + } #[inline] fn vex_from_c5(&mut self, bits: u8) { @@ -3640,8 +4349,65 @@ impl Prefixes { let rxb = (high >> 5) ^ 0x07; let wrxb = rxb | w >> 4; let l = (low & 0x04) << 2; - let synthetic_rex = wrxb | l | 0x80; - self.vex = PrefixVex { bits: synthetic_rex }; + let synthetic_vex = wrxb | l | 0x80; + self.vex = PrefixVex { bits: synthetic_vex }; + } + + #[inline] + fn evex_from(&mut self, b1: u8, b2: u8, b3: u8) { + let w = b2 & 0x80; + let rxb = ((b1 >> 5) & 0b111) ^ 0b111; // `rxb` is provided in inverted form + let wrxb = rxb | (w >> 4); + let l = (b3 & 0x20) >> 1; + let synthetic_vex = wrxb | l | 0x80; + self.vex_from(synthetic_vex); + + // R' is provided in inverted form + let rp = ((b1 & 0x10) >> 4) ^ 1; + let lp = (b3 & 0x40) >> 6; + let aaa = b3 & 0b111; + let z = (b3 & 0x80) >> 7; + let b = (b3 & 0x10) >> 4; + self.evex_data.from(rp, lp, z, b, aaa); + } +} + +impl EvexData { + fn from(&mut self, rp: u8, lp: u8, z: u8, b: u8, aaa: u8) { + let mut bits = 0; + bits |= aaa; + bits |= b << 3; + bits |= z << 4; + bits |= lp << 5; + bits |= rp << 6; + bits |= 0x80; + self.bits = bits; + } +} + +impl EvexData { + pub(crate) fn present(&self) -> bool { + self.bits & 0b1000_0000 != 0 + } + + pub(crate) fn aaa(&self) -> u8 { + self.bits & 0b111 + } + + pub(crate) fn b(&self) -> bool { + (self.bits & 0b0000_1000) != 0 + } + + pub(crate) fn z(&self) -> bool { + (self.bits & 0b0001_0000) != 0 + } + + pub(crate) fn lp(&self) -> bool { + (self.bits & 0b0010_0000) != 0 + } + + pub(crate) fn rp(&self) -> bool { + (self.bits & 0b0100_0000) != 0 } } @@ -4179,6 +4945,7 @@ enum OperandCode { CS = OperandCodeBuilder::new().special_case(104).bits(), SS = OperandCodeBuilder::new().special_case(105).bits(), DS = OperandCodeBuilder::new().special_case(106).bits(), + ModRM_0x62 = OperandCodeBuilder::new().special_case(107).bits(), } const LOCKABLE_INSTRUCTIONS: &[Opcode] = &[ @@ -4345,7 +5112,7 @@ const OPCODES: [OpcodeRecord; 256] = [ // 0x60 OpcodeRecord(Interpretation::Instruction(Opcode::PUSHA), OperandCode::Nothing), OpcodeRecord(Interpretation::Instruction(Opcode::POPA), OperandCode::Nothing), - OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing), + OpcodeRecord(Interpretation::Instruction(Opcode::BOUND), OperandCode::ModRM_0x62), OpcodeRecord(Interpretation::Instruction(Opcode::ARPL), OperandCode::Ew_Gw), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), OpcodeRecord(Interpretation::Prefix, OperandCode::Nothing), @@ -4567,6 +5334,18 @@ 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_vex<T: Iterator<Item=u8>>(bytes_iter: &mut T, instr: &mut Instruction, modrm: u8, length: &mut u8, bank: RegisterBank) -> Result<OperandSpec, DecodeError> { + if modrm >= 0b11000000 { + read_modrm_reg(instr, modrm, bank) + } else { + let res = read_M(bytes_iter, instr, modrm, length)?; + if (modrm & 0b01_000_000) == 0b01_000_000 { + instr.prefixes.apply_compressed_disp(true); + } + Ok(res) + } +} #[allow(non_snake_case)] fn read_modrm_reg(instr: &mut Instruction, modrm: u8, reg_bank: RegisterBank) -> Result<OperandSpec, DecodeError> { @@ -8679,6 +9458,35 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter instruction.operands[1] = instruction.operands[0]; instruction.operands[0] = temp; } + OperandCode::ModRM_0x62 => { + let modrm = read_modrm(&mut bytes_iter, length)?; + + if modrm < 0xc0 { + instruction.modrm_rrr = + RegSpec { bank: RegisterBank::D, num: (modrm >> 3) & 7 }; + if instruction.prefixes.operand_size() { + instruction.modrm_rrr.bank = RegisterBank::W; + instruction.mem_size = 4; + } else { + instruction.mem_size = 8; + } + + instruction.operands[0] = OperandSpec::RegRRR; + instruction.operands[1] = read_M(&mut bytes_iter, instruction, modrm, length)?; + instruction.operand_count = 2; + } else { + let prefixes = &instruction.prefixes; + if prefixes.lock() || prefixes.operand_size() || prefixes.rep_any() { + return Err(DecodeError::InvalidPrefixes); + } else { + evex::read_evex(&mut bytes_iter, instruction, *length, Some(modrm))?; + // there's an unavoidable `instruction.length = *length;` after + // `unlikely_operands`. the current length is correct, so store it back to + // length to make the reassignment store a correct length. + *length = instruction.length; + } + } + } _ => { // TODO: this should be unreachable - safe to panic now? // can't simply delete this arm because the non-unlikely operands are handled outside diff --git a/src/protected_mode/vex.rs b/src/protected_mode/vex.rs index ce40e6e..5c66654 100644 --- a/src/protected_mode/vex.rs +++ b/src/protected_mode/vex.rs @@ -1685,7 +1685,7 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: & } else { VEXOperandCode::G_V_E_xmm }), - 0x04 => (Opcode::VPHADDUBSW, if L { + 0x04 => (Opcode::VPMADDUBSW, if L { VEXOperandCode::G_V_E_ymm } else { VEXOperandCode::G_V_E_xmm |