aboutsummaryrefslogtreecommitdiff
path: root/src/long_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/long_mode')
-rw-r--r--src/long_mode/display.rs54
-rw-r--r--src/long_mode/mod.rs316
-rw-r--r--src/long_mode/uarch.rs4
-rw-r--r--src/long_mode/vex.rs182
4 files changed, 501 insertions, 55 deletions
diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs
index 5318ebb..807565c 100644
--- a/src/long_mode/display.rs
+++ b/src/long_mode/display.rs
@@ -306,6 +306,9 @@ impl fmt::Display for Opcode {
&Opcode::BTC => write!(f, "btc"),
&Opcode::BSF => write!(f, "bsf"),
&Opcode::BSR => write!(f, "bsr"),
+ &Opcode::BZHI => write!(f, "bzhi"),
+ &Opcode::PDEP => write!(f, "pdep"),
+ &Opcode::PEXT => write!(f, "pext"),
&Opcode::TZCNT => write!(f, "tzcnt"),
&Opcode::MOVSS => write!(f, "movss"),
&Opcode::SQRTSS => write!(f, "sqrtss"),
@@ -354,17 +357,30 @@ impl fmt::Display for Opcode {
&Opcode::RDMSR => write!(f, "rdmsr"),
&Opcode::RDTSC => write!(f, "rdtsc"),
&Opcode::RDPMC => write!(f, "rdpmc"),
+ &Opcode::RDPID => write!(f, "rdpid"),
+ &Opcode::RDFSBASE => write!(f, "rdfsbase"),
+ &Opcode::RDGSBASE => write!(f, "rdgsbase"),
+ &Opcode::WRFSBASE => write!(f, "wrfsbase"),
+ &Opcode::WRGSBASE => write!(f, "wrgsbase"),
&Opcode::FXSAVE => write!(f, "fxsave"),
&Opcode::FXRSTOR => write!(f, "fxrstor"),
&Opcode::LDMXCSR => write!(f, "ldmxcsr"),
&Opcode::STMXCSR => write!(f, "stmxcsr"),
&Opcode::XSAVE => write!(f, "xsave"),
+ &Opcode::XSAVEC => write!(f, "xsavec"),
+ &Opcode::XSAVES => write!(f, "xsaves"),
+ &Opcode::XSAVEC64 => write!(f, "xsavec64"),
+ &Opcode::XSAVES64 => write!(f, "xsaves64"),
&Opcode::XRSTOR => write!(f, "xrstor"),
+ &Opcode::XRSTORS => write!(f, "xrstors"),
+ &Opcode::XRSTORS64 => write!(f, "xrstors64"),
&Opcode::XSAVEOPT => write!(f, "xsaveopt"),
&Opcode::LFENCE => write!(f, "lfence"),
&Opcode::MFENCE => write!(f, "mfence"),
&Opcode::SFENCE => write!(f, "sfence"),
&Opcode::CLFLUSH => write!(f, "clflush"),
+ &Opcode::CLFLUSHOPT => write!(f, "clflushopt"),
+ &Opcode::CLWB => write!(f, "clwb"),
&Opcode::SGDT => write!(f, "sgdt"),
&Opcode::SIDT => write!(f, "sidt"),
&Opcode::LGDT => write!(f, "lgdt"),
@@ -450,11 +466,15 @@ impl fmt::Display for Opcode {
&Opcode::SAR => write!(f, "sar"),
&Opcode::SAL => write!(f, "sal"),
&Opcode::SHR => write!(f, "shr"),
+ &Opcode::SARX => write!(f, "sarx"),
+ &Opcode::SHLX => write!(f, "shlx"),
+ &Opcode::SHRX => write!(f, "shrx"),
&Opcode::SHRD => write!(f, "shrd"),
&Opcode::SHL => write!(f, "shl"),
&Opcode::RCR => write!(f, "rcr"),
&Opcode::RCL => write!(f, "rcl"),
&Opcode::ROR => write!(f, "ror"),
+ &Opcode::RORX => write!(f, "rorx"),
&Opcode::ROL => write!(f, "rol"),
&Opcode::CMOVA => write!(f, "cmova"),
&Opcode::CMOVB => write!(f, "cmovb"),
@@ -475,9 +495,12 @@ impl fmt::Display for Opcode {
&Opcode::NEG => write!(f, "neg"),
&Opcode::NOT => write!(f, "not"),
&Opcode::MUL => write!(f, "mul"),
+ &Opcode::MULX => write!(f, "mulx"),
&Opcode::DIV => write!(f, "div"),
&Opcode::IDIV => write!(f, "idiv"),
&Opcode::CMPXCHG => write!(f, "cmpxchg"),
+ &Opcode::CMPXCHG8B => write!(f, "cmpxchg8b"),
+ &Opcode::CMPXCHG16B => write!(f, "cmpxchg16b"),
&Opcode::MOVSX_b => write!(f, "movsx"),
&Opcode::MOVSX_w => write!(f, "movsx"),
&Opcode::MOVZX_b => write!(f, "movzx"),
@@ -652,6 +675,8 @@ impl fmt::Display for Opcode {
&Opcode::BLSMSK => write!(f, "blsmsk"),
&Opcode::BLSR => write!(f, "blsr"),
&Opcode::VMCLEAR => write!(f, "vmclear"),
+ &Opcode::VMPTRLD => write!(f, "vmptrld"),
+ &Opcode::VMPTRST => write!(f, "vmptrst"),
&Opcode::VMXON => write!(f, "vmxon"),
&Opcode::VMCALL => write!(f, "vmcall"),
&Opcode::VMLAUNCH => write!(f, "vmlaunch"),
@@ -1310,16 +1335,21 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::DIV |
Opcode::IDIV |
Opcode::MUL |
+ Opcode::MULX |
Opcode::NEG |
Opcode::NOT |
Opcode::SAR |
Opcode::SAL |
Opcode::SHR |
+ Opcode::SARX |
+ Opcode::SHLX |
+ Opcode::SHRX |
Opcode::SHRD |
Opcode::SHL |
Opcode::RCR |
Opcode::RCL |
Opcode::ROR |
+ Opcode::RORX |
Opcode::ROL |
Opcode::INC |
Opcode::DEC |
@@ -1341,6 +1371,9 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::BTC |
Opcode::BSF |
Opcode::BSR |
+ Opcode::BZHI |
+ Opcode::PDEP |
+ Opcode::PEXT |
Opcode::TZCNT |
Opcode::ANDN |
Opcode::BEXTR |
@@ -1833,23 +1866,38 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::CMP |
Opcode::CMPPS |
Opcode::CMPPD |
+ Opcode::CMPXCHG8B |
+ Opcode::CMPXCHG16B |
Opcode::CMPXCHG => { write!(out, "{}", colors.comparison_op(self)) }
Opcode::WRMSR |
Opcode::RDMSR |
Opcode::RDTSC |
Opcode::RDPMC |
+ Opcode::RDPID |
+ Opcode::RDFSBASE |
+ Opcode::RDGSBASE |
+ Opcode::WRFSBASE |
+ Opcode::WRGSBASE |
Opcode::FXSAVE |
Opcode::FXRSTOR |
Opcode::LDMXCSR |
Opcode::STMXCSR |
Opcode::XSAVE |
+ Opcode::XSAVEC |
+ Opcode::XSAVES |
+ Opcode::XSAVEC64 |
+ Opcode::XSAVES64 |
Opcode::XRSTOR |
+ Opcode::XRSTORS |
+ Opcode::XRSTORS64 |
Opcode::XSAVEOPT |
Opcode::LFENCE |
Opcode::MFENCE |
Opcode::SFENCE |
Opcode::CLFLUSH |
+ Opcode::CLFLUSHOPT |
+ Opcode::CLWB |
Opcode::SGDT |
Opcode::SIDT |
Opcode::LGDT |
@@ -1886,6 +1934,8 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> Colorize<T, Color
Opcode::VMREAD |
Opcode::VMWRITE |
Opcode::VMCLEAR |
+ Opcode::VMPTRLD |
+ Opcode::VMPTRST |
Opcode::VMXON |
Opcode::VMCALL |
Opcode::VMLAUNCH |
@@ -1993,6 +2043,10 @@ impl <T: fmt::Write, Color: fmt::Display, Y: YaxColors<Color>> ShowContextual<u6
self.opcode.colorize(colors, out)?;
+ if self.opcode == Opcode::XBEGIN {
+ return write!(out, " $+{}", colors.number(signed_i32_hex(self.imm as i32)));
+ }
+
match self.operands[0] {
OperandSpec::Nothing => {
return Ok(());
diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs
index 20abe1f..58d4c57 100644
--- a/src/long_mode/mod.rs
+++ b/src/long_mode/mod.rs
@@ -528,17 +528,36 @@ const BMI1: [Opcode; 6] = [
Opcode::TZCNT,
];
+const BMI2: [Opcode; 8] = [
+ Opcode::BZHI,
+ Opcode::MULX,
+ Opcode::PDEP,
+ Opcode::PEXT,
+ Opcode::RORX,
+ Opcode::SARX,
+ Opcode::SHRX,
+ Opcode::SHLX,
+];
+
+#[allow(dead_code)]
+const XSAVE: [Opcode; 10] = [
+ Opcode::XGETBV,
+ Opcode::XRSTOR,
+ Opcode::XRSTORS,
+ Opcode::XSAVE,
+ Opcode::XSAVEC,
+ Opcode::XSAVEC64,
+ Opcode::XSAVEOPT,
+ Opcode::XSAVES,
+ Opcode::XSAVES64,
+ Opcode::XSETBV,
+];
+
// TODO:
// PTWRITE
-// RDFSBASE
-// RDGSBASE
-// WRFSBASE
-// WRGSBASE
// TPAUSE
// UMONITOR
// UMWAIT
-// CLFLUSHOPT
-// CLWB
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Opcode {
@@ -740,6 +759,8 @@ pub enum Opcode {
MFENCE,
SFENCE,
CLFLUSH,
+ CLFLUSHOPT,
+ CLWB,
WRMSR,
RDTSC,
RDMSR,
@@ -1376,6 +1397,32 @@ pub enum Opcode {
ADOX,
PREFETCHW,
+
+ RDPID,
+ CMPXCHG8B,
+ CMPXCHG16B,
+ VMPTRLD,
+ VMPTRST,
+
+ BZHI,
+ MULX,
+ SHLX,
+ SHRX,
+ SARX,
+ PDEP,
+ PEXT,
+ RORX,
+ XRSTORS,
+ XRSTORS64,
+ XSAVEC,
+ XSAVEC64,
+ XSAVES,
+ XSAVES64,
+
+ RDFSBASE,
+ RDGSBASE,
+ WRFSBASE,
+ WRGSBASE,
}
#[derive(Debug)]
@@ -2094,7 +2141,7 @@ impl InstDecoder {
/// 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
@@ -2686,9 +2733,8 @@ impl InstDecoder {
* (if CPUID.01H:ECX.POPCNT[bit 23] = 1).
* ```
*/
- if self.intel_quirks() && (!self.sse4_2() || !self.popcnt()) {
- inst.opcode = Opcode::Invalid;
- return Err(DecodeError::InvalidOpcode);
+ if self.intel_quirks() && (self.sse4_2() || self.popcnt()) {
+ return Ok(());
} else if !self.popcnt() {
/*
* elsewhere from the amd APM:
@@ -2795,6 +2841,11 @@ impl InstDecoder {
return Err(DecodeError::InvalidOpcode);
}
}
+ if !self.bmi2() {
+ if BMI2.contains(&other) {
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
}
}
Ok(())
@@ -3137,6 +3188,8 @@ pub enum OperandCode {
ModRM_0x0fae,
ModRM_0x0fba,
ModRM_0xf238,
+ ModRM_0xf30fae,
+ ModRM_0x660fae,
ModRM_0xf30fc7,
ModRM_0x660f38,
ModRM_0xf30f38,
@@ -3513,7 +3566,7 @@ const OPCODE_660F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0x660fae),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
// 0xb0
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
@@ -4075,7 +4128,7 @@ const OPCODE_F30F_MAP: [OpcodeRecord; 256] = [
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
- OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
+ OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::ModRM_0xf30fae),
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
// 0xb0
OpcodeRecord(Interpretation::Instruction(Opcode::Invalid), OperandCode::Nothing),
@@ -5379,13 +5432,12 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
return Ok(());
} else {
instruction.opcode = Opcode::XBEGIN;
- instruction.disp = if opwidth == 2 {
+ instruction.imm = if opwidth == 2 {
read_imm_signed(&mut bytes_iter, 2, length)? as i16 as i64 as u64
} else {
read_imm_signed(&mut bytes_iter, 4, length)? as i32 as i64 as u64
};
- instruction.modrm_mmm = RegSpec::rip();
- instruction.operands[0] = OperandSpec::RegDisp;
+ instruction.operands[0] = OperandSpec::ImmI32;
instruction.operand_count = 1;
return Ok(());
}
@@ -5628,6 +5680,9 @@ fn read_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter: T,
instruction.imm =
read_num(&mut bytes_iter, 1)? as u8 as u64;
*length += 1;
+ if instruction.operands[1] == OperandSpec::RegMMM {
+ instruction.modrm_mmm.bank = RegisterBank::MM;
+ }
instruction.operands[2] = OperandSpec::ImmI8;
instruction.operand_count = 3;
},
@@ -5776,7 +5831,7 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
}
OperandCode::ModRM_0x0f0d => {
let modrm = read_modrm(&mut bytes_iter, length)?;
- let r = modrm & 0b111;
+ let r = (modrm >> 3) & 0b111;
let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes);
@@ -5842,46 +5897,94 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
return read_operands(decoder, bytes_iter, instruction, operands, length);
},
OperandCode::ModRM_0x0f3a => {
+ let opcode = read_modrm(&mut bytes_iter, length)?;
+ if opcode == 0xcc {
+ instruction.opcode = Opcode::SHA1RNDS4;
+ return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_xmm_Ib, length);
+ } else if opcode == 0x0f {
+ instruction.opcode = Opcode::PALIGNR;
+ return read_operands(decoder, bytes_iter, instruction, OperandCode::G_E_mm_Ib, length);
+ }
},
OperandCode::ModRM_0x0fc7 => {
let modrm = read_modrm(&mut bytes_iter, length)?;
- if modrm >> 6 == 0b11 {
- match (modrm >> 3) & 0b111 {
- 0b111 => {
- instruction.opcode = Opcode::RDSEED;
- instruction.operand_count = 1;
- instruction.operands[0] = OperandSpec::RegRRR;
- let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes);
- instruction.modrm_rrr =
- RegSpec::from_parts(modrm & 7, instruction.prefixes.rex().r(), match opwidth {
- 8 => RegisterBank::Q,
- 4 => RegisterBank::D,
- 2 => RegisterBank::W,
- _ => unreachable!()
- });
+ let is_reg = (modrm & 0xc0) == 0xc0;
+
+ let r = (modrm >> 3) & 0b111;
+
+ let opcode = match r {
+ 0b001 => {
+ if is_reg {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ } else {
+ if instruction.prefixes.rex().w() {
+ Opcode::CMPXCHG16B
+ } else {
+ Opcode::CMPXCHG8B
+ }
}
- 0b110 => {
- instruction.opcode = Opcode::RDRAND;
- instruction.operand_count = 1;
- instruction.operands[0] = OperandSpec::RegRRR;
- let opwidth = imm_width_from_prefixes_64(SizeCode::vq, instruction.prefixes);
- instruction.modrm_rrr =
- RegSpec::from_parts(modrm & 7, instruction.prefixes.rex().r(), match opwidth {
- 8 => RegisterBank::Q,
- 4 => RegisterBank::D,
- 2 => RegisterBank::W,
- _ => unreachable!()
- });
+ }
+ 0b011 => {
+ if is_reg {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ } else {
+ if instruction.prefixes.rex().w() {
+ Opcode::XRSTORS64
+ } else {
+ Opcode::XRSTORS
+ }
}
- _ => {
+ }
+ 0b100 => {
+ if is_reg {
instruction.opcode = Opcode::Invalid;
- return Err(DecodeError::InvalidOpcode);
+ return Err(DecodeError::InvalidOperand);
+ } else {
+ if instruction.prefixes.rex().w() {
+ Opcode::XSAVEC64
+ } else {
+ Opcode::XSAVEC
+ }
}
}
- } else {
- instruction.opcode = Opcode::Invalid;
- return Err(DecodeError::InvalidOpcode);
- }
+ 0b101 => {
+ if is_reg {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ } else {
+ if instruction.prefixes.rex().w() {
+ Opcode::XSAVES64
+ } else {
+ Opcode::XSAVES
+ }
+ }
+ }
+ 0b110 => {
+ if is_reg {
+ Opcode::RDRAND
+ } else {
+ Opcode::VMPTRLD
+ }
+ }
+ 0b111 => {
+ if is_reg {
+ Opcode::RDSEED
+ } else {
+ Opcode::VMPTRST
+ }
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOperand);
+ }
+ };
+
+ instruction.opcode = opcode;
+ instruction.operand_count = 1;
+ let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
},
OperandCode::ModRM_0x0f71 => {
instruction.operand_count = 2;
@@ -6168,15 +6271,33 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
instruction.operands[1] = OperandSpec::ImmU8;
},
OperandCode::ModRM_0x660fc7 => {
+ let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
let modrm = read_modrm(&mut bytes_iter, length)?;
let r = (modrm >> 3) & 7;
match r {
6 => {
instruction.opcode = Opcode::VMCLEAR;
- instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
if instruction.operands[0] == OperandSpec::RegMMM {
- return Err(DecodeError::InvalidOperand);
+ // this would be invalid as `vmclear`, so fall back to the parse as
+ // 66-prefixed rdrand. this is a register operand, so just demote it to the
+ // word-form operand:
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::W, num: instruction.modrm_mmm.num };
+ instruction.opcode = Opcode::RDRAND;
+ }
+ instruction.operand_count = 1;
+ }
+ 7 => {
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ if instruction.operands[0] == OperandSpec::RegMMM {
+ // this would be invalid as `vmclear`, so fall back to the parse as
+ // 66-prefixed rdrand. this is a register operand, so just demote it to the
+ // word-form operand:
+ instruction.modrm_mmm = RegSpec { bank: RegisterBank::W, num: instruction.modrm_mmm.num };
+ instruction.opcode = Opcode::RDSEED;
+ } else {
+ return Err(DecodeError::InvalidOpcode);
}
instruction.operand_count = 1;
}
@@ -6185,15 +6306,108 @@ fn unlikely_operands<T: Iterator<Item=u8>>(decoder: &InstDecoder, mut bytes_iter
}
}
},
+ OperandCode::ModRM_0x660fae => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+ if modrm < 0xc0 {
+ instruction.opcode = match (modrm >> 3) & 7 {
+ 6 => {
+ Opcode::CLWB
+ }
+ 7 => {
+ Opcode::CLFLUSHOPT
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* opwidth */, length)?;
+ instruction.operand_count = 1;
+ } else {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ },
+ OperandCode::ModRM_0xf30fae => {
+ let modrm = read_modrm(&mut bytes_iter, length)?;
+
+ if (modrm & 0xc0) == 0xc0 {
+ let r = (modrm >> 3) & 7;
+ let m = modrm & 7;
+ match r {
+ 0 => {
+ instruction.opcode = Opcode::RDFSBASE;
+ let opwidth = if instruction.prefixes.rex().w() {
+ RegisterBank::Q
+ } else {
+ RegisterBank::D
+ };
+ instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth);
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.operand_count = 1;
+ }
+ 1 => {
+ instruction.opcode = Opcode::RDGSBASE;
+ let opwidth = if instruction.prefixes.rex().w() {
+ RegisterBank::Q
+ } else {
+ RegisterBank::D
+ };
+ instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth);
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.operand_count = 1;
+
+ }
+ 2 => {
+ instruction.opcode = Opcode::WRFSBASE;
+ let opwidth = if instruction.prefixes.rex().w() {
+ RegisterBank::Q
+ } else {
+ RegisterBank::D
+ };
+ instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth);
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.operand_count = 1;
+ }
+ 3 => {
+ instruction.opcode = Opcode::WRGSBASE;
+ let opwidth = if instruction.prefixes.rex().w() {
+ RegisterBank::Q
+ } else {
+ RegisterBank::D
+ };
+ instruction.modrm_mmm = RegSpec::from_parts(m, instruction.prefixes.rex().x(), opwidth);
+ instruction.operands[0] = OperandSpec::RegMMM;
+ instruction.operand_count = 1;
+
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ }
+ }
OperandCode::ModRM_0xf30fc7 => {
+ let opwidth = imm_width_from_prefixes_64(SizeCode::vqp, instruction.prefixes);
let modrm = read_modrm(&mut bytes_iter, length)?;
let r = (modrm >> 3) & 7;
match r {
6 => {
instruction.opcode = Opcode::VMXON;
- instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, 1 /* doesn't matter, something using this width is invalid */, length)?;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
if instruction.operands[0] == OperandSpec::RegMMM {
+ // this would be invalid as `vmxon`, so fall back to the parse as
+ // f3-prefixed rdrand
+ instruction.opcode = Opcode::RDRAND;
+ }
+ instruction.operand_count = 1;
+ }
+ 7 => {
+ instruction.opcode = Opcode::RDPID;
+ instruction.operands[0] = read_E(&mut bytes_iter, instruction, modrm, opwidth, length)?;
+ if instruction.operands[0] != OperandSpec::RegMMM {
return Err(DecodeError::InvalidOperand);
}
instruction.operand_count = 1;
diff --git a/src/long_mode/uarch.rs b/src/long_mode/uarch.rs
index b2b1201..94b6b45 100644
--- a/src/long_mode/uarch.rs
+++ b/src/long_mode/uarch.rs
@@ -203,7 +203,9 @@ pub mod intel {
/// common denominator: if you want a `Skylake` decoder with AVX512, something like the
/// following:
/// ```
- /// InstDecoder::skylake().with_avx512_f().with_avx512_dq()
+ /// yaxpeax_x86::long_mode::uarch::intel::skylake()
+ /// .with_avx512_f()
+ /// .with_avx512_dq();
/// ```
/// is likely your best option.
pub fn skylake() -> InstDecoder {
diff --git a/src/long_mode/vex.rs b/src/long_mode/vex.rs
index fe50c4e..cf30622 100644
--- a/src/long_mode/vex.rs
+++ b/src/long_mode/vex.rs
@@ -83,6 +83,10 @@ enum VEXOperandCode {
Ed_G_xmm,
G_xmm_Ed,
G_xmm_Eq,
+ G_E_V,
+ G_V_E,
+ G_E_Ib,
+ BMI1_F3,
}
#[inline(never)]
@@ -694,6 +698,88 @@ fn read_vex_operands<T: Iterator<Item=u8>>(bytes: &mut T, instruction: &mut Inst
instruction.operands[2] = OperandSpec::RegVex;
Ok(())
}
+ VEXOperandCode::G_V_E => {
+ let modrm = read_modrm(bytes, length)?;
+ let (opwidth, bank) = if instruction.prefixes.vex().w() {
+ (8, RegisterBank::Q)
+ } else {
+ (4, RegisterBank::D)
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank);
+ instruction.vex_reg.bank = bank;
+ let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = OperandSpec::RegVex;
+ instruction.operands[2] = mem_oper;
+ instruction.operand_count = 3;
+ Ok(())
+ }
+ VEXOperandCode::G_E_V => {
+ let modrm = read_modrm(bytes, length)?;
+ let (opwidth, bank) = if instruction.prefixes.vex().w() {
+ (8, RegisterBank::Q)
+ } else {
+ (4, RegisterBank::D)
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank);
+ instruction.vex_reg.bank = bank;
+ let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.operands[2] = OperandSpec::RegVex;
+ instruction.operand_count = 3;
+ Ok(())
+ }
+ VEXOperandCode::G_E_Ib => {
+ let modrm = read_modrm(bytes, length)?;
+ let (opwidth, bank) = if instruction.prefixes.vex().w() {
+ (8, RegisterBank::Q)
+ } else {
+ (4, RegisterBank::D)
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank);
+ let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?;
+ instruction.operands[0] = OperandSpec::RegRRR;
+ instruction.operands[1] = mem_oper;
+ instruction.imm = read_imm_unsigned(bytes, 1, length)?;
+ instruction.operands[2] = OperandSpec::ImmI8;
+ instruction.operand_count = 3;
+ Ok(())
+ }
+ VEXOperandCode::BMI1_F3 => {
+ let modrm = read_modrm(bytes, length)?;
+ instruction.opcode = match (modrm >> 3) & 7 {
+ 1 => {
+ Opcode::BLSR
+ }
+ 2 => {
+ Opcode::BLSMSK
+ }
+ 3 => {
+ Opcode::BLSI
+ }
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ };
+ let (opwidth, bank) = if instruction.prefixes.vex().w() {
+ (8, RegisterBank::Q)
+ } else {
+ (4, RegisterBank::D)
+ };
+ instruction.modrm_rrr =
+ RegSpec::from_parts((modrm >> 3) & 7,instruction.prefixes.vex().x(), bank);
+ let mem_oper = read_E(bytes, instruction, modrm, opwidth, length)?;
+ instruction.operands[0] = OperandSpec::RegVex;
+ instruction.operands[1] = mem_oper;
+ instruction.operand_count = 2;
+ instruction.vex_reg.bank = bank;
+ Ok(())
+ }
VEXOperandCode::G_E_ymm_imm8 |
VEXOperandCode::G_V_E_xmm_xmm4 |
@@ -2270,15 +2356,92 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &
} else {
VEXOperandCode::G_V_E_xmm
}),
+ 0xF7 => (Opcode::SHLX, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_V
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else if let VEXOpcodePrefix::PrefixF2 = p {
+ match opc {
+ 0xF5 => (Opcode::PDEP, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E
+ }),
+ 0xF6 => (Opcode::MULX, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E
+ }),
+ 0xF7 => (Opcode::SHRX, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_V
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
+ } else if let VEXOpcodePrefix::PrefixF3 = p {
+ match opc {
+ 0xF5 => (Opcode::PEXT, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E
+ }),
+ 0xF7 => (Opcode::SARX, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_V
+ }),
_ => {
instruction.opcode = Opcode::Invalid;
return Err(DecodeError::InvalidOpcode);
}
}
} else {
- // the only VEX* 0f38 instructions have an implied 66 prefix.
- instruction.opcode = Opcode::Invalid;
- return Err(DecodeError::InvalidOpcode);
+ match opc {
+ 0xF2 => (Opcode::ANDN, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_V_E
+ }),
+ 0xF3 => (Opcode::Invalid, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::BMI1_F3
+ }),
+ 0xF5 => (Opcode::BZHI, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_V
+ }),
+ 0xF7 => (Opcode::BEXTR, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_V
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
}
}
VEXOpcodeMap::Map0F3A => {
@@ -2504,6 +2667,19 @@ fn read_vex_instruction<T: Iterator<Item=u8>>(opcode_map: VEXOpcodeMap, bytes: &
return Err(DecodeError::InvalidOpcode);
}
}
+ } else if let VEXOpcodePrefix::PrefixF2 = p {
+ match opc {
+ 0xF0 => (Opcode::RORX, if L {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ } else {
+ VEXOperandCode::G_E_Ib
+ }),
+ _ => {
+ instruction.opcode = Opcode::Invalid;
+ return Err(DecodeError::InvalidOpcode);
+ }
+ }
} else {
// the only VEX* 0f3a instructions have an implied 66 prefix.
instruction.opcode = Opcode::Invalid;