aboutsummaryrefslogtreecommitdiff
path: root/src/long_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/long_mode')
-rw-r--r--src/long_mode/isa_settings.rs977
-rw-r--r--src/long_mode/mod.rs1444
-rw-r--r--src/long_mode/uarch.rs100
3 files changed, 1115 insertions, 1406 deletions
diff --git a/src/long_mode/isa_settings.rs b/src/long_mode/isa_settings.rs
new file mode 100644
index 0000000..de3d6e7
--- /dev/null
+++ b/src/long_mode/isa_settings.rs
@@ -0,0 +1,977 @@
+use super::{BMI1, BMI2, DecodeError, DecodeEverything, InstDecoder, Instruction, Opcode};
+
+macro_rules! gen_isa_settings {
+ (
+ $(
+ $(#[$doc:meta])*
+ $feature:ident,
+ $(#[$set_doc:item])*
+ $set_feature:ident = $idx:expr;
+ )+
+
+ {
+ $(
+ $(#[$composite_doc:meta])*
+ $composite_feature:ident = {
+ $first_inner_feature:ident
+ $(,$($inner_feature:ident$(,)?)+)?
+ }$(,)?
+ )*
+ }
+
+ {
+ $(
+ $(#[$composite_set_doc:meta])*
+ $composite_set_feature:ident = {
+ $set_first_inner_feature:ident
+ $(,$($set_inner_feature:ident$(,)?)+)?
+ }$(,)?
+ )*
+ }
+ ) => {
+ /// specific decode settings controlling how an x86 byte sequence is interpreted.
+ ///
+ /// this currently exists to specify which extensions are to be accepted or rejected. the two
+ /// implementations provided by `yaxpeax-x86` are:
+ /// * [`InstDecoder`], providing configurable enablement or disablement per-extension
+ /// * [`DecodeEverything`], which allows all extensions supported by `yaxpeax-x86`
+ ///
+ /// notably, `InstDecoder::default()` and `DecodeEverything` are functionally equivalent in that
+ /// they accept all extensions supported by the decoder.
+ ///
+ /// TODO: many additional extension support flags.
+ /// * extended MMX (see `sha256:daee4e23dac983f1744126352d40cc71d47b4a9283a2a1e473837728ca9c51ac`)
+ /// * lots of others... tile extensions...
+ pub trait IsaSettings {
+ $(
+ $(#[$doc])*
+ fn $feature(&self) -> bool;
+ )+
+
+ $(
+ $(#[$composite_doc])*
+ fn $composite_feature(&self) -> bool {
+ self.$first_inner_feature()
+ $($(&& self.$inner_feature())+)?
+ }
+ )*
+
+ fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), DecodeError> {
+ revise_instruction(self, inst)
+ }
+ }
+
+ impl IsaSettings for DecodeEverything {
+ $(fn $feature(&self) -> bool { true })+
+
+ fn revise_instruction(&self, _inst: &mut Instruction) -> Result<(), DecodeError> {
+ Ok(())
+ }
+ }
+
+ impl IsaSettings for InstDecoder {
+ $(
+ fn $feature(&self) -> bool {
+ let i = $idx as usize;
+ self.flags[i / 64] & (1 << (i % 64)) != 0
+ }
+ )+
+ }
+
+ impl InstDecoder {
+ $(
+ $(#[$set_doc])*
+ pub fn $set_feature(mut self) -> Self {
+ let i = $idx as usize;
+ self.flags[i / 64] |= 1 << (i % 64);
+ self
+ }
+ )+
+
+ $(
+ $(#[$composite_set_doc])*
+ pub fn $composite_set_feature(&self) -> Self {
+ self.$set_first_inner_feature()
+ $($(.$set_inner_feature())+)?
+ }
+ )*
+
+ $(
+ $(#[$doc])*
+ pub fn $feature(&self) -> bool {
+ <Self as IsaSettings>::$feature(self)
+ }
+ )+
+
+ $(
+ $(#[$composite_doc])*
+ pub fn $composite_feature(&self) -> bool {
+ <Self as IsaSettings>::$composite_feature(self)
+ }
+ )*
+ }
+ }
+}
+gen_isa_settings!(
+ _3dnow, with_3dnow = 1;
+ _3dnowprefetch, with_3dnowprefetch = 2;
+ abm, with_abm = 3;
+ adx, with_adx = 4;
+ aesni, with_aesni = 5;
+ amd_quirks, with_amd_quirks = 6;
+ avx, with_avx = 7;
+ avx2, with_avx2 = 8;
+ avx512_4fmaps, with_avx512_4fmaps = 10;
+ avx512_4vnniw, with_avx512_4vnniw = 11;
+ avx512_bitalg, with_avx512_bitalg = 12;
+ avx512_bw, with_avx512_bw = 13;
+ avx512_cd, with_avx512_cd = 14;
+ avx512_dq, with_avx512_dq = 15;
+ avx512_er, with_avx512_er = 16;
+ avx512_f, with_avx512_f = 17;
+ avx512_fma, with_avx512_fma = 18;
+ avx512_pf, with_avx512_pf = 19;
+ avx512_vbmi, with_avx512_vbmi = 20;
+ avx512_vbmi2, with_avx512_vbmi2 = 21;
+ avx512_vl, with_avx512_vl = 22;
+ avx512_vpopcntdq, with_avx512_vpopcntdq = 23;
+ avx_vnni, with_avx_vnni = 24;
+ bmi1, with_bmi1 = 25;
+ #[doc="`bmi2` indicates support for the `BZHI`, `MULX`, `PDEP`, `PEXT`, `RORX`, `SARX`, `SHRX`, "]
+ #[doc="and `SHLX` instructions. `bmi2` is implemented in all x86_64 chips that implement `bmi`, "]
+ #[doc="except the amd `piledriver` and `steamroller` microarchitectures."]
+ bmi2, with_bmi2 = 26;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_EBX_x0`: \"CLFLUSHOPT instruction support.\""]
+ clflushopt, with_clflushopt = 27;
+ clwb, with_clwb = 28;
+ cmov, with_cmov = 29;
+ cmpxchg16b, with_cmpxchg16b = 30;
+ cx8, with_cx8 = 31;
+ f16c, with_f16c = 32;
+ fma3, with_fma3 = 33;
+ fma4, with_fma4 = 34;
+ gfni, with_gfni = 35;
+ intel_quirks, with_intel_quirks = 36;
+ invpcid, with_invpcid = 37;
+ #[doc="`lahfsahf` is only unset for early revisions of 64-bit amd and intel chips. unfortunately"]
+ #[doc="the clearest documentation on when these instructions were reintroduced into 64-bit"]
+ #[doc="architectures seems to be"]
+ #[doc="[wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations):"]
+ #[doc="```text"]
+ #[doc="Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD"]
+ #[doc="introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and"]
+ #[doc="Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the"]
+ #[doc="instructions with the Pentium 4 G1 stepping in December 2005. The 64-bit version of Windows"]
+ #[doc="8.1 requires this feature.[47]"]
+ #[doc="```"]
+ #[doc=""]
+ #[doc="this puts reintroduction of these instructions somewhere in the middle of prescott and k8"]
+ #[doc="lifecycles, for intel and amd respectively. because there is no specific uarch where these"]
+ #[doc="features become enabled, prescott and k8 default to not supporting these instructions,"]
+ #[doc="where later uarches support these instructions."]
+ lahfsahf, with_lahfsahf = 38;
+ lzcnt, with_lzcnt = 39;
+ monitor, with_monitor = 40;
+ movbe, with_movbe = 41;
+ mpx, with_mpx = 42;
+ pclmulqdq, with_pclmulqdq = 43;
+ pcommit, with_pcommit = 44;
+ popcnt, with_popcnt = 45;
+ prefetchw, with_prefetchw = 46;
+ prefetchwt1, with_prefetchwt1 = 47;
+ rdrand, with_rdrand = 48;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_EBX_x0`: \"RDSEED instruction support.\""]
+ rdseed, with_rdseed = 49;
+ rdtscp, with_rdtscp = 50;
+ sgx, with_sgx = 51;
+ sha, with_sha = 52;
+ skinit, with_skinit = 53;
+ sse3, with_sse3 = 54;
+ sse4_1, with_sse4_1 = 55;
+ sse4_2, with_sse4_2 = 56;
+ sse4a, with_sse4a = 57;
+ ssse3, with_ssse3 = 58;
+ svm, with_svm = 59;
+ syscall, with_syscall = 60;
+ tbm, with_tbm = 61;
+ tsx, with_tsx = 62;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_ECX_x0`: \"VAES 256-bit instruction support.\""]
+ vaes, with_vaes = 63;
+ vmx, with_vmx = 64;
+ xop, with_xop = 65;
+ xsave, with_xsave = 66;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_000D_EAX_x1`: \"XSAVEC and compact XRSTOR supported.\""]
+ xsavec, with_xsavec = 67;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_000D_EAX_x1`: \"XSAVES, XRSTOR, and XSS are supported.\""]
+ xsaves, with_xsaves = 68;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_000D_EAX_x1`: \"XSAVEOPT is available.\""]
+ xsaveopt, with_xsaveopt = 69;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_EAX_x0`: \"FS and GS base read/write instruction support.\""]
+ fsgsbase, with_fsgsbase = 70;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0001_ECX`: \"Support for MWAITX and MONITORX instructions.\""]
+ monitorx, with_monitorx = 71;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0008_EBX`: \"WBNOINVD instruction supported.\""]
+ wbnoinvd, with_wbnoinvd = 72;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0008_EBX`: \"CLZERO instruction supported.\""]
+ clzero, with_clzero = 72;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_ECX_x0`: \"RDPID instruction and TSC_AUX MSR support.\""]
+ rdpid, with_rdpid = 73;
+ #[doc="from AMD APM Vol 3 `CPUID Fn0000_0007_ECX_x0`: \"VPCLMULQDQ 256-bit instruction support.\""]
+ vpclmulqdq, with_vpclmulqdq = 74;
+ #[doc="supported in Zen 5, but not mentioned in the AMD APM as of revision 3.36."]
+ movdir64b, with_movdir64b = 75;
+ #[doc="supported in Zen 5, but not mentioned in the AMD APM as of revision 3.36."]
+ enqcmd, with_enqcmd = 76;
+
+ {
+ sse4 = {
+ sse4_1,
+ sse4_2,
+ }
+
+ #[doc = "returns `true` if this `InstDecoder` has **all** `avx512` features enabled."]
+ avx512 = {
+ avx512_4fmaps,
+ avx512_4vnniw,
+ avx512_bitalg,
+ avx512_bw,
+ avx512_cd,
+ avx512_dq,
+ avx512_er,
+ avx512_f,
+ avx512_fma,
+ avx512_pf,
+ avx512_vbmi,
+ avx512_vbmi2,
+ avx512_vl,
+ avx512_vpopcntdq,
+ },
+ }
+
+ {
+ with_sse4 = {
+ with_sse4_1,
+ with_sse4_2,
+ }
+
+ with_avx512 = {
+ with_avx512_4fmaps,
+ with_avx512_4vnniw,
+ with_avx512_bitalg,
+ with_avx512_bw,
+ with_avx512_cd,
+ with_avx512_dq,
+ with_avx512_er,
+ with_avx512_f,
+ with_avx512_fma,
+ with_avx512_pf,
+ with_avx512_vbmi,
+ with_avx512_vbmi2,
+ with_avx512_vl,
+ with_avx512_vpopcntdq,
+ }
+ }
+);
+
+/// optionally reject or reinterpret instruction according to settings for this decode
+/// operation.
+fn revise_instruction<D: IsaSettings + ?Sized>(settings: &D, inst: &mut Instruction) -> Result<(), DecodeError> {
+ if inst.prefixes.evex().is_some() {
+ if !settings.avx512() {
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ return Ok(());
+ }
+ }
+ match inst.opcode {
+ // original 3dnow instructions. see also
+ // `3DNow-Technology-Manual.pdf`
+ // * sha256: daee4e23dac983f1744126352d40cc71d47b4a9283a2a1e473837728ca9c51ac
+ // * ref: https://www.amd.com/content/dam/amd/en/documents/archived-tech-docs/programmer-references/21928.pdf
+ // * order# 21928
+ Opcode::FEMMS |
+ Opcode::PAVGUSB |
+ Opcode::PFADD |
+ Opcode::PFSUB |
+ Opcode::PFSUBR |
+ Opcode::PFACC |
+ Opcode::PFCMPGE |
+ Opcode::PFCMPGT |
+ Opcode::PFCMPEQ |
+ Opcode::PFMAX |
+ Opcode::PFMIN |
+ Opcode::PI2FD |
+ Opcode::PF2ID |
+ Opcode::PFRCP |
+ Opcode::PFRSQRT |
+ Opcode::PFMUL |
+ Opcode::PFRCPIT1 |
+ Opcode::PFRCPIT2 |
+ Opcode::PFRSQIT1 |
+ Opcode::PMULHRW => {
+ if !settings._3dnow() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ // later extension to 3dnow. see also
+ // `AMD-Extensions-to-the-3DNow-and-MMX-Instruction-Sets.pdf`
+ // * sha256: ad847bd6877a682296fc584b4bbee354bf84c57bb97ba57e9c9adfc63cc5f465
+ // * ref: https://refspecs.linuxfoundation.org/AMD-extensions.pdf
+ // * order# 22466
+ Opcode::PF2IW |
+ Opcode::PFNACC |
+ Opcode::PFPNACC |
+ Opcode::PI2FW |
+ Opcode::PSWAPD => {
+ if !settings._3dnow() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::TZCNT => {
+ if !settings.bmi1() {
+ // tzcnt is only supported if bmi1 is enabled. without bmi1, this decodes as
+ // bsf.
+ inst.opcode = Opcode::BSF;
+ }
+ }
+ Opcode::LDDQU |
+ Opcode::ADDSUBPS |
+ Opcode::ADDSUBPD |
+ Opcode::HADDPS |
+ Opcode::HSUBPS |
+ Opcode::HADDPD |
+ Opcode::HSUBPD |
+ Opcode::MOVSHDUP |
+ Opcode::MOVSLDUP |
+ Opcode::MOVDDUP |
+ Opcode::MONITOR |
+ Opcode::MWAIT => {
+ // via Intel section 5.7, SSE3 Instructions
+ if !settings.sse3() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PHADDW |
+ Opcode::PHADDSW |
+ Opcode::PHADDD |
+ Opcode::PHSUBW |
+ Opcode::PHSUBSW |
+ Opcode::PHSUBD |
+ Opcode::PABSB |
+ Opcode::PABSW |
+ Opcode::PABSD |
+ Opcode::PMADDUBSW |
+ Opcode::PMULHRSW |
+ Opcode::PSHUFB |
+ Opcode::PSIGNB |
+ Opcode::PSIGNW |
+ Opcode::PSIGND |
+ Opcode::PALIGNR => {
+ // via Intel section 5.8, SSSE3 Instructions
+ if !settings.ssse3() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PMULLD |
+ Opcode::PMULDQ |
+ Opcode::MOVNTDQA |
+ Opcode::BLENDPD |
+ Opcode::BLENDPS |
+ Opcode::BLENDVPD |
+ Opcode::BLENDVPS |
+ Opcode::PBLENDVB |
+ Opcode::BLENDW |
+ Opcode::PMINUW |
+ Opcode::PMINUD |
+ Opcode::PMINSB |
+ Opcode::PMINSD |
+ Opcode::PMAXUW |
+ Opcode::PMAXUD |
+ Opcode::PMAXSB |
+ Opcode::PMAXSD |
+ Opcode::ROUNDPS |
+ Opcode::ROUNDPD |
+ Opcode::ROUNDSS |
+ Opcode::ROUNDSD |
+ Opcode::PBLENDW |
+ Opcode::EXTRACTPS |
+ Opcode::INSERTPS |
+ Opcode::PINSRB |
+ Opcode::PINSRD |
+ Opcode::PINSRQ |
+ Opcode::PMOVSXBW |
+ Opcode::PMOVZXBW |
+ Opcode::PMOVSXBD |
+ Opcode::PMOVZXBD |
+ Opcode::PMOVSXWD |
+ Opcode::PMOVZXWD |
+ Opcode::PMOVSXBQ |
+ Opcode::PMOVZXBQ |
+ Opcode::PMOVSXWQ |
+ Opcode::PMOVZXWQ |
+ Opcode::PMOVSXDQ |
+ Opcode::PMOVZXDQ |
+ Opcode::DPPS |
+ Opcode::DPPD |
+ Opcode::MPSADBW |
+ Opcode::PHMINPOSUW |
+ Opcode::PTEST |
+ Opcode::PCMPEQQ |
+ Opcode::PEXTRB |
+ Opcode::PEXTRW |
+ Opcode::PEXTRD |
+ Opcode::PEXTRQ |
+ Opcode::PACKUSDW => {
+ // via Intel section 5.10, SSE4.1 Instructions
+ if !settings.sse4_1() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::EXTRQ |
+ Opcode::INSERTQ |
+ Opcode::MOVNTSS |
+ Opcode::MOVNTSD => {
+ if !settings.sse4a() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::CRC32 |
+ Opcode::PCMPESTRI |
+ Opcode::PCMPESTRM |
+ Opcode::PCMPISTRI |
+ Opcode::PCMPISTRM |
+ Opcode::PCMPGTQ => {
+ // via Intel section 5.11, SSE4.2 Instructions
+ if !settings.sse4_2() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::AESDEC |
+ Opcode::AESDECLAST |
+ Opcode::AESENC |
+ Opcode::AESENCLAST |
+ Opcode::AESIMC |
+ Opcode::AESKEYGENASSIST => {
+ // via Intel section 5.12. AESNI AND PCLMULQDQ
+ if !settings.aesni() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::PCLMULQDQ => {
+ // via Intel section 5.12. AESNI AND PCLMULQDQ
+ if !settings.pclmulqdq() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::XABORT |
+ Opcode::XBEGIN |
+ Opcode::XEND |
+ Opcode::XTEST => {
+ if !settings.tsx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::SHA1MSG1 |
+ Opcode::SHA1MSG2 |
+ Opcode::SHA1NEXTE |
+ Opcode::SHA1RNDS4 |
+ Opcode::SHA256MSG1 |
+ Opcode::SHA256MSG2 |
+ Opcode::SHA256RNDS2 => {
+ if !settings.sha() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::ENCLV |
+ Opcode::ENCLS |
+ Opcode::ENCLU => {
+ if !settings.sgx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ // AVX...
+ Opcode::VMOVDDUP |
+ Opcode::VPSHUFLW |
+ Opcode::VPSHUFHW |
+ Opcode::VHADDPS |
+ Opcode::VHSUBPS |
+ Opcode::VADDSUBPS |
+ Opcode::VCVTPD2DQ |
+ Opcode::VLDDQU |
+ Opcode::VCOMISD |
+ Opcode::VCOMISS |
+ Opcode::VUCOMISD |
+ Opcode::VUCOMISS |
+ Opcode::VADDPD |
+ Opcode::VADDPS |
+ Opcode::VADDSD |
+ Opcode::VADDSS |
+ Opcode::VADDSUBPD |
+ Opcode::VBLENDPD |
+ Opcode::VBLENDPS |
+ Opcode::VBLENDVPD |
+ Opcode::VBLENDVPS |
+ Opcode::VBROADCASTF128 |
+ Opcode::VBROADCASTI128 |
+ Opcode::VBROADCASTSD |
+ Opcode::VBROADCASTSS |
+ Opcode::VCMPSD |
+ Opcode::VCMPSS |
+ Opcode::VCMPPD |
+ Opcode::VCMPPS |
+ Opcode::VCVTDQ2PD |
+ Opcode::VCVTDQ2PS |
+ Opcode::VCVTPD2PS |
+ Opcode::VCVTPS2DQ |
+ Opcode::VCVTPS2PD |
+ Opcode::VCVTSS2SD |
+ Opcode::VCVTSI2SS |
+ Opcode::VCVTSI2SD |
+ Opcode::VCVTSD2SI |
+ Opcode::VCVTSD2SS |
+ Opcode::VCVTSS2SI |
+ Opcode::VCVTTPD2DQ |
+ Opcode::VCVTTPS2DQ |
+ Opcode::VCVTTSS2SI |
+ Opcode::VCVTTSD2SI |
+ Opcode::VDIVPD |
+ Opcode::VDIVPS |
+ Opcode::VDIVSD |
+ Opcode::VDIVSS |
+ Opcode::VDPPD |
+ Opcode::VDPPS |
+ Opcode::VEXTRACTF128 |
+ Opcode::VEXTRACTI128 |
+ Opcode::VEXTRACTPS |
+ Opcode::VFMADD132PD |
+ Opcode::VFMADD132PS |
+ Opcode::VFMADD132SD |
+ Opcode::VFMADD132SS |
+ Opcode::VFMADD213PD |
+ Opcode::VFMADD213PS |
+ Opcode::VFMADD213SD |
+ Opcode::VFMADD213SS |
+ Opcode::VFMADD231PD |
+ Opcode::VFMADD231PS |
+ Opcode::VFMADD231SD |
+ Opcode::VFMADD231SS |
+ Opcode::VFMADDSUB132PD |
+ Opcode::VFMADDSUB132PS |
+ Opcode::VFMADDSUB213PD |
+ Opcode::VFMADDSUB213PS |
+ Opcode::VFMADDSUB231PD |
+ Opcode::VFMADDSUB231PS |
+ Opcode::VFMSUB132PD |
+ Opcode::VFMSUB132PS |
+ Opcode::VFMSUB132SD |
+ Opcode::VFMSUB132SS |
+ Opcode::VFMSUB213PD |
+ Opcode::VFMSUB213PS |
+ Opcode::VFMSUB213SD |
+ Opcode::VFMSUB213SS |
+ Opcode::VFMSUB231PD |
+ Opcode::VFMSUB231PS |
+ Opcode::VFMSUB231SD |
+ Opcode::VFMSUB231SS |
+ Opcode::VFMSUBADD132PD |
+ Opcode::VFMSUBADD132PS |
+ Opcode::VFMSUBADD213PD |
+ Opcode::VFMSUBADD213PS |
+ Opcode::VFMSUBADD231PD |
+ Opcode::VFMSUBADD231PS |
+ Opcode::VFNMADD132PD |
+ Opcode::VFNMADD132PS |
+ Opcode::VFNMADD132SD |
+ Opcode::VFNMADD132SS |
+ Opcode::VFNMADD213PD |
+ Opcode::VFNMADD213PS |
+ Opcode::VFNMADD213SD |
+ Opcode::VFNMADD213SS |
+ Opcode::VFNMADD231PD |
+ Opcode::VFNMADD231PS |
+ Opcode::VFNMADD231SD |
+ Opcode::VFNMADD231SS |
+ Opcode::VFNMSUB132PD |
+ Opcode::VFNMSUB132PS |
+ Opcode::VFNMSUB132SD |
+ Opcode::VFNMSUB132SS |
+ Opcode::VFNMSUB213PD |
+ Opcode::VFNMSUB213PS |
+ Opcode::VFNMSUB213SD |
+ Opcode::VFNMSUB213SS |
+ Opcode::VFNMSUB231PD |
+ Opcode::VFNMSUB231PS |
+ Opcode::VFNMSUB231SD |
+ Opcode::VFNMSUB231SS |
+ Opcode::VGATHERDPD |
+ Opcode::VGATHERDPS |
+ Opcode::VGATHERQPD |
+ Opcode::VGATHERQPS |
+ Opcode::VHADDPD |
+ Opcode::VHSUBPD |
+ Opcode::VINSERTF128 |
+ Opcode::VINSERTI128 |
+ Opcode::VINSERTPS |
+ Opcode::VMASKMOVDQU |
+ Opcode::VMASKMOVPD |
+ Opcode::VMASKMOVPS |
+ Opcode::VMAXPD |
+ Opcode::VMAXPS |
+ Opcode::VMAXSD |
+ Opcode::VMAXSS |
+ Opcode::VMINPD |
+ Opcode::VMINPS |
+ Opcode::VMINSD |
+ Opcode::VMINSS |
+ Opcode::VMOVAPD |
+ Opcode::VMOVAPS |
+ Opcode::VMOVD |
+ Opcode::VMOVDQA |
+ Opcode::VMOVDQU |
+ Opcode::VMOVHLPS |
+ Opcode::VMOVHPD |
+ Opcode::VMOVHPS |
+ Opcode::VMOVLHPS |
+ Opcode::VMOVLPD |
+ Opcode::VMOVLPS |
+ Opcode::VMOVMSKPD |
+ Opcode::VMOVMSKPS |
+ Opcode::VMOVNTDQ |
+ Opcode::VMOVNTDQA |
+ Opcode::VMOVNTPD |
+ Opcode::VMOVNTPS |
+ Opcode::VMOVQ |
+ Opcode::VMOVSS |
+ Opcode::VMOVSD |
+ Opcode::VMOVSHDUP |
+ Opcode::VMOVSLDUP |
+ Opcode::VMOVUPD |
+ Opcode::VMOVUPS |
+ Opcode::VMPSADBW |
+ Opcode::VMULPD |
+ Opcode::VMULPS |
+ Opcode::VMULSD |
+ Opcode::VMULSS |
+ Opcode::VPABSB |
+ Opcode::VPABSD |
+ Opcode::VPABSW |
+ Opcode::VPACKSSDW |
+ Opcode::VPACKUSDW |
+ Opcode::VPACKSSWB |
+ Opcode::VPACKUSWB |
+ Opcode::VPADDB |
+ Opcode::VPADDD |
+ Opcode::VPADDQ |
+ Opcode::VPADDSB |
+ Opcode::VPADDSW |
+ Opcode::VPADDUSB |
+ Opcode::VPADDUSW |
+ Opcode::VPADDW |
+ Opcode::VPALIGNR |
+ Opcode::VPAND |
+ Opcode::VANDPD |
+ Opcode::VANDPS |
+ Opcode::VANDNPD |
+ Opcode::VANDNPS |
+ Opcode::VORPD |
+ Opcode::VORPS |
+ Opcode::VPANDN |
+ Opcode::VPAVGB |
+ Opcode::VPAVGW |
+ Opcode::VPBLENDD |
+ Opcode::VPBLENDVB |
+ Opcode::VPBLENDW |
+ Opcode::VPBROADCASTB |
+ Opcode::VPBROADCASTD |
+ Opcode::VPBROADCASTQ |
+ Opcode::VPBROADCASTW |
+ Opcode::VPCLMULQDQ |
+ Opcode::VPCMPEQB |
+ Opcode::VPCMPEQD |
+ Opcode::VPCMPEQQ |
+ Opcode::VPCMPEQW |
+ Opcode::VPCMPGTB |
+ Opcode::VPCMPGTD |
+ Opcode::VPCMPGTQ |
+ Opcode::VPCMPGTW |
+ Opcode::VPCMPESTRI |
+ Opcode::VPCMPESTRM |
+ Opcode::VPCMPISTRI |
+ Opcode::VPCMPISTRM |
+ Opcode::VPERM2F128 |
+ Opcode::VPERM2I128 |
+ Opcode::VPERMD |
+ Opcode::VPERMILPD |
+ Opcode::VPERMILPS |
+ Opcode::VPERMPD |
+ Opcode::VPERMPS |
+ Opcode::VPERMQ |
+ Opcode::VPEXTRB |
+ Opcode::VPEXTRD |
+ Opcode::VPEXTRQ |
+ Opcode::VPEXTRW |
+ Opcode::VPGATHERDD |
+ Opcode::VPGATHERDQ |
+ Opcode::VPGATHERQD |
+ Opcode::VPGATHERQQ |
+ Opcode::VPHADDD |
+ Opcode::VPHADDSW |
+ Opcode::VPHADDW |
+ Opcode::VPMADDUBSW |
+ Opcode::VPHMINPOSUW |
+ Opcode::VPHSUBD |
+ Opcode::VPHSUBSW |
+ Opcode::VPHSUBW |
+ Opcode::VPINSRB |
+ Opcode::VPINSRD |
+ Opcode::VPINSRQ |
+ Opcode::VPINSRW |
+ Opcode::VPMADDWD |
+ Opcode::VPMASKMOVD |
+ Opcode::VPMASKMOVQ |
+ Opcode::VPMAXSB |
+ Opcode::VPMAXSD |
+ Opcode::VPMAXSW |
+ Opcode::VPMAXUB |
+ Opcode::VPMAXUW |
+ Opcode::VPMAXUD |
+ Opcode::VPMINSB |
+ Opcode::VPMINSW |
+ Opcode::VPMINSD |
+ Opcode::VPMINUB |
+ Opcode::VPMINUW |
+ Opcode::VPMINUD |
+ Opcode::VPMOVMSKB |
+ Opcode::VPMOVSXBD |
+ Opcode::VPMOVSXBQ |
+ Opcode::VPMOVSXBW |
+ Opcode::VPMOVSXDQ |
+ Opcode::VPMOVSXWD |
+ Opcode::VPMOVSXWQ |
+ Opcode::VPMOVZXBD |
+ Opcode::VPMOVZXBQ |
+ Opcode::VPMOVZXBW |
+ Opcode::VPMOVZXDQ |
+ Opcode::VPMOVZXWD |
+ Opcode::VPMOVZXWQ |
+ Opcode::VPMULDQ |
+ Opcode::VPMULHRSW |
+ Opcode::VPMULHUW |
+ Opcode::VPMULHW |
+ Opcode::VPMULLQ |
+ Opcode::VPMULLD |
+ Opcode::VPMULLW |
+ Opcode::VPMULUDQ |
+ Opcode::VPOR |
+ Opcode::VPSADBW |
+ Opcode::VPSHUFB |
+ Opcode::VPSHUFD |
+ Opcode::VPSIGNB |
+ Opcode::VPSIGND |
+ Opcode::VPSIGNW |
+ Opcode::VPSLLD |
+ Opcode::VPSLLDQ |
+ Opcode::VPSLLQ |
+ Opcode::VPSLLVD |
+ Opcode::VPSLLVQ |
+ Opcode::VPSLLW |
+ Opcode::VPSRAD |
+ Opcode::VPSRAVD |
+ Opcode::VPSRAW |
+ Opcode::VPSRLD |
+ Opcode::VPSRLDQ |
+ Opcode::VPSRLQ |
+ Opcode::VPSRLVD |
+ Opcode::VPSRLVQ |
+ Opcode::VPSRLW |
+ Opcode::VPSUBB |
+ Opcode::VPSUBD |
+ Opcode::VPSUBQ |
+ Opcode::VPSUBSB |
+ Opcode::VPSUBSW |
+ Opcode::VPSUBUSB |
+ Opcode::VPSUBUSW |
+ Opcode::VPSUBW |
+ Opcode::VPTEST |
+ Opcode::VPUNPCKHBW |
+ Opcode::VPUNPCKHDQ |
+ Opcode::VPUNPCKHQDQ |
+ Opcode::VPUNPCKHWD |
+ Opcode::VPUNPCKLBW |
+ Opcode::VPUNPCKLDQ |
+ Opcode::VPUNPCKLQDQ |
+ Opcode::VPUNPCKLWD |
+ Opcode::VPXOR |
+ Opcode::VRCPPS |
+ Opcode::VROUNDPD |
+ Opcode::VROUNDPS |
+ Opcode::VROUNDSD |
+ Opcode::VROUNDSS |
+ Opcode::VRSQRTPS |
+ Opcode::VRSQRTSS |
+ Opcode::VRCPSS |
+ Opcode::VSHUFPD |
+ Opcode::VSHUFPS |
+ Opcode::VSQRTPD |
+ Opcode::VSQRTPS |
+ Opcode::VSQRTSS |
+ Opcode::VSQRTSD |
+ Opcode::VSUBPD |
+ Opcode::VSUBPS |
+ Opcode::VSUBSD |
+ Opcode::VSUBSS |
+ Opcode::VTESTPD |
+ Opcode::VTESTPS |
+ Opcode::VUNPCKHPD |
+ Opcode::VUNPCKHPS |
+ Opcode::VUNPCKLPD |
+ Opcode::VUNPCKLPS |
+ Opcode::VXORPD |
+ Opcode::VXORPS |
+ Opcode::VZEROUPPER |
+ Opcode::VZEROALL |
+ Opcode::VLDMXCSR |
+ Opcode::VSTMXCSR => {
+ // TODO: check a table for these
+ if !settings.avx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VAESDEC |
+ Opcode::VAESDECLAST |
+ Opcode::VAESENC |
+ Opcode::VAESENCLAST |
+ Opcode::VAESIMC |
+ Opcode::VAESKEYGENASSIST => {
+ // TODO: check a table for these
+ if !settings.avx() || !settings.aesni() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::MOVBE => {
+ if !settings.movbe() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::POPCNT => {
+ /*
+ * from the intel SDM:
+ * ```
+ * Before an application attempts to use the POPCNT instruction, it must check that
+ * the processor supports SSE4.2 (if CPUID.01H:ECX.SSE4_2[bit 20] = 1) and POPCNT
+ * (if CPUID.01H:ECX.POPCNT[bit 23] = 1).
+ * ```
+ */
+ if settings.intel_quirks() && (settings.sse4_2() || settings.popcnt()) {
+ return Ok(());
+ } else if !settings.popcnt() {
+ /*
+ * elsewhere from the amd APM:
+ * `Instruction Subsets and CPUID Feature Flags` on page 507 indicates that
+ * popcnt is present when the popcnt bit is reported by cpuid. this seems to be
+ * the less quirky default, so `intel_quirks` is considered the outlier, and
+ * before this default.
+ * */
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::LZCNT => {
+ /*
+ * amd APM, `LZCNT` page 212:
+ * LZCNT is an Advanced Bit Manipulation (ABM) instruction. Support for the LZCNT
+ * instruction is indicated by CPUID Fn8000_0001_ECX[ABM] = 1.
+ *
+ * meanwhile the intel SDM simply states:
+ * ```
+ * CPUID.EAX=80000001H:ECX.LZCNT[bit 5]: if 1 indicates the processor supports the
+ * LZCNT instruction.
+ * ```
+ *
+ * so that's considered the less-quirky (default) case here.
+ * */
+ if settings.amd_quirks() && !settings.abm() {
+ return Err(DecodeError::InvalidOpcode);
+ } else if !settings.lzcnt() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::ADCX |
+ Opcode::ADOX => {
+ if !settings.adx() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VMRUN |
+ Opcode::VMLOAD |
+ Opcode::VMSAVE |
+ Opcode::CLGI |
+ Opcode::VMMCALL |
+ Opcode::INVLPGA => {
+ if !settings.svm() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::STGI |
+ Opcode::SKINIT => {
+ if !settings.svm() || !settings.skinit() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::LAHF |
+ Opcode::SAHF => {
+ if !settings.lahfsahf() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::VCVTPS2PH |
+ Opcode::VCVTPH2PS => {
+ /*
+ * from intel SDM:
+ * ```
+ * 14.4.1 Detection of F16C Instructions Application using float 16 instruction
+ * must follow a detection sequence similar to AVX to ensure: • The OS has
+ * enabled YMM state management support, • The processor support AVX as
+ * indicated by the CPUID feature flag, i.e. CPUID.01H:ECX.AVX[bit 28] = 1. •
+ * The processor support 16-bit floating-point conversion instructions via a
+ * CPUID feature flag (CPUID.01H:ECX.F16C[bit 29] = 1).
+ * ```
+ *
+ * TODO: only the VEX-coded variant of this instruction should be gated on `f16c`.
+ * the EVEX-coded variant should be gated on `avx512f` or `avx512vl` if not
+ * EVEX.512-coded.
+ */
+ if !settings.avx() || !settings.f16c() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::RDRAND => {
+ if !settings.rdrand() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::RDSEED => {
+ if !settings.rdseed() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ Opcode::MONITORX | Opcode::MWAITX | // these are gated on the `monitorx` and `mwaitx` cpuid bits, but are AMD-only.
+ Opcode::CLZERO | Opcode::RDPRU => { // again, gated on specific cpuid bits, but AMD-only.
+ if !settings.amd_quirks() {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ other => {
+ if !settings.bmi1() {
+ if BMI1.contains(&other) {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ if !settings.bmi2() {
+ if BMI2.contains(&other) {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ }
+ Ok(())
+}
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 0ce6a58..0045236 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -3,6 +3,9 @@ mod evex;
#[cfg(feature = "fmt")]
mod display;
pub mod uarch;
+mod isa_settings;
+
+pub use isa_settings::IsaSettings;
pub use crate::MemoryAccessSize;
@@ -2791,73 +2794,7 @@ impl LengthedInstruction for Instruction {
/// the design requiring that.
#[derive(PartialEq, Copy, Clone, Eq, Hash, PartialOrd, Ord)]
pub struct InstDecoder {
- // extensions tracked here:
- // 0. SSE3
- // 1. SSSE3
- // 2. monitor (intel-only?)
- // 3. vmx (some atom chips still lack it)
- // 4. fma3 (intel haswell/broadwell+, amd piledriver+)
- // 5. cmpxchg16b (some amd are missing this one)
- // 6. sse4.1
- // 7. sse4.2
- // 8. movbe
- // 9. popcnt (independent of BMI)
- // 10. aesni
- // 11. xsave (xsave, xrestor, xsetbv, xgetbv)
- // 12. rdrand (intel ivybridge+, amd ..??)
- // 13. sgx (eadd, eblock, ecreate, edbgrd, edbgwr, einit, eldb, eldu, epa, eremove, etrace,
- // ewb, eenter, eexit, egetkey, ereport, eresume)
- // 14. bmi1 (intel haswell+, amd jaguar+)
- // 15. avx2 (intel haswell+, amd excavator+)
- // 16. bmi2 (intel ?, amd ?)
- // 17. invpcid
- // 18. mpx
- // 19. avx512_f
- // 20. avx512_dq
- // 21. rdseed
- // 22. adx
- // 23. avx512_fma
- // 24. pcommit
- // 25. clflushopt
- // 26. clwb
- // 27. avx512_pf
- // 28. avx512_er
- // 29. avx512_cd
- // 30. sha
- // 31. avx512_bw
- // 32. avx512_vl
- // 33. prefetchwt1
- // 34. avx512_vbmi
- // 35. avx512_vbmi2
- // 36. gfni (galois field instructions)
- // 37. vaes
- // 38. pclmulqdq
- // 39. avx_vnni
- // 40. avx512_bitalg
- // 41. avx512_vpopcntdq
- // 42. avx512_4vnniw
- // 43. avx512_4fmaps
- // 44. cx8 // cmpxchg8 - is this actually optional in x86_64?
- // 45. syscall // syscall/sysret - actually optional in x86_64?
- // 46. rdtscp // actually optional in x86_64?
- // 47. abm (lzcnt, popcnt)
- // 48. sse4a
- // 49. 3dnowprefetch // actually optional?
- // 50. xop
- // 51. skinit
- // 52. tbm
- // 53. intel quirks
- // 54. amd quirks
- // 55. avx (intel ?, amd ?)
- // 56. amd-v/svm
- // 57. lahfsahf
- // 58. cmov
- // 59. f16c
- // 60. fma4
- // 61. prefetchw
- // 62. tsx
- // 63. lzcnt
- flags: u64,
+ flags: [u64; 2],
}
impl InstDecoder {
@@ -2867,7 +2804,7 @@ impl InstDecoder {
/// and any instructions defined by extensions.
pub fn minimal() -> Self {
InstDecoder {
- flags: 0,
+ flags: [0, 0],
}
}
@@ -2879,1311 +2816,32 @@ impl InstDecoder {
let mut reader = yaxpeax_arch::U8Reader::new(data);
self.decode(&mut reader)
}
+}
- pub fn sse3(&self) -> bool {
- self.flags & (1 << 0) != 0
- }
-
- pub fn with_sse3(mut self) -> Self {
- self.flags |= 1 << 0;
- self
- }
-
- pub fn ssse3(&self) -> bool {
- self.flags & (1 << 1) != 0
- }
-
- pub fn with_ssse3(mut self) -> Self {
- self.flags |= 1 << 1;
- self
- }
-
- pub fn monitor(&self) -> bool {
- self.flags & (1 << 2) != 0
- }
-
- pub fn with_monitor(mut self) -> Self {
- self.flags |= 1 << 2;
- self
- }
-
- pub fn vmx(&self) -> bool {
- self.flags & (1 << 3) != 0
- }
-
- pub fn with_vmx(mut self) -> Self {
- self.flags |= 1 << 3;
- self
- }
-
- pub fn fma3(&self) -> bool {
- self.flags & (1 << 4) != 0
- }
-
- pub fn with_fma3(mut self) -> Self {
- self.flags |= 1 << 4;
- self
- }
-
- pub fn cmpxchg16b(&self) -> bool {
- self.flags & (1 << 5) != 0
- }
-
- pub fn with_cmpxchg16b(mut self) -> Self {
- self.flags |= 1 << 5;
- self
- }
-
- pub fn sse4_1(&self) -> bool {
- self.flags & (1 << 6) != 0
- }
-
- pub fn with_sse4_1(mut self) -> Self {
- self.flags |= 1 << 6;
- self
- }
-
- pub fn sse4_2(&self) -> bool {
- self.flags & (1 << 7) != 0
- }
-
- pub fn with_sse4_2(mut self) -> Self {
- self.flags |= 1 << 7;
- self
- }
-
- pub fn with_sse4(self) -> Self {
- self
- .with_sse4_1()
- .with_sse4_2()
- }
-
- pub fn movbe(&self) -> bool {
- self.flags & (1 << 8) != 0
- }
-
- pub fn with_movbe(mut self) -> Self {
- self.flags |= 1 << 8;
- self
- }
-
- pub fn popcnt(&self) -> bool {
- self.flags & (1 << 9) != 0
- }
-
- pub fn with_popcnt(mut self) -> Self {
- self.flags |= 1 << 9;
- self
- }
-
- pub fn aesni(&self) -> bool {
- self.flags & (1 << 10) != 0
- }
-
- pub fn with_aesni(mut self) -> Self {
- self.flags |= 1 << 10;
- self
- }
-
- pub fn xsave(&self) -> bool {
- self.flags & (1 << 11) != 0
- }
-
- pub fn with_xsave(mut self) -> Self {
- self.flags |= 1 << 11;
- self
- }
-
- pub fn rdrand(&self) -> bool {
- self.flags & (1 << 12) != 0
- }
-
- pub fn with_rdrand(mut self) -> Self {
- self.flags |= 1 << 12;
- self
- }
-
- pub fn sgx(&self) -> bool {
- self.flags & (1 << 13) != 0
- }
-
- pub fn with_sgx(mut self) -> Self {
- self.flags |= 1 << 13;
- self
- }
-
- pub fn bmi1(&self) -> bool {
- self.flags & (1 << 14) != 0
- }
-
- pub fn with_bmi1(mut self) -> Self {
- self.flags |= 1 << 14;
- self
- }
-
- pub fn avx2(&self) -> bool {
- self.flags & (1 << 15) != 0
- }
-
- pub fn with_avx2(mut self) -> Self {
- self.flags |= 1 << 15;
- self
- }
-
- /// `bmi2` indicates support for the `BZHI`, `MULX`, `PDEP`, `PEXT`, `RORX`, `SARX`, `SHRX`,
- /// and `SHLX` instructions. `bmi2` is implemented in all x86_64 chips that implement `bmi`,
- /// except the amd `piledriver` and `steamroller` microarchitectures.
- pub fn bmi2(&self) -> bool {
- self.flags & (1 << 16) != 0
- }
-
- pub fn with_bmi2(mut self) -> Self {
- self.flags |= 1 << 16;
- self
- }
-
- pub fn invpcid(&self) -> bool {
- self.flags & (1 << 17) != 0
- }
-
- pub fn with_invpcid(mut self) -> Self {
- self.flags |= 1 << 17;
- self
- }
-
- pub fn mpx(&self) -> bool {
- self.flags & (1 << 18) != 0
- }
-
- pub fn with_mpx(mut self) -> Self {
- self.flags |= 1 << 18;
- self
- }
-
- pub fn avx512_f(&self) -> bool {
- self.flags & (1 << 19) != 0
- }
-
- pub fn with_avx512_f(mut self) -> Self {
- self.flags |= 1 << 19;
- self
- }
-
- pub fn avx512_dq(&self) -> bool {
- self.flags & (1 << 20) != 0
- }
-
- pub fn with_avx512_dq(mut self) -> Self {
- self.flags |= 1 << 20;
- self
- }
-
- pub fn rdseed(&self) -> bool {
- self.flags & (1 << 21) != 0
- }
-
- pub fn with_rdseed(mut self) -> Self {
- self.flags |= 1 << 21;
- self
- }
-
- pub fn adx(&self) -> bool {
- self.flags & (1 << 22) != 0
- }
-
- pub fn with_adx(mut self) -> Self {
- self.flags |= 1 << 22;
- self
- }
-
- pub fn avx512_fma(&self) -> bool {
- self.flags & (1 << 23) != 0
- }
-
- pub fn with_avx512_fma(mut self) -> Self {
- self.flags |= 1 << 23;
- self
- }
-
- pub fn pcommit(&self) -> bool {
- self.flags & (1 << 24) != 0
- }
-
- pub fn with_pcommit(mut self) -> Self {
- self.flags |= 1 << 24;
- self
- }
-
- pub fn clflushopt(&self) -> bool {
- self.flags & (1 << 25) != 0
- }
-
- pub fn with_clflushopt(mut self) -> Self {
- self.flags |= 1 << 25;
- self
- }
-
- pub fn clwb(&self) -> bool {
- self.flags & (1 << 26) != 0
- }
-
- pub fn with_clwb(mut self) -> Self {
- self.flags |= 1 << 26;
- self
- }
-
- pub fn avx512_pf(&self) -> bool {
- self.flags & (1 << 27) != 0
- }
-
- pub fn with_avx512_pf(mut self) -> Self {
- self.flags |= 1 << 27;
- self
- }
-
- pub fn avx512_er(&self) -> bool {
- self.flags & (1 << 28) != 0
- }
-
- pub fn with_avx512_er(mut self) -> Self {
- self.flags |= 1 << 28;
- self
- }
-
- pub fn avx512_cd(&self) -> bool {
- self.flags & (1 << 29) != 0
- }
-
- pub fn with_avx512_cd(mut self) -> Self {
- self.flags |= 1 << 29;
- self
- }
-
- pub fn sha(&self) -> bool {
- self.flags & (1 << 30) != 0
- }
-
- pub fn with_sha(mut self) -> Self {
- self.flags |= 1 << 30;
- self
- }
-
- pub fn avx512_bw(&self) -> bool {
- self.flags & (1 << 31) != 0
- }
-
- pub fn with_avx512_bw(mut self) -> Self {
- self.flags |= 1 << 31;
- self
- }
-
- pub fn avx512_vl(&self) -> bool {
- self.flags & (1 << 32) != 0
- }
-
- pub fn with_avx512_vl(mut self) -> Self {
- self.flags |= 1 << 32;
- self
- }
-
- pub fn prefetchwt1(&self) -> bool {
- self.flags & (1 << 33) != 0
- }
-
- pub fn with_prefetchwt1(mut self) -> Self {
- self.flags |= 1 << 33;
- self
- }
-
- pub fn avx512_vbmi(&self) -> bool {
- self.flags & (1 << 34) != 0
- }
-
- pub fn with_avx512_vbmi(mut self) -> Self {
- self.flags |= 1 << 34;
- self
- }
-
- pub fn avx512_vbmi2(&self) -> bool {
- self.flags & (1 << 35) != 0
- }
-
- pub fn with_avx512_vbmi2(mut self) -> Self {
- self.flags |= 1 << 35;
- self
- }
-
- pub fn gfni(&self) -> bool {
- self.flags & (1 << 36) != 0
- }
-
- pub fn with_gfni(mut self) -> Self {
- self.flags |= 1 << 36;
- self
- }
-
- pub fn vaes(&self) -> bool {
- self.flags & (1 << 37) != 0
- }
-
- pub fn with_vaes(mut self) -> Self {
- self.flags |= 1 << 37;
- self
- }
-
- pub fn pclmulqdq(&self) -> bool {
- self.flags & (1 << 38) != 0
- }
-
- pub fn with_pclmulqdq(mut self) -> Self {
- self.flags |= 1 << 38;
- self
- }
-
- pub fn avx_vnni(&self) -> bool {
- self.flags & (1 << 39) != 0
- }
-
- pub fn with_avx_vnni(mut self) -> Self {
- self.flags |= 1 << 39;
- self
- }
-
- pub fn avx512_bitalg(&self) -> bool {
- self.flags & (1 << 40) != 0
- }
-
- pub fn with_avx512_bitalg(mut self) -> Self {
- self.flags |= 1 << 40;
- self
- }
-
- pub fn avx512_vpopcntdq(&self) -> bool {
- self.flags & (1 << 41) != 0
- }
-
- pub fn with_avx512_vpopcntdq(mut self) -> Self {
- self.flags |= 1 << 41;
- self
- }
-
- pub fn avx512_4vnniw(&self) -> bool {
- self.flags & (1 << 42) != 0
- }
-
- pub fn with_avx512_4vnniw(mut self) -> Self {
- self.flags |= 1 << 42;
- self
- }
-
- pub fn avx512_4fmaps(&self) -> bool {
- self.flags & (1 << 43) != 0
- }
-
- pub fn with_avx512_4fmaps(mut self) -> Self {
- self.flags |= 1 << 43;
- self
- }
-
- /// returns `true` if this `InstDecoder` has **all** `avx512` features enabled.
- pub fn avx512(&self) -> bool {
- let avx512_mask =
- (1 << 19) |
- (1 << 20) |
- (1 << 23) |
- (1 << 27) |
- (1 << 28) |
- (1 << 29) |
- (1 << 31) |
- (1 << 32) |
- (1 << 34) |
- (1 << 35) |
- (1 << 40) |
- (1 << 41) |
- (1 << 42) |
- (1 << 43);
-
- (self.flags & avx512_mask) == avx512_mask
- }
-
- /// enable all `avx512` features on this `InstDecoder`. no real CPU, at time of writing,
- /// actually has such a feature combination, but this is a useful overestimate for `avx512`
- /// generally.
- pub fn with_avx512(mut self) -> Self {
- let avx512_mask =
- (1 << 19) |
- (1 << 20) |
- (1 << 23) |
- (1 << 27) |
- (1 << 28) |
- (1 << 29) |
- (1 << 31) |
- (1 << 32) |
- (1 << 34) |
- (1 << 35) |
- (1 << 40) |
- (1 << 41) |
- (1 << 42) |
- (1 << 43);
-
- self.flags |= avx512_mask;
- self
- }
-
- pub fn cx8(&self) -> bool {
- self.flags & (1 << 44) != 0
- }
-
- pub fn with_cx8(mut self) -> Self {
- self.flags |= 1 << 44;
- self
- }
-
- pub fn syscall(&self) -> bool {
- self.flags & (1 << 45) != 0
- }
-
- pub fn with_syscall(mut self) -> Self {
- self.flags |= 1 << 45;
- self
- }
-
- pub fn rdtscp(&self) -> bool {
- self.flags & (1 << 46) != 0
- }
-
- pub fn with_rdtscp(mut self) -> Self {
- self.flags |= 1 << 46;
- self
- }
-
- pub fn abm(&self) -> bool {
- self.flags & (1 << 47) != 0
- }
-
- pub fn with_abm(mut self) -> Self {
- self.flags |= 1 << 47;
- self
- }
-
- pub fn sse4a(&self) -> bool {
- self.flags & (1 << 48) != 0
- }
-
- pub fn with_sse4a(mut self) -> Self {
- self.flags |= 1 << 48;
- self
- }
-
- pub fn _3dnowprefetch(&self) -> bool {
- self.flags & (1 << 49) != 0
- }
-
- pub fn with_3dnowprefetch(mut self) -> Self {
- self.flags |= 1 << 49;
- self
- }
-
- pub fn xop(&self) -> bool {
- self.flags & (1 << 50) != 0
- }
-
- pub fn with_xop(mut self) -> Self {
- self.flags |= 1 << 50;
- self
- }
-
- pub fn skinit(&self) -> bool {
- self.flags & (1 << 51) != 0
- }
-
- pub fn with_skinit(mut self) -> Self {
- self.flags |= 1 << 51;
- self
- }
-
- pub fn tbm(&self) -> bool {
- self.flags & (1 << 52) != 0
- }
-
- pub fn with_tbm(mut self) -> Self {
- self.flags |= 1 << 52;
- self
- }
-
- pub fn intel_quirks(&self) -> bool {
- self.flags & (1 << 53) != 0
- }
-
- pub fn with_intel_quirks(mut self) -> Self {
- self.flags |= 1 << 53;
- self
- }
-
- pub fn amd_quirks(&self) -> bool {
- self.flags & (1 << 54) != 0
- }
-
- pub fn with_amd_quirks(mut self) -> Self {
- self.flags |= 1 << 54;
- self
- }
-
- pub fn avx(&self) -> bool {
- self.flags & (1 << 55) != 0
- }
-
- pub fn with_avx(mut self) -> Self {
- self.flags |= 1 << 55;
- self
- }
-
- pub fn svm(&self) -> bool {
- self.flags & (1 << 56) != 0
- }
-
- pub fn with_svm(mut self) -> Self {
- self.flags |= 1 << 56;
- self
- }
-
- /// `lahfsahf` is only unset for early revisions of 64-bit amd and intel chips. unfortunately
- /// the clearest documentation on when these instructions were reintroduced into 64-bit
- /// architectures seems to be
- /// [wikipedia](https://en.wikipedia.org/wiki/X86-64#Older_implementations):
- /// ```text
- /// Early AMD64 and Intel 64 CPUs lacked LAHF and SAHF instructions in 64-bit mode. AMD
- /// introduced these instructions (also in 64-bit mode) with their Athlon 64, Opteron and
- /// Turion 64 revision D processors in March 2005[48][49][50] while Intel introduced the
- /// instructions with the Pentium 4 G1 stepping in December 2005. The 64-bit version of Windows
- /// 8.1 requires this feature.[47]
- /// ```
- ///
- /// this puts reintroduction of these instructions somewhere in the middle of prescott and k8
- /// lifecycles, for intel and amd respectively. because there is no specific uarch where these
- /// features become enabled, prescott and k8 default to not supporting these instructions,
- /// where later uarches support these instructions.
- pub fn lahfsahf(&self) -> bool {
- self.flags & (1 << 57) != 0
- }
-
- pub fn with_lahfsahf(mut self) -> Self {
- self.flags |= 1 << 57;
- self
- }
-
- pub fn cmov(&self) -> bool {
- self.flags & (1 << 58) != 0
- }
-
- pub fn with_cmov(mut self) -> Self {
- self.flags |= 1 << 58;
- self
- }
-
- pub fn f16c(&self) -> bool {
- self.flags & (1 << 59) != 0
- }
-
- pub fn with_f16c(mut self) -> Self {
- self.flags |= 1 << 59;
- self
- }
-
- pub fn fma4(&self) -> bool {
- self.flags & (1 << 60) != 0
- }
-
- pub fn with_fma4(mut self) -> Self {
- self.flags |= 1 << 60;
- self
- }
-
- pub fn prefetchw(&self) -> bool {
- self.flags & (1 << 61) != 0
- }
+pub struct DecodeEverything {}
- pub fn with_prefetchw(mut self) -> Self {
- self.flags |= 1 << 61;
- self
- }
-
- pub fn tsx(&self) -> bool {
- self.flags & (1 << 62) != 0
- }
+impl Decoder<Arch> for DecodeEverything {
+ fn decode<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(&self, words: &mut T) -> Result<Instruction, <Arch as yaxpeax_arch::Arch>::DecodeError> {
+ let mut instr = Instruction::invalid();
+ self.decode_into(&mut instr, words)?;
- pub fn with_tsx(mut self) -> Self {
- self.flags |= 1 << 62;
- self
+ Ok(instr)
}
-
- pub fn lzcnt(&self) -> bool {
- self.flags & (1 << 63) != 0
+ #[inline(always)]
+ fn decode_into<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(&self, instr: &mut Instruction, words: &mut T) -> Result<(), <Arch as yaxpeax_arch::Arch>::DecodeError> {
+ self.decode_with_annotation(instr, words, &mut NullSink)
}
+}
- pub fn with_lzcnt(mut self) -> Self {
- self.flags |= 1 << 63;
- self
- }
+impl AnnotatingDecoder<Arch> for DecodeEverything {
+ type FieldDescription = FieldDescription;
- /// optionally reject or reinterpret instruction according to the decoder's
- /// declared extensions.
- fn revise_instruction(&self, inst: &mut Instruction) -> Result<(), DecodeError> {
- if inst.prefixes.evex().is_some() {
- if !self.avx512() {
- return Err(DecodeError::InvalidOpcode);
- } else {
- return Ok(());
- }
- }
- match inst.opcode {
- Opcode::TZCNT => {
- if !self.bmi1() {
- // tzcnt is only supported if bmi1 is enabled. without bmi1, this decodes as
- // bsf.
- inst.opcode = Opcode::BSF;
- }
- }
- Opcode::LDDQU |
- Opcode::ADDSUBPS |
- Opcode::ADDSUBPD |
- Opcode::HADDPS |
- Opcode::HSUBPS |
- Opcode::HADDPD |
- Opcode::HSUBPD |
- Opcode::MOVSHDUP |
- Opcode::MOVSLDUP |
- Opcode::MOVDDUP |
- Opcode::MONITOR |
- Opcode::MWAIT => {
- // via Intel section 5.7, SSE3 Instructions
- if !self.sse3() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::PHADDW |
- Opcode::PHADDSW |
- Opcode::PHADDD |
- Opcode::PHSUBW |
- Opcode::PHSUBSW |
- Opcode::PHSUBD |
- Opcode::PABSB |
- Opcode::PABSW |
- Opcode::PABSD |
- Opcode::PMADDUBSW |
- Opcode::PMULHRSW |
- Opcode::PSHUFB |
- Opcode::PSIGNB |
- Opcode::PSIGNW |
- Opcode::PSIGND |
- Opcode::PALIGNR => {
- // via Intel section 5.8, SSSE3 Instructions
- if !self.ssse3() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::PMULLD |
- Opcode::PMULDQ |
- Opcode::MOVNTDQA |
- Opcode::BLENDPD |
- Opcode::BLENDPS |
- Opcode::BLENDVPD |
- Opcode::BLENDVPS |
- Opcode::PBLENDVB |
- Opcode::BLENDW |
- Opcode::PMINUW |
- Opcode::PMINUD |
- Opcode::PMINSB |
- Opcode::PMINSD |
- Opcode::PMAXUW |
- Opcode::PMAXUD |
- Opcode::PMAXSB |
- Opcode::PMAXSD |
- Opcode::ROUNDPS |
- Opcode::ROUNDPD |
- Opcode::ROUNDSS |
- Opcode::ROUNDSD |
- Opcode::PBLENDW |
- Opcode::EXTRACTPS |
- Opcode::INSERTPS |
- Opcode::PINSRB |
- Opcode::PINSRD |
- Opcode::PINSRQ |
- Opcode::PMOVSXBW |
- Opcode::PMOVZXBW |
- Opcode::PMOVSXBD |
- Opcode::PMOVZXBD |
- Opcode::PMOVSXWD |
- Opcode::PMOVZXWD |
- Opcode::PMOVSXBQ |
- Opcode::PMOVZXBQ |
- Opcode::PMOVSXWQ |
- Opcode::PMOVZXWQ |
- Opcode::PMOVSXDQ |
- Opcode::PMOVZXDQ |
- Opcode::DPPS |
- Opcode::DPPD |
- Opcode::MPSADBW |
- Opcode::PHMINPOSUW |
- Opcode::PTEST |
- Opcode::PCMPEQQ |
- Opcode::PEXTRB |
- Opcode::PEXTRW |
- Opcode::PEXTRD |
- Opcode::PEXTRQ |
- Opcode::PACKUSDW => {
- // via Intel section 5.10, SSE4.1 Instructions
- if !self.sse4_1() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::EXTRQ |
- Opcode::INSERTQ |
- Opcode::MOVNTSS |
- Opcode::MOVNTSD => {
- if !self.sse4a() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::CRC32 |
- Opcode::PCMPESTRI |
- Opcode::PCMPESTRM |
- Opcode::PCMPISTRI |
- Opcode::PCMPISTRM |
- Opcode::PCMPGTQ => {
- // via Intel section 5.11, SSE4.2 Instructions
- if !self.sse4_2() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::AESDEC |
- Opcode::AESDECLAST |
- Opcode::AESENC |
- Opcode::AESENCLAST |
- Opcode::AESIMC |
- Opcode::AESKEYGENASSIST => {
- // via Intel section 5.12. AESNI AND PCLMULQDQ
- if !self.aesni() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::PCLMULQDQ => {
- // via Intel section 5.12. AESNI AND PCLMULQDQ
- if !self.pclmulqdq() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::XABORT |
- Opcode::XBEGIN |
- Opcode::XEND |
- Opcode::XTEST => {
- if !self.tsx() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::SHA1MSG1 |
- Opcode::SHA1MSG2 |
- Opcode::SHA1NEXTE |
- Opcode::SHA1RNDS4 |
- Opcode::SHA256MSG1 |
- Opcode::SHA256MSG2 |
- Opcode::SHA256RNDS2 => {
- if !self.sha() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::ENCLV |
- Opcode::ENCLS |
- Opcode::ENCLU => {
- if !self.sgx() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- // AVX...
- Opcode::VMOVDDUP |
- Opcode::VPSHUFLW |
- Opcode::VPSHUFHW |
- Opcode::VHADDPS |
- Opcode::VHSUBPS |
- Opcode::VADDSUBPS |
- Opcode::VCVTPD2DQ |
- Opcode::VLDDQU |
- Opcode::VCOMISD |
- Opcode::VCOMISS |
- Opcode::VUCOMISD |
- Opcode::VUCOMISS |
- Opcode::VADDPD |
- Opcode::VADDPS |
- Opcode::VADDSD |
- Opcode::VADDSS |
- Opcode::VADDSUBPD |
- Opcode::VBLENDPD |
- Opcode::VBLENDPS |
- Opcode::VBLENDVPD |
- Opcode::VBLENDVPS |
- Opcode::VBROADCASTF128 |
- Opcode::VBROADCASTI128 |
- Opcode::VBROADCASTSD |
- Opcode::VBROADCASTSS |
- Opcode::VCMPSD |
- Opcode::VCMPSS |
- Opcode::VCMPPD |
- Opcode::VCMPPS |
- Opcode::VCVTDQ2PD |
- Opcode::VCVTDQ2PS |
- Opcode::VCVTPD2PS |
- Opcode::VCVTPS2DQ |
- Opcode::VCVTPS2PD |
- Opcode::VCVTSS2SD |
- Opcode::VCVTSI2SS |
- Opcode::VCVTSI2SD |
- Opcode::VCVTSD2SI |
- Opcode::VCVTSD2SS |
- Opcode::VCVTSS2SI |
- Opcode::VCVTTPD2DQ |
- Opcode::VCVTTPS2DQ |
- Opcode::VCVTTSS2SI |
- Opcode::VCVTTSD2SI |
- Opcode::VDIVPD |
- Opcode::VDIVPS |
- Opcode::VDIVSD |
- Opcode::VDIVSS |
- Opcode::VDPPD |
- Opcode::VDPPS |
- Opcode::VEXTRACTF128 |
- Opcode::VEXTRACTI128 |
- Opcode::VEXTRACTPS |
- Opcode::VFMADD132PD |
- Opcode::VFMADD132PS |
- Opcode::VFMADD132SD |
- Opcode::VFMADD132SS |
- Opcode::VFMADD213PD |
- Opcode::VFMADD213PS |
- Opcode::VFMADD213SD |
- Opcode::VFMADD213SS |
- Opcode::VFMADD231PD |
- Opcode::VFMADD231PS |
- Opcode::VFMADD231SD |
- Opcode::VFMADD231SS |
- Opcode::VFMADDSUB132PD |
- Opcode::VFMADDSUB132PS |
- Opcode::VFMADDSUB213PD |
- Opcode::VFMADDSUB213PS |
- Opcode::VFMADDSUB231PD |
- Opcode::VFMADDSUB231PS |
- Opcode::VFMSUB132PD |
- Opcode::VFMSUB132PS |
- Opcode::VFMSUB132SD |
- Opcode::VFMSUB132SS |
- Opcode::VFMSUB213PD |
- Opcode::VFMSUB213PS |
- Opcode::VFMSUB213SD |
- Opcode::VFMSUB213SS |
- Opcode::VFMSUB231PD |
- Opcode::VFMSUB231PS |
- Opcode::VFMSUB231SD |
- Opcode::VFMSUB231SS |
- Opcode::VFMSUBADD132PD |
- Opcode::VFMSUBADD132PS |
- Opcode::VFMSUBADD213PD |
- Opcode::VFMSUBADD213PS |
- Opcode::VFMSUBADD231PD |
- Opcode::VFMSUBADD231PS |
- Opcode::VFNMADD132PD |
- Opcode::VFNMADD132PS |
- Opcode::VFNMADD132SD |
- Opcode::VFNMADD132SS |
- Opcode::VFNMADD213PD |
- Opcode::VFNMADD213PS |
- Opcode::VFNMADD213SD |
- Opcode::VFNMADD213SS |
- Opcode::VFNMADD231PD |
- Opcode::VFNMADD231PS |
- Opcode::VFNMADD231SD |
- Opcode::VFNMADD231SS |
- Opcode::VFNMSUB132PD |
- Opcode::VFNMSUB132PS |
- Opcode::VFNMSUB132SD |
- Opcode::VFNMSUB132SS |
- Opcode::VFNMSUB213PD |
- Opcode::VFNMSUB213PS |
- Opcode::VFNMSUB213SD |
- Opcode::VFNMSUB213SS |
- Opcode::VFNMSUB231PD |
- Opcode::VFNMSUB231PS |
- Opcode::VFNMSUB231SD |
- Opcode::VFNMSUB231SS |
- Opcode::VGATHERDPD |
- Opcode::VGATHERDPS |
- Opcode::VGATHERQPD |
- Opcode::VGATHERQPS |
- Opcode::VHADDPD |
- Opcode::VHSUBPD |
- Opcode::VINSERTF128 |
- Opcode::VINSERTI128 |
- Opcode::VINSERTPS |
- Opcode::VMASKMOVDQU |
- Opcode::VMASKMOVPD |
- Opcode::VMASKMOVPS |
- Opcode::VMAXPD |
- Opcode::VMAXPS |
- Opcode::VMAXSD |
- Opcode::VMAXSS |
- Opcode::VMINPD |
- Opcode::VMINPS |
- Opcode::VMINSD |
- Opcode::VMINSS |
- Opcode::VMOVAPD |
- Opcode::VMOVAPS |
- Opcode::VMOVD |
- Opcode::VMOVDQA |
- Opcode::VMOVDQU |
- Opcode::VMOVHLPS |
- Opcode::VMOVHPD |
- Opcode::VMOVHPS |
- Opcode::VMOVLHPS |
- Opcode::VMOVLPD |
- Opcode::VMOVLPS |
- Opcode::VMOVMSKPD |
- Opcode::VMOVMSKPS |
- Opcode::VMOVNTDQ |
- Opcode::VMOVNTDQA |
- Opcode::VMOVNTPD |
- Opcode::VMOVNTPS |
- Opcode::VMOVQ |
- Opcode::VMOVSS |
- Opcode::VMOVSD |
- Opcode::VMOVSHDUP |
- Opcode::VMOVSLDUP |
- Opcode::VMOVUPD |
- Opcode::VMOVUPS |
- Opcode::VMPSADBW |
- Opcode::VMULPD |
- Opcode::VMULPS |
- Opcode::VMULSD |
- Opcode::VMULSS |
- Opcode::VPABSB |
- Opcode::VPABSD |
- Opcode::VPABSW |
- Opcode::VPACKSSDW |
- Opcode::VPACKUSDW |
- Opcode::VPACKSSWB |
- Opcode::VPACKUSWB |
- Opcode::VPADDB |
- Opcode::VPADDD |
- Opcode::VPADDQ |
- Opcode::VPADDSB |
- Opcode::VPADDSW |
- Opcode::VPADDUSB |
- Opcode::VPADDUSW |
- Opcode::VPADDW |
- Opcode::VPALIGNR |
- Opcode::VPAND |
- Opcode::VANDPD |
- Opcode::VANDPS |
- Opcode::VANDNPD |
- Opcode::VANDNPS |
- Opcode::VORPD |
- Opcode::VORPS |
- Opcode::VPANDN |
- Opcode::VPAVGB |
- Opcode::VPAVGW |
- Opcode::VPBLENDD |
- Opcode::VPBLENDVB |
- Opcode::VPBLENDW |
- Opcode::VPBROADCASTB |
- Opcode::VPBROADCASTD |
- Opcode::VPBROADCASTQ |
- Opcode::VPBROADCASTW |
- Opcode::VPCLMULQDQ |
- Opcode::VPCMPEQB |
- Opcode::VPCMPEQD |
- Opcode::VPCMPEQQ |
- Opcode::VPCMPEQW |
- Opcode::VPCMPGTB |
- Opcode::VPCMPGTD |
- Opcode::VPCMPGTQ |
- Opcode::VPCMPGTW |
- Opcode::VPCMPESTRI |
- Opcode::VPCMPESTRM |
- Opcode::VPCMPISTRI |
- Opcode::VPCMPISTRM |
- Opcode::VPERM2F128 |
- Opcode::VPERM2I128 |
- Opcode::VPERMD |
- Opcode::VPERMILPD |
- Opcode::VPERMILPS |
- Opcode::VPERMPD |
- Opcode::VPERMPS |
- Opcode::VPERMQ |
- Opcode::VPEXTRB |
- Opcode::VPEXTRD |
- Opcode::VPEXTRQ |
- Opcode::VPEXTRW |
- Opcode::VPGATHERDD |
- Opcode::VPGATHERDQ |
- Opcode::VPGATHERQD |
- Opcode::VPGATHERQQ |
- Opcode::VPHADDD |
- Opcode::VPHADDSW |
- Opcode::VPHADDW |
- Opcode::VPMADDUBSW |
- Opcode::VPHMINPOSUW |
- Opcode::VPHSUBD |
- Opcode::VPHSUBSW |
- Opcode::VPHSUBW |
- Opcode::VPINSRB |
- Opcode::VPINSRD |
- Opcode::VPINSRQ |
- Opcode::VPINSRW |
- Opcode::VPMADDWD |
- Opcode::VPMASKMOVD |
- Opcode::VPMASKMOVQ |
- Opcode::VPMAXSB |
- Opcode::VPMAXSD |
- Opcode::VPMAXSW |
- Opcode::VPMAXUB |
- Opcode::VPMAXUW |
- Opcode::VPMAXUD |
- Opcode::VPMINSB |
- Opcode::VPMINSW |
- Opcode::VPMINSD |
- Opcode::VPMINUB |
- Opcode::VPMINUW |
- Opcode::VPMINUD |
- Opcode::VPMOVMSKB |
- Opcode::VPMOVSXBD |
- Opcode::VPMOVSXBQ |
- Opcode::VPMOVSXBW |
- Opcode::VPMOVSXDQ |
- Opcode::VPMOVSXWD |
- Opcode::VPMOVSXWQ |
- Opcode::VPMOVZXBD |
- Opcode::VPMOVZXBQ |
- Opcode::VPMOVZXBW |
- Opcode::VPMOVZXDQ |
- Opcode::VPMOVZXWD |
- Opcode::VPMOVZXWQ |
- Opcode::VPMULDQ |
- Opcode::VPMULHRSW |
- Opcode::VPMULHUW |
- Opcode::VPMULHW |
- Opcode::VPMULLQ |
- Opcode::VPMULLD |
- Opcode::VPMULLW |
- Opcode::VPMULUDQ |
- Opcode::VPOR |
- Opcode::VPSADBW |
- Opcode::VPSHUFB |
- Opcode::VPSHUFD |
- Opcode::VPSIGNB |
- Opcode::VPSIGND |
- Opcode::VPSIGNW |
- Opcode::VPSLLD |
- Opcode::VPSLLDQ |
- Opcode::VPSLLQ |
- Opcode::VPSLLVD |
- Opcode::VPSLLVQ |
- Opcode::VPSLLW |
- Opcode::VPSRAD |
- Opcode::VPSRAVD |
- Opcode::VPSRAW |
- Opcode::VPSRLD |
- Opcode::VPSRLDQ |
- Opcode::VPSRLQ |
- Opcode::VPSRLVD |
- Opcode::VPSRLVQ |
- Opcode::VPSRLW |
- Opcode::VPSUBB |
- Opcode::VPSUBD |
- Opcode::VPSUBQ |
- Opcode::VPSUBSB |
- Opcode::VPSUBSW |
- Opcode::VPSUBUSB |
- Opcode::VPSUBUSW |
- Opcode::VPSUBW |
- Opcode::VPTEST |
- Opcode::VPUNPCKHBW |
- Opcode::VPUNPCKHDQ |
- Opcode::VPUNPCKHQDQ |
- Opcode::VPUNPCKHWD |
- Opcode::VPUNPCKLBW |
- Opcode::VPUNPCKLDQ |
- Opcode::VPUNPCKLQDQ |
- Opcode::VPUNPCKLWD |
- Opcode::VPXOR |
- Opcode::VRCPPS |
- Opcode::VROUNDPD |
- Opcode::VROUNDPS |
- Opcode::VROUNDSD |
- Opcode::VROUNDSS |
- Opcode::VRSQRTPS |
- Opcode::VRSQRTSS |
- Opcode::VRCPSS |
- Opcode::VSHUFPD |
- Opcode::VSHUFPS |
- Opcode::VSQRTPD |
- Opcode::VSQRTPS |
- Opcode::VSQRTSS |
- Opcode::VSQRTSD |
- Opcode::VSUBPD |
- Opcode::VSUBPS |
- Opcode::VSUBSD |
- Opcode::VSUBSS |
- Opcode::VTESTPD |
- Opcode::VTESTPS |
- Opcode::VUNPCKHPD |
- Opcode::VUNPCKHPS |
- Opcode::VUNPCKLPD |
- Opcode::VUNPCKLPS |
- Opcode::VXORPD |
- Opcode::VXORPS |
- Opcode::VZEROUPPER |
- Opcode::VZEROALL |
- Opcode::VLDMXCSR |
- Opcode::VSTMXCSR => {
- // TODO: check a table for these
- if !self.avx() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::VAESDEC |
- Opcode::VAESDECLAST |
- Opcode::VAESENC |
- Opcode::VAESENCLAST |
- Opcode::VAESIMC |
- Opcode::VAESKEYGENASSIST => {
- // TODO: check a table for these
- if !self.avx() || !self.aesni() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::MOVBE => {
- if !self.movbe() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::POPCNT => {
- /*
- * from the intel SDM:
- * ```
- * Before an application attempts to use the POPCNT instruction, it must check that
- * the processor supports SSE4.2 (if CPUID.01H:ECX.SSE4_2[bit 20] = 1) and POPCNT
- * (if CPUID.01H:ECX.POPCNT[bit 23] = 1).
- * ```
- */
- if self.intel_quirks() && (self.sse4_2() || self.popcnt()) {
- return Ok(());
- } else if !self.popcnt() {
- /*
- * elsewhere from the amd APM:
- * `Instruction Subsets and CPUID Feature Flags` on page 507 indicates that
- * popcnt is present when the popcnt bit is reported by cpuid. this seems to be
- * the less quirky default, so `intel_quirks` is considered the outlier, and
- * before this default.
- * */
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::LZCNT => {
- /*
- * amd APM, `LZCNT` page 212:
- * LZCNT is an Advanced Bit Manipulation (ABM) instruction. Support for the LZCNT
- * instruction is indicated by CPUID Fn8000_0001_ECX[ABM] = 1.
- *
- * meanwhile the intel SDM simply states:
- * ```
- * CPUID.EAX=80000001H:ECX.LZCNT[bit 5]: if 1 indicates the processor supports the
- * LZCNT instruction.
- * ```
- *
- * so that's considered the less-quirky (default) case here.
- * */
- if self.amd_quirks() && !self.abm() {
- return Err(DecodeError::InvalidOpcode);
- } else if !self.lzcnt() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::ADCX |
- Opcode::ADOX => {
- if !self.adx() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::VMRUN |
- Opcode::VMLOAD |
- Opcode::VMSAVE |
- Opcode::CLGI |
- Opcode::VMMCALL |
- Opcode::INVLPGA => {
- if !self.svm() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::STGI |
- Opcode::SKINIT => {
- if !self.svm() || !self.skinit() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::LAHF |
- Opcode::SAHF => {
- if !self.lahfsahf() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::VCVTPS2PH |
- Opcode::VCVTPH2PS => {
- /*
- * from intel SDM:
- * ```
- * 14.4.1 Detection of F16C Instructions Application using float 16 instruction
- * must follow a detection sequence similar to AVX to ensure: • The OS has
- * enabled YMM state management support, • The processor support AVX as
- * indicated by the CPUID feature flag, i.e. CPUID.01H:ECX.AVX[bit 28] = 1. •
- * The processor support 16-bit floating-point conversion instructions via a
- * CPUID feature flag (CPUID.01H:ECX.F16C[bit 29] = 1).
- * ```
- *
- * TODO: only the VEX-coded variant of this instruction should be gated on `f16c`.
- * the EVEX-coded variant should be gated on `avx512f` or `avx512vl` if not
- * EVEX.512-coded.
- */
- if !self.avx() || !self.f16c() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::RDRAND => {
- if !self.rdrand() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::RDSEED => {
- if !self.rdseed() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- Opcode::MONITORX | Opcode::MWAITX | // these are gated on the `monitorx` and `mwaitx` cpuid bits, but are AMD-only.
- Opcode::CLZERO | Opcode::RDPRU => { // again, gated on specific cpuid bits, but AMD-only.
- if !self.amd_quirks() {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- other => {
- if !self.bmi1() {
- if BMI1.contains(&other) {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- if !self.bmi2() {
- if BMI2.contains(&other) {
- return Err(DecodeError::InvalidOpcode);
- }
- }
- }
- }
- Ok(())
+ #[inline(always)]
+ fn decode_with_annotation<
+ T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>,
+ S: DescriptionSink<Self::FieldDescription>
+ >(&self, instr: &mut Instruction, words: &mut T, sink: &mut S) -> Result<(), <Arch as yaxpeax_arch::Arch>::DecodeError> {
+ decode_with_annotation(self, instr, words, sink)
}
}
@@ -4194,7 +2852,7 @@ impl Default for InstDecoder {
/// instruction defined in any extension.
fn default() -> Self {
Self {
- flags: 0xffffffff_ffffffff,
+ flags: [0xffffffff_ffffffff, 0xffffffff_ffffffff],
}
}
}
@@ -4202,16 +2860,7 @@ impl Default for InstDecoder {
impl Decoder<Arch> for InstDecoder {
fn decode<T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>>(&self, words: &mut T) -> Result<Instruction, <Arch as yaxpeax_arch::Arch>::DecodeError> {
let mut instr = Instruction::invalid();
- DecodeCtx::new().read_with_annotations(self, words, &mut instr, &mut NullSink)?;
-
- instr.length = words.offset() as u8;
- if words.offset() > 15 {
- return Err(DecodeError::TooLong);
- }
-
- if self != &InstDecoder::default() {
- self.revise_instruction(&mut instr)?;
- }
+ self.decode_into(&mut instr, words)?;
Ok(instr)
}
@@ -4229,19 +2878,26 @@ impl AnnotatingDecoder<Arch> for InstDecoder {
T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>,
S: DescriptionSink<Self::FieldDescription>
>(&self, instr: &mut Instruction, words: &mut T, sink: &mut S) -> Result<(), <Arch as yaxpeax_arch::Arch>::DecodeError> {
- DecodeCtx::new().read_with_annotations(self, words, instr, sink)?;
-
- instr.length = words.offset() as u8;
- if words.offset() > 15 {
- return Err(DecodeError::TooLong);
- }
+ decode_with_annotation(self, instr, words, sink)
+ }
+}
- if self != &InstDecoder::default() {
- self.revise_instruction(instr)?;
- }
+#[inline(always)]
+fn decode_with_annotation<
+ D: IsaSettings,
+ T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>,
+ S: DescriptionSink<FieldDescription>
+>(isa_settings: &D, instr: &mut Instruction, words: &mut T, sink: &mut S) -> Result<(), <Arch as yaxpeax_arch::Arch>::DecodeError> {
+ DecodeCtx::new().read_with_annotations(isa_settings, words, instr, sink)?;
- Ok(())
+ instr.length = words.offset() as u8;
+ if words.offset() > 15 {
+ return Err(DecodeError::TooLong);
}
+
+ isa_settings.revise_instruction(instr)?;
+
+ Ok(())
}
impl Opcode {
@@ -6725,9 +5381,10 @@ fn read_opc_hotpath<
#[cfg_attr(feature="profiling", inline(never))]
#[cfg_attr(not(feature="profiling"), inline(always))]
fn read_with_annotations<
+ D: IsaSettings,
T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>,
S: DescriptionSink<FieldDescription>,
->(mut self, decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, sink: &mut S) -> Result<(), DecodeError> {
+>(mut self, isa_settings: &D, words: &mut T, instruction: &mut Instruction, sink: &mut S) -> Result<(), DecodeError> {
words.mark();
let mut nextb = words.next().ok().ok_or(DecodeError::ExhaustedInput)?;
let mut next_rec = OPCODES[nextb as usize];
@@ -6875,7 +5532,7 @@ fn read_with_annotations<
record.operand()
};
- self.read_operands(decoder, words, instruction, record, sink)?;
+ self.read_operands(isa_settings, words, instruction, record, sink)?;
if self.check_lock {
if !instruction.opcode.can_lock() || !instruction.operands[0].is_memory() {
@@ -6944,9 +5601,10 @@ fn read_avx_prefixed<
#[cfg_attr(feature="profiling", inline(never))]
#[cfg_attr(not(feature="profiling"), inline(always))]
fn read_operands<
+ D: IsaSettings,
T: Reader<<Arch as yaxpeax_arch::Arch>::Address, <Arch as yaxpeax_arch::Arch>::Word>,
S: DescriptionSink<FieldDescription>
->(&mut self, decoder: &InstDecoder, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, sink: &mut S) -> Result<(), DecodeError> {
+>(&mut self, isa_settings: &D, words: &mut T, instruction: &mut Instruction, operand_code: OperandCode, sink: &mut S) -> Result<(), DecodeError> {
sink.record(
words.offset() as u32 * 8 - 1, words.offset() as u32 * 8 - 1,
InnerDescription::Boundary("opcode ends/operands begin (typically)")
@@ -10070,7 +8728,7 @@ fn read_operands<
instruction.opcode = Opcode::LFENCE;
// Intel's manual accepts m != 0, AMD supports m != 0 though the manual
// doesn't say (tested on threadripper)
- if !decoder.amd_quirks() && !decoder.intel_quirks() {
+ if !isa_settings.amd_quirks() && !isa_settings.intel_quirks() {
if m != 0 {
return Err(DecodeError::InvalidOperand);
}
@@ -10080,7 +8738,7 @@ fn read_operands<
instruction.opcode = Opcode::MFENCE;
// Intel's manual accepts m != 0, AMD supports m != 0 though the manual
// doesn't say (tested on threadripper)
- if !decoder.amd_quirks() && !decoder.intel_quirks() {
+ if !isa_settings.amd_quirks() && !isa_settings.intel_quirks() {
if m != 0 {
return Err(DecodeError::InvalidOperand);
}
@@ -10090,7 +8748,7 @@ fn read_operands<
instruction.opcode = Opcode::SFENCE;
// Intel's manual accepts m != 0, AMD supports m != 0 though the manual
// doesn't say (tested on threadripper)
- if !decoder.amd_quirks() && !decoder.intel_quirks() {
+ if !isa_settings.amd_quirks() && !isa_settings.intel_quirks() {
if m != 0 {
return Err(DecodeError::InvalidOperand);
}
diff --git a/src/long_mode/uarch.rs b/src/long_mode/uarch.rs
index bfd4887..5af0175 100644
--- a/src/long_mode/uarch.rs
+++ b/src/long_mode/uarch.rs
@@ -1,12 +1,24 @@
+//! information for AMD and Intel microarchitectures in the modules below is sourced from a
+//! combination of Wikipedia (especially for dates), one-off research for particular
+//! microarchitectures, and `InstLatx64`'s CPUID dumps via [chip directory](https://github.com/iximeow/chip_directory).
+//!
+//! these microarchitecture-specific decoders are relatively rarely used, but generally should be
+//! accurate.
+
pub mod amd {
- //! most information about instruction set extensions for microarchitectures here was sourced
- //! from
- //! [https://en.wikipedia.org/wiki/AMD_Accelerated_Processing_Unit#Feature_overview](https://docs.rs/yaxpeax-x86/0.0.12/yaxpeax_x86/protected_mode/uarch/intel/index.html)
+ //! initial information for the mircoarchitecture (families) described here came from a
+ //! combination of the Wikipedia pages
+ //! [https://en.wikipedia.org/wiki/AMD_Accelerated_Processing_Unit#Feature_overview](https://en.wikipedia.org/wiki/AMD_Accelerated_Processing_Unit#Feature_overview)
//! and
- //! [https://en.wikipedia.org/wiki/Template:AMD_x86_CPU_features](https://docs.rs/yaxpeax-x86/0.0.12/yaxpeax_x86/protected_mode/uarch/intel/index.html).
- //! these mappings are best-effort but fairly unused, so a critical eye should be kept towards
- //! these decoders rejecting instructions they should not, or incorrectly accepting
- //! instructions.
+ //! [https://en.wikipedia.org/wiki/Template:AMD_x86_CPU_features](https://en.wikipedia.org/wiki/Template:AMD_x86_CPU_features).
+ //! it has been since "augmented" by the CPUID dumps from InstLatx64, via [chip
+ //! directory](https://github.com/iximeow/chip_directory/tree/no-gods-no-/x86). scare quotes
+ //! because in several cases CPUID measurement error adds, rather than removes, ambiguity.
+ //! additionally, for some CPU features, InstLatx64 has CPUID dumps of early engineering
+ //! samples where features are not present. later production steppings of those parts do
+ //! universally have the corresponding feature, which makes it less obvious which features are
+ //! universally present in a family, standardized in a following architecture, unevenly present
+ //! due to market segmentation, and so on.
//!
//! microarchitectures as defined here are with respect to flags reported by CPUID. notably,
//! `Zen` does not report `FMA4` support by `CPUID`, but instructions in that extension
@@ -35,9 +47,6 @@ pub mod amd {
.with_abm()
.with_lahfsahf()
.with_sse3()
- .with_ssse3()
- .with_sse4()
- .with_sse4_2()
.with_sse4a()
}
@@ -45,6 +54,9 @@ pub mod amd {
/// support among other extensions, and are notable for including `AESNI`.
pub fn bulldozer() -> InstDecoder {
k10()
+ .with_ssse3()
+ .with_sse4()
+ .with_sse4_2()
.with_bmi1()
.with_aesni()
.with_pclmulqdq()
@@ -52,6 +64,8 @@ pub mod amd {
.with_avx()
.with_fma4()
.with_xop()
+ .with_xsave()
+ .with_skinit()
}
/// `Piledriver` was the successor to `Bulldozer`, launched in 2012.
@@ -86,21 +100,81 @@ pub mod amd {
/// instructions to AVX2 and discarded FMA4, TBM, and XOP extensions. they also gained ADX,
/// SHA, RDSEED, and other extensions.
pub fn zen() -> InstDecoder {
+ // no nice way to *un*set feature bits, but several extensions were dropped.
+ // so, start again from K10.
k10()
+ // first, bundle all the K10->Bulldozer features..
+ .with_ssse3()
+ .with_sse4()
+ .with_sse4_2()
+ .with_bmi1()
+ .with_aesni()
+ .with_pclmulqdq()
+ .with_f16c()
.with_avx()
+ .with_xsave()
+ .with_skinit()
+ // now all the Bulldozer (/Piledriver/Steamroller/Excavator)->Zen features
.with_avx2()
- .with_bmi1()
.with_aesni()
.with_pclmulqdq()
.with_f16c()
.with_movbe()
.with_bmi2()
- .with_rdrand()
.with_adx()
.with_sha()
+ .with_rdrand()
.with_rdseed()
.with_fma3()
- // TODO: XSAVEC, XSAVES, XRSTORS, CLFLUSHOPT, CLZERO?
+
+ .with_xsavec()
+ .with_xsaves()
+ .with_xsaveopt()
+ .with_clflushopt()
+ .with_clwb()
+ .with_fsgsbase()
+ .with_monitorx()
+ }
+
+ /// `Zen 2`, launched in 2019, succeeded `Zen`/`Zen+`. there aren't many instruction set
+ /// extensions here, but `clwb`, `rdpid`, and `wbnoinvd` show up here.
+ pub fn zen2() -> InstDecoder {
+ zen()
+ .with_clwb()
+ .with_rdpid()
+ .with_wbnoinvd()
+ }
+
+ /// `Zen 3`, launched in 2020, succeeded `Zen 2`. like `Zen 2`, there aren't many instruction
+ /// set extensions here.
+ pub fn zen3() -> InstDecoder {
+ zen2()
+ .with_invpcid()
+ .with_vaes()
+ .with_vpclmulqdq()
+ }
+
+ /// `Zen 4`, launched in 2022, succeeded `Zen 3`. `Zen 4` is notable for being the first AMD
+ /// processor family supporting AVX-512.
+ pub fn zen4() -> InstDecoder {
+ zen3()
+ .with_avx512_f()
+ .with_avx512_vl()
+ .with_avx512_bw()
+ .with_avx512_cd()
+ .with_avx512_cd()
+ .with_avx512_vbmi()
+ .with_avx512_vbmi2()
+ .with_avx512_vpopcntdq()
+ .with_gfni()
+ }
+
+ /// `Zen 5`, launched in 2024, succeeded `Zen 4`. `Zen 5` adds only a few additional
+ /// instructions; some AVX-512 features, `enqcmd`, and `movdir64b`.
+ pub fn zen5() -> InstDecoder {
+ zen4()
+ .with_movdir64b()
+ .with_enqcmd()
}
}