use crate::x86::x86_full_instr_info::{EncodingForm, InstrEncodingInfo, X86FullOpcode, X86FullInstrInfo};
use crate::x86::x86_instr_info::{OperandType, X86InstrDesc, X86InstrInfo, X86MemOperand, X86Operand, X86SchedInfo};
use crate::x86::x86_register_info::{X86RegisterInfo, X86_64_REG_COUNT};
pub const PREFIX_LOCK: u8 = 0xF0;
pub const PREFIX_REPNE: u8 = 0xF2;
pub const PREFIX_REPNZ: u8 = 0xF2;
pub const PREFIX_REP: u8 = 0xF3;
pub const PREFIX_REPZ: u8 = 0xF3;
pub const PREFIX_CS: u8 = 0x2E;
pub const PREFIX_SS: u8 = 0x36;
pub const PREFIX_DS: u8 = 0x3E;
pub const PREFIX_ES: u8 = 0x26;
pub const PREFIX_FS: u8 = 0x64;
pub const PREFIX_GS: u8 = 0x65;
pub const PREFIX_OPERAND_SIZE: u8 = 0x66;
pub const PREFIX_ADDRESS_SIZE: u8 = 0x67;
pub const ALL_LEGACY_PREFIXES: [u8; 12] = [
PREFIX_LOCK, PREFIX_REPNE, PREFIX_REP,
PREFIX_CS, PREFIX_SS, PREFIX_DS, PREFIX_ES, PREFIX_FS, PREFIX_GS,
PREFIX_OPERAND_SIZE, PREFIX_ADDRESS_SIZE, 0x00 ];
pub const REX_BASE: u8 = 0x40;
pub const REX_W_BIT: u8 = 0x08;
pub const REX_R_BIT: u8 = 0x04;
pub const REX_X_BIT: u8 = 0x02;
pub const REX_B_BIT: u8 = 0x01;
pub const REX_W: u8 = REX_BASE | REX_W_BIT; pub const REX_R: u8 = REX_BASE | REX_R_BIT; pub const REX_X: u8 = REX_BASE | REX_X_BIT; pub const REX_B: u8 = REX_BASE | REX_B_BIT; pub const REX_WR: u8 = REX_BASE | REX_W_BIT | REX_R_BIT; pub const REX_WB: u8 = REX_BASE | REX_W_BIT | REX_B_BIT; pub const REX_WRXB: u8 = REX_BASE | REX_W_BIT | REX_R_BIT | REX_X_BIT | REX_B_BIT;
pub const ALL_REX_COMBINATIONS: [(u8, &str, bool, bool, bool, bool); 16] = [
(0x40, "REX", false, false, false, false),
(0x41, "REX.B", false, false, false, true ),
(0x42, "REX.X", false, false, true, false),
(0x43, "REX.XB", false, false, true, true ),
(0x44, "REX.R", false, true, false, false),
(0x45, "REX.RB", false, true, false, true ),
(0x46, "REX.RX", false, true, true, false),
(0x47, "REX.RXB", false, true, true, true ),
(0x48, "REX.W", true, false, false, false),
(0x49, "REX.WB", true, false, false, true ),
(0x4A, "REX.WX", true, false, true, false),
(0x4B, "REX.WXB", true, false, true, true ),
(0x4C, "REX.WR", true, true, false, false),
(0x4D, "REX.WRB", true, true, false, true ),
(0x4E, "REX.WRX", true, true, true, false),
(0x4F, "REX.WRXB", true, true, true, true ),
];
pub const VEX_2BYTE: u8 = 0xC5;
pub const VEX_3BYTE: u8 = 0xC4;
pub const VEX_MAP_0F: u8 = 0x01;
pub const VEX_MAP_0F38: u8 = 0x02;
pub const VEX_MAP_0F3A: u8 = 0x03;
pub const VEX_PP_NONE: u8 = 0x00;
pub const VEX_PP_66: u8 = 0x01;
pub const VEX_PP_F3: u8 = 0x02;
pub const VEX_PP_F2: u8 = 0x03;
pub const VEX_MMMMM_0F: u8 = 0x01;
pub const VEX_MMMMM_0F38: u8 = 0x02;
pub const VEX_MMMMM_0F3A: u8 = 0x03;
pub const EVEX_MAGIC: u8 = 0x62;
pub const EVEX_MAP_0F: u8 = 0x01;
pub const EVEX_MAP_0F38: u8 = 0x02;
pub const EVEX_MAP_0F3A: u8 = 0x03;
pub const EVEX_MAP_5: u8 = 0x05;
pub const EVEX_MAP_6: u8 = 0x06;
pub const EVEX_MAP_7: u8 = 0x07;
pub const EVEX_VL128: u8 = 0x00;
pub const EVEX_VL256: u8 = 0x01;
pub const EVEX_VL512: u8 = 0x02;
pub const XOP_MAGIC: u8 = 0x8F;
pub const XOP_MAP_8: u8 = 0x08;
pub const XOP_MAP_9: u8 = 0x09;
pub const XOP_MAP_A: u8 = 0x0A;
pub const ESCAPE_0F: u8 = 0x0F;
pub const ESCAPE_0F38: u8 = 0x38;
pub const ESCAPE_0F3A: u8 = 0x3A;
pub const ESCAPE_3DNOW: u8 = 0x0F;
pub const ALU_ADD_BASE: u8 = 0x00;
pub const ALU_OR_BASE: u8 = 0x08;
pub const ALU_ADC_BASE: u8 = 0x10;
pub const ALU_SBB_BASE: u8 = 0x18;
pub const ALU_AND_BASE: u8 = 0x20;
pub const ALU_SUB_BASE: u8 = 0x28;
pub const ALU_XOR_BASE: u8 = 0x30;
pub const ALU_CMP_BASE: u8 = 0x38;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum OpcodeMap {
Primary,
TwoByte,
ThreeByte38,
ThreeByte3A,
VexMap1, VexMap2, VexMap3, EvexMap1, EvexMap2, EvexMap3, EvexMap5, EvexMap6, EvexMap7, XopMap8, XopMap9, XopMapA, ThreeDNow,
}
impl OpcodeMap {
pub const fn num_escape_bytes(&self) -> usize {
match self {
OpcodeMap::Primary => 0,
OpcodeMap::TwoByte => 1,
OpcodeMap::ThreeByte38 | OpcodeMap::ThreeByte3A | OpcodeMap::ThreeDNow => 2,
_ => 0,
}
}
pub fn escape_bytes(&self) -> &[u8] {
match self {
OpcodeMap::Primary => &[],
OpcodeMap::TwoByte => &[ESCAPE_0F],
OpcodeMap::ThreeByte38 => &[ESCAPE_0F, ESCAPE_0F38],
OpcodeMap::ThreeByte3A => &[ESCAPE_0F, ESCAPE_0F3A],
OpcodeMap::ThreeDNow => &[ESCAPE_0F, ESCAPE_0F],
OpcodeMap::VexMap1 | OpcodeMap::EvexMap1 => &[],
OpcodeMap::VexMap2 | OpcodeMap::EvexMap2 => &[],
OpcodeMap::VexMap3 | OpcodeMap::EvexMap3 => &[],
_ => &[],
}
}
pub const fn vex_mmmmm(&self) -> u8 {
match self {
OpcodeMap::VexMap1 => VEX_MMMMM_0F,
OpcodeMap::VexMap2 => VEX_MMMMM_0F38,
OpcodeMap::VexMap3 => VEX_MMMMM_0F3A,
_ => 0,
}
}
pub const fn evex_mm(&self) -> u8 {
match self {
OpcodeMap::EvexMap1 => 1,
OpcodeMap::EvexMap2 => 2,
OpcodeMap::EvexMap3 => 3,
OpcodeMap::EvexMap5 => 5,
OpcodeMap::EvexMap6 => 6,
OpcodeMap::EvexMap7 => 7,
_ => 0,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum MandatoryPrefix {
None,
P66,
PF2,
PF3,
}
impl MandatoryPrefix {
pub const fn byte(&self) -> Option<u8> {
match self { Self::None => None, Self::P66 => Some(0x66), Self::PF2 => Some(0xF2), Self::PF3 => Some(0xF3) }
}
pub const fn vex_pp_bits(&self) -> u8 {
match self { Self::None => VEX_PP_NONE, Self::P66 => VEX_PP_66, Self::PF3 => VEX_PP_F3, Self::PF2 => VEX_PP_F2 }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ModRM {
pub mod_bits: u8,
pub reg_bits: u8,
pub rm_bits: u8,
}
impl ModRM {
pub const fn new(mod_bits: u8, reg_bits: u8, rm_bits: u8) -> Self {
Self { mod_bits: mod_bits & 0x03, reg_bits: reg_bits & 0x07, rm_bits: rm_bits & 0x07 }
}
pub const fn encode(&self) -> u8 {
(self.mod_bits << 6) | (self.reg_bits << 3) | self.rm_bits
}
pub const fn mod_direct(reg: u8, rm: u8) -> u8 { (0x03 << 6) | ((reg & 0x07) << 3) | (rm & 0x07) }
pub const fn mod_mem_no_disp(reg: u8, rm: u8) -> u8 { (0x00 << 6) | ((reg & 0x07) << 3) | (rm & 0x07) }
pub const fn mod_mem_disp8(reg: u8, rm: u8) -> u8 { (0x01 << 6) | ((reg & 0x07) << 3) | (rm & 0x07) }
pub const fn mod_mem_disp32(reg: u8, rm: u8) -> u8 { (0x02 << 6) | ((reg & 0x07) << 3) | (rm & 0x07) }
pub const fn mod_rip_rel(reg: u8) -> u8 { (0x00 << 6) | ((reg & 0x07) << 3) | 0x05 }
pub const fn mod_field(&self) -> u8 { self.mod_bits }
pub const fn reg_field(&self) -> u8 { self.reg_bits }
pub const fn rm_field(&self) -> u8 { self.rm_bits }
}
#[derive(Debug, Clone)]
pub struct X86ModRMEncoding;
impl X86ModRMEncoding {
pub const ALL_MODRM_VALUES: [(u8, u8, u8, &'static str); 256] = {
let mut table = [(0u8, 0u8, 0u8, ""); 256];
let mut byte = 0u16;
while byte < 256 {
let mod_bits = (byte >> 6) as u8;
let reg_bits = ((byte >> 3) & 0x07) as u8;
let rm_bits = (byte & 0x07) as u8;
let desc = match (mod_bits, rm_bits) {
(0x00, 0x05) => "[rip+disp32]",
(0x00, 0x04) => "[--][--]+[SIB]+disp32",
(0x00, _) => "[reg]",
(0x01, 0x04) => "[--][--]+[SIB]+disp8",
(0x01, _) => "[reg+disp8]",
(0x02, 0x04) => "[--][--]+[SIB]+disp32",
(0x02, _) => "[reg+disp32]",
(0x03, _) => "register",
_ => "?",
};
table[byte as usize] = (mod_bits, reg_bits, rm_bits, desc);
byte += 1;
}
table
};
pub const fn mod_rm(mod_bits: u8, reg_bits: u8, rm_bits: u8) -> u8 {
((mod_bits & 0x03) << 6) | ((reg_bits & 0x07) << 3) | (rm_bits & 0x07)
}
pub const fn mod_field(byte: u8) -> u8 { (byte >> 6) & 0x03 }
pub const fn reg_field(byte: u8) -> u8 { (byte >> 3) & 0x07 }
pub const fn rm_field(byte: u8) -> u8 { byte & 0x07 }
pub const fn is_memory_reference(byte: u8) -> bool { Self::mod_field(byte) != 0x03 }
pub const fn is_register_reference(byte: u8) -> bool { Self::mod_field(byte) == 0x03 }
pub const fn needs_displacement(byte: u8) -> bool {
let m = Self::mod_field(byte);
m == 0x01 || m == 0x02 || (m == 0x00 && Self::rm_field(byte) == 0x05)
}
pub const fn disp_size(byte: u8) -> u8 {
match Self::mod_field(byte) {
0x00 => if Self::rm_field(byte) == 0x05 { 4 } else { 0 },
0x01 => 1,
0x02 => 4,
_ => 0,
}
}
pub const fn needs_sib(byte: u8) -> bool {
Self::mod_field(byte) != 0x03 && Self::rm_field(byte) == 0x04
}
pub const fn rm_register_name_64(rm: u8) -> &'static str {
match rm { 0=>"RAX",1=>"RCX",2=>"RDX",3=>"RBX",4=>"RSP",5=>"RBP",6=>"RSI",7=>"RDI", _=>"??" }
}
pub const fn rm_register_name_32(rm: u8) -> &'static str {
match rm { 0=>"EAX",1=>"ECX",2=>"EDX",3=>"EBX",4=>"ESP",5=>"EBP",6=>"ESI",7=>"EDI", _=>"??" }
}
pub const fn rm_register_name_16(rm: u8) -> &'static str {
match rm { 0=>"AX",1=>"CX",2=>"DX",3=>"BX",4=>"SP",5=>"BP",6=>"SI",7=>"DI", _=>"??" }
}
pub const fn rm_register_name_8(rm: u8, rex_present: bool) -> &'static str {
match (rm, rex_present) {
(0,_)=>"AL",(1,_)=>"CL",(2,_)=>"DL",(3,_)=>"BL",
(4,false)=>"AH",(4,true)=>"SPL",(5,false)=>"CH",(5,true)=>"BPL",
(6,false)=>"DH",(6,true)=>"SIL",(7,false)=>"BH",(7,true)=>"DIL", _=>"??"
}
}
pub const fn reg_register_name_64(reg: u8) -> &'static str {
match reg { 0=>"RAX",1=>"RCX",2=>"RDX",3=>"RBX",4=>"RSP",5=>"RBP",6=>"RSI",7=>"RDI", _=>"??" }
}
pub const fn reg_register_name_32(reg: u8) -> &'static str {
match reg { 0=>"EAX",1=>"ECX",2=>"EDX",3=>"EBX",4=>"ESP",5=>"EBP",6=>"ESI",7=>"EDI", _=>"??" }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SIB {
pub scale_bits: u8,
pub index_bits: u8,
pub base_bits: u8,
}
impl SIB {
pub const fn new(scale: u8, index: u8, base: u8) -> Self {
Self { scale_bits: scale & 0x03, index_bits: index & 0x07, base_bits: base & 0x07 }
}
pub const fn encode(&self) -> u8 {
(self.scale_bits << 6) | (self.index_bits << 3) | self.base_bits
}
pub const fn scale_1(index: u8, base: u8) -> Self { Self::new(0x00, index, base) }
pub const fn scale_2(index: u8, base: u8) -> Self { Self::new(0x01, index, base) }
pub const fn scale_4(index: u8, base: u8) -> Self { Self::new(0x02, index, base) }
pub const fn scale_8(index: u8, base: u8) -> Self { Self::new(0x03, index, base) }
pub const NO_INDEX: u8 = 0x04;
pub const RBP_BASE: u8 = 0x05;
pub const R13_BASE: u8 = 0x05;
pub const fn with_no_index(base: u8) -> Self { Self::new(0x00, Self::NO_INDEX, base) }
pub const fn rip_relative() -> Self { Self::new(0x00, Self::NO_INDEX, Self::RBP_BASE) }
pub const fn scale_value(&self) -> u8 {
match self.scale_bits { 0x00=>1, 0x01=>2, 0x02=>4, 0x03=>8, _=>1 }
}
}
#[derive(Debug, Clone)]
pub struct X86SIBEncoding;
impl X86SIBEncoding {
pub const ALL_SIB_VALUES: [(u8, &'static str, &'static str, bool); 256] = {
let mut table = [(0u8, "", "", false); 256];
let mut byte = 0u16;
let idx_names: [&str; 8] = ["EAX","ECX","EDX","EBX","none","EBP","ESI","EDI"];
let base_names: [&str; 8] = ["EAX","ECX","EDX","EBX","ESP","EBP","ESI","EDI"];
while byte < 256 {
let scale = (byte >> 6) as u8;
let idx = ((byte >> 3) & 0x07) as u8;
let base = (byte & 0x07) as u8;
let scale_val: u8 = match scale { 0=>1,1=>2,2=>4,3=>8, _=>1 };
let is_abs = idx == 4 && base == 5;
table[byte as usize] = (scale_val, idx_names[idx as usize], base_names[base as usize], is_abs);
byte += 1;
}
table
};
pub const fn sib(scale: u8, index: u8, base: u8) -> u8 {
((scale & 0x03) << 6) | ((index & 0x07) << 3) | (base & 0x07)
}
pub const fn scale_field(byte: u8) -> u8 { (byte >> 6) & 0x03 }
pub const fn index_field(byte: u8) -> u8 { (byte >> 3) & 0x07 }
pub const fn base_field(byte: u8) -> u8 { byte & 0x07 }
pub const NO_INDEX: u8 = 0x04;
pub const RBP_BASE: u8 = 0x05;
pub const R13_BASE: u8 = 0x05;
pub const fn scale_value(scale_bits: u8) -> u8 {
match scale_bits { 0x00=>1,0x01=>2,0x02=>4,0x03=>8, _=>1 }
}
pub const fn has_index(byte: u8) -> bool { Self::index_field(byte) != Self::NO_INDEX }
pub const fn is_absolute_disp32(byte: u8) -> bool {
Self::index_field(byte) == Self::NO_INDEX && Self::base_field(byte) == Self::RBP_BASE
}
pub const fn is_rip_relative(modrm: u8, sib: u8) -> bool {
X86ModRMEncoding::mod_field(modrm) == 0x00
&& X86ModRMEncoding::rm_field(modrm) == 0x04
&& Self::base_field(sib) == Self::RBP_BASE
}
pub const fn index_register_name_64(index: u8) -> &'static str {
match index {
0=>"RAX",1=>"RCX",2=>"RDX",3=>"RBX",4=>"(none)",5=>"RBP",6=>"RSI",7=>"RDI",
8=>"R8",9=>"R9",10=>"R10",11=>"R11",12=>"R12",13=>"R13",14=>"R14",15=>"R15",
_=>"??",
}
}
pub const fn base_register_name_64(base: u8) -> &'static str {
match base {
0=>"RAX",1=>"RCX",2=>"RDX",3=>"RBX",4=>"RSP",5=>"RBP",6=>"RSI",7=>"RDI",
8=>"R8",9=>"R9",10=>"R10",11=>"R11",12=>"R12",13=>"R13",14=>"R14",15=>"R15",
_=>"??",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct PrefixBytes {
pub bytes: Vec<u8>,
}
impl PrefixBytes {
pub fn new() -> Self { Self::default() }
pub fn with_capacity(n: usize) -> Self { Self { bytes: Vec::with_capacity(n) } }
pub fn push(&mut self, b: u8) { self.bytes.push(b); }
pub fn extend(&mut self, bs: &[u8]) { self.bytes.extend_from_slice(bs); }
pub fn len(&self) -> usize { self.bytes.len() }
pub fn is_empty(&self) -> bool { self.bytes.is_empty() }
pub fn as_slice(&self) -> &[u8] { &self.bytes }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PrefixedOpcode {
pub prefixes: [Option<u8>; 4],
pub prefix_count: u8,
}
impl Default for PrefixedOpcode {
fn default() -> Self { Self { prefixes: [None; 4], prefix_count: 0 } }
}
impl PrefixedOpcode {
pub fn new() -> Self { Self::default() }
pub fn push(&mut self, b: u8) {
if self.prefix_count < 4 { self.prefixes[self.prefix_count as usize] = Some(b); self.prefix_count += 1; }
}
pub fn to_bytes(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(self.prefix_count as usize);
for i in 0..self.prefix_count as usize {
if let Some(b) = self.prefixes[i] { out.push(b); }
}
out
}
}
#[derive(Debug, Clone)]
pub struct X86PrefixEncoding {
pub use_lock: bool,
pub use_repne: bool,
pub use_rep: bool,
pub use_segment_override: Option<u8>,
pub use_operand_size_override: bool,
pub use_address_size_override: bool,
pub rex: Option<u8>,
pub mandatory_prefix: MandatoryPrefix,
pub vex_2byte: bool,
pub vex2_inverted_r: bool,
pub vex2_vvvv: u8,
pub vex2_l: bool,
pub vex2_pp: u8,
pub vex_3byte: bool,
pub vex3_inverted_r: bool,
pub vex3_inverted_x: bool,
pub vex3_inverted_b: bool,
pub vex3_mmmmm: u8,
pub vex3_w: bool,
pub vex3_vvvv: u8,
pub vex3_l: bool,
pub vex3_pp: u8,
pub is_evex: bool,
pub evex_r_prime: bool,
pub evex_x_prime: bool,
pub evex_b_prime: bool,
pub evex_r: bool,
pub evex_x: bool,
pub evex_b: bool,
pub evex_v_prime: bool,
pub evex_w: bool,
pub evex_z: bool,
pub evex_aaa: u8,
pub evex_l_prime: bool,
pub evex_bcst: bool,
pub evex_pp: u8,
pub evex_mm: u8,
pub is_xop: bool,
pub xop_inverted_r: bool,
pub xop_inverted_x: bool,
pub xop_inverted_b: bool,
pub xop_mmmmm: u8,
pub xop_w: bool,
pub xop_vvvv: u8,
pub xop_l: bool,
pub xop_pp: u8,
}
impl Default for X86PrefixEncoding {
fn default() -> Self { Self::new() }
}
impl X86PrefixEncoding {
pub fn new() -> Self {
Self {
use_lock: false, use_repne: false, use_rep: false,
use_segment_override: None,
use_operand_size_override: false, use_address_size_override: false,
rex: None, mandatory_prefix: MandatoryPrefix::None,
vex_2byte: false, vex2_inverted_r: false, vex2_vvvv: 0, vex2_l: false, vex2_pp: 0,
vex_3byte: false,
vex3_inverted_r: false, vex3_inverted_x: false, vex3_inverted_b: false,
vex3_mmmmm: 0x01, vex3_w: false, vex3_vvvv: 0, vex3_l: false, vex3_pp: 0,
is_evex: false,
evex_r_prime: false, evex_x_prime: false, evex_b_prime: false,
evex_r: false, evex_x: false, evex_b: false,
evex_v_prime: false, evex_w: false,
evex_z: false, evex_aaa: 0,
evex_l_prime: false, evex_bcst: false,
evex_pp: 0, evex_mm: 1,
is_xop: false,
xop_inverted_r: false, xop_inverted_x: false, xop_inverted_b: false,
xop_mmmmm: 8, xop_w: false, xop_vvvv: 0, xop_l: false, xop_pp: 0,
}
}
pub fn with_lock(mut self) -> Self { self.use_lock = true; self }
pub fn with_repne(mut self) -> Self { self.use_repne = true; self }
pub fn with_rep(mut self) -> Self { self.use_rep = true; self }
pub fn with_segment(mut self, seg: u8) -> Self { self.use_segment_override = Some(seg); self }
pub fn with_operand_size(mut self) -> Self { self.use_operand_size_override = true; self }
pub fn with_address_size(mut self) -> Self { self.use_address_size_override = true; self }
pub fn with_rex(mut self, w: bool, r: bool, x: bool, b: bool) -> Self {
let mut rex = REX_BASE;
if w { rex |= REX_W_BIT; } if r { rex |= REX_R_BIT; }
if x { rex |= REX_X_BIT; } if b { rex |= REX_B_BIT; }
self.rex = if rex != REX_BASE { Some(rex) } else { None };
self
}
pub fn with_rex_w(mut self) -> Self { self.with_rex(true, false, false, false) }
pub fn with_rex_r(mut self) -> Self { self.with_rex(false, true, false, false) }
pub fn with_rex_b(mut self) -> Self { self.with_rex(false, false, false, true) }
pub fn with_prefix66(mut self) -> Self { self.mandatory_prefix = MandatoryPrefix::P66; self }
pub fn with_prefix_f2(mut self) -> Self { self.mandatory_prefix = MandatoryPrefix::PF2; self }
pub fn with_prefix_f3(mut self) -> Self { self.mandatory_prefix = MandatoryPrefix::PF3; self }
pub fn with_vex2(mut self, inv_r: bool, vvvv: u8, l: bool, pp: u8) -> Self {
self.vex_2byte = true; self.vex2_inverted_r = inv_r; self.vex2_vvvv = vvvv & 0x0F;
self.vex2_l = l; self.vex2_pp = pp & 0x03; self
}
#[allow(clippy::too_many_arguments)]
pub fn with_vex3(mut self, inv_r: bool, inv_x: bool, inv_b: bool, mmmmm: u8, w: bool, vvvv: u8, l: bool, pp: u8) -> Self {
self.vex_3byte = true; self.vex3_inverted_r = inv_r; self.vex3_inverted_x = inv_x; self.vex3_inverted_b = inv_b;
self.vex3_mmmmm = mmmmm & 0x1F; self.vex3_w = w; self.vex3_vvvv = vvvv & 0x0F; self.vex3_l = l; self.vex3_pp = pp & 0x03; self
}
#[allow(clippy::too_many_arguments)]
pub fn with_evex(mut self,
rp: bool, xp: bool, bp: bool, r: bool, x: bool, b: bool,
vp: bool, w: bool, mm: u8, pp: u8,
z: bool, aaa: u8, lp: bool, bcst: bool) -> Self
{
self.is_evex = true;
self.evex_r_prime = rp; self.evex_x_prime = xp; self.evex_b_prime = bp;
self.evex_r = r; self.evex_x = x; self.evex_b = b;
self.evex_v_prime = vp; self.evex_w = w;
self.evex_mm = mm & 0x03; self.evex_pp = pp & 0x03;
self.evex_z = z; self.evex_aaa = aaa & 0x07;
self.evex_l_prime = lp; self.evex_bcst = bcst; self
}
pub fn with_xop(mut self, inv_r: bool, inv_x: bool, inv_b: bool, mmmmm: u8, w: bool, vvvv: u8, l: bool, pp: u8) -> Self {
self.is_xop = true;
self.xop_inverted_r = inv_r; self.xop_inverted_x = inv_x; self.xop_inverted_b = inv_b;
self.xop_mmmmm = mmmmm & 0x1F; self.xop_w = w;
self.xop_vvvv = vvvv & 0x0F; self.xop_l = l; self.xop_pp = pp & 0x03; self
}
pub fn encode_bytes(&self) -> Vec<u8> {
let mut out = Vec::with_capacity(8);
if self.use_lock { out.push(PREFIX_LOCK); }
if self.use_repne { out.push(PREFIX_REPNE); }
if self.use_rep { out.push(PREFIX_REP); }
if let Some(seg) = self.use_segment_override { out.push(seg); }
if self.use_operand_size_override { out.push(PREFIX_OPERAND_SIZE); }
if self.use_address_size_override { out.push(PREFIX_ADDRESS_SIZE); }
if let Some(mp) = self.mandatory_prefix.byte() { out.push(mp); }
if let Some(rex) = self.rex { out.push(rex); }
if self.vex_2byte {
out.push(VEX_2BYTE);
let inv_r = if self.vex2_inverted_r { 0x00 } else { 0x80 };
let vvvv = (self.vex2_vvvv ^ 0x0F) << 3;
let l = if self.vex2_l { 0x04 } else { 0x00 };
out.push(inv_r | vvvv | l | self.vex2_pp);
}
if self.vex_3byte {
out.push(VEX_3BYTE);
let inv_r = if self.vex3_inverted_r { 0x00 } else { 0x80 };
let inv_x = if self.vex3_inverted_x { 0x00 } else { 0x40 };
let inv_b = if self.vex3_inverted_b { 0x00 } else { 0x20 };
out.push(inv_r | inv_x | inv_b | (self.vex3_mmmmm & 0x1F));
let w = if self.vex3_w { 0x80 } else { 0x00 };
let vvvv = (self.vex3_vvvv ^ 0x0F) << 3;
let l = if self.vex3_l { 0x04 } else { 0x00 };
out.push(w | vvvv | l | self.vex3_pp);
}
if self.is_evex {
out.push(EVEX_MAGIC);
let rp = if self.evex_r_prime { 0x00 } else { 0x80 };
let xp = if self.evex_x_prime { 0x00 } else { 0x40 };
let bp = if self.evex_b_prime { 0x00 } else { 0x20 };
let r = if self.evex_r { 0x00 } else { 0x10 };
out.push(rp | xp | bp | r | (self.evex_mm & 0x03));
let vp = if self.evex_v_prime { 0x00 } else { 0x08 };
let w = if self.evex_w { 0x80 } else { 0x00 };
let vvvv= (self.evex_vvvv ^ 0x0F) << 3;
out.push(w | vvvv | vp | (self.evex_pp & 0x03));
let z = if self.evex_z { 0x80 } else { 0x00 };
let lp = if self.evex_l_prime { 0x20 } else { 0x00 };
let bcst= if self.evex_bcst { 0x10 } else { 0x00 };
out.push(z | lp | bcst | (self.evex_aaa & 0x07));
}
if self.is_xop {
out.push(XOP_MAGIC);
let inv_r = if self.xop_inverted_r { 0x00 } else { 0x80 };
let inv_x = if self.xop_inverted_x { 0x00 } else { 0x40 };
let inv_b = if self.xop_inverted_b { 0x00 } else { 0x20 };
out.push(inv_r | inv_x | inv_b | (self.xop_mmmmm & 0x1F));
let w = if self.xop_w { 0x80 } else { 0x00 };
let vvvv = (self.xop_vvvv ^ 0x0F) << 3;
let l = if self.xop_l { 0x04 } else { 0x00 };
out.push(w | vvvv | l | (self.xop_pp & 0x03));
}
out
}
pub fn prefix_byte_count(&self) -> usize { self.encode_bytes().len() }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct X86InstructionEncoding {
pub mnemonic: &'static str,
pub intel_mnemonic: &'static str,
pub opcode_bytes: &'static [u8],
pub opcode_map: OpcodeMap,
pub mandatory_prefix: MandatoryPrefix,
pub encoding_form: EncodingForm,
pub has_modrm: bool,
pub modrm_extension: Option<u8>,
pub rex_w: bool,
pub operand_types: &'static [OperandType],
pub has_imm8: bool,
pub has_imm16: bool,
pub has_imm32: bool,
pub has_imm64: bool,
pub plus_opcode_reg: Option<u8>,
pub is_branch: bool,
pub is_call: bool,
pub is_return: bool,
pub is_terminator: bool,
pub has_side_effects: bool,
pub may_load: bool,
pub may_store: bool,
pub is_commutative: bool,
}
#[allow(clippy::too_many_arguments)]
impl X86InstructionEncoding {
pub const fn new(
mnemonic: &'static str, intel_mnemonic: &'static str,
opcode_bytes: &'static [u8], opcode_map: OpcodeMap,
mandatory_prefix: MandatoryPrefix, encoding_form: EncodingForm,
has_modrm: bool, modrm_extension: Option<u8>, rex_w: bool,
operand_types: &'static [OperandType],
has_imm8: bool, has_imm16: bool, has_imm32: bool, has_imm64: bool,
plus_opcode_reg: Option<u8>,
is_branch: bool, is_call: bool, is_return: bool, is_terminator: bool,
has_side_effects: bool, may_load: bool, may_store: bool, is_commutative: bool,
) -> Self {
Self { mnemonic, intel_mnemonic, opcode_bytes, opcode_map, mandatory_prefix, encoding_form,
has_modrm, modrm_extension, rex_w, operand_types,
has_imm8, has_imm16, has_imm32, has_imm64, plus_opcode_reg,
is_branch, is_call, is_return, is_terminator,
has_side_effects, may_load, may_store, is_commutative }
}
pub const fn opcode_byte(&self) -> u8 { self.opcode_bytes[0] }
pub fn estimated_length(&self, has_sib: bool, disp_size: u8) -> usize {
let mut len = match self.encoding_form {
EncodingForm::Legacy | EncodingForm::LegacyREX => {
(if self.rex_w { 1 } else { 0 }) + self.opcode_bytes.len()
}
EncodingForm::VEX | EncodingForm::VEX3Byte => 3 + 1,
EncodingForm::EVEX => 4 + 1,
EncodingForm::XOP => 3 + 1,
EncodingForm::None => self.opcode_bytes.len(),
};
if self.has_modrm { len += 1; }
if has_sib { len += 1; }
len += disp_size as usize;
if self.has_imm8 { len += 1; }
if self.has_imm16 { len += 2; }
if self.has_imm32 { len += 4; }
if self.has_imm64 { len += 8; }
len
}
}
const NO_OPS: &[OperandType] = &[];
#[derive(Debug, Clone)]
pub struct X86OpcodeMap {
pub primary: Vec<Option<X86InstructionEncoding>>,
pub two_byte: Vec<Option<X86InstructionEncoding>>,
pub three_byte_38: Vec<Option<X86InstructionEncoding>>,
pub three_byte_3a: Vec<Option<X86InstructionEncoding>>,
pub vex_map1: Vec<Option<X86InstructionEncoding>>,
pub vex_map2: Vec<Option<X86InstructionEncoding>>,
pub vex_map3: Vec<Option<X86InstructionEncoding>>,
pub evex_map1: Vec<Option<X86InstructionEncoding>>,
pub evex_map2: Vec<Option<X86InstructionEncoding>>,
pub evex_map3: Vec<Option<X86InstructionEncoding>>,
pub xop_map8: Vec<Option<X86InstructionEncoding>>,
pub xop_map9: Vec<Option<X86InstructionEncoding>>,
pub xop_map_a: Vec<Option<X86InstructionEncoding>>,
pub three_dnow: Vec<Option<X86InstructionEncoding>>,
pub by_mnemonic: std::collections::HashMap<String, Vec<usize>>,
}
impl Default for X86OpcodeMap { fn default() -> Self { Self::new() } }
impl X86OpcodeMap {
pub fn new() -> Self {
Self {
primary: vec![None; 256], two_byte: vec![None; 256],
three_byte_38: vec![None; 256], three_byte_3a: vec![None; 256],
vex_map1: vec![None; 256], vex_map2: vec![None; 256], vex_map3: vec![None; 256],
evex_map1: vec![None; 256], evex_map2: vec![None; 256], evex_map3: vec![None; 256],
xop_map8: vec![None; 256], xop_map9: vec![None; 256], xop_map_a: vec![None; 256],
three_dnow: vec![None; 256],
by_mnemonic: std::collections::HashMap::new(),
}
}
fn ins(&mut self, map_id: u8, idx: u8, enc: X86InstructionEncoding) {
let key = ((map_id as usize) << 8) | idx as usize;
self.by_mnemonic.entry(enc.mnemonic.to_string()).or_default().push(key);
match map_id {
0 => self.primary[idx as usize] = Some(enc),
1 => self.two_byte[idx as usize] = Some(enc),
2 => self.three_byte_38[idx as usize] = Some(enc),
3 => self.three_byte_3a[idx as usize] = Some(enc),
4 => self.vex_map1[idx as usize] = Some(enc),
5 => self.vex_map2[idx as usize] = Some(enc),
6 => self.vex_map3[idx as usize] = Some(enc),
7 => self.evex_map1[idx as usize] = Some(enc),
8 => self.evex_map2[idx as usize] = Some(enc),
9 => self.evex_map3[idx as usize] = Some(enc),
10 => self.xop_map8[idx as usize] = Some(enc),
11 => self.xop_map9[idx as usize] = Some(enc),
12 => self.xop_map_a[idx as usize] = Some(enc),
13 => self.three_dnow[idx as usize] = Some(enc),
_ => {},
}
}
fn ins_prim(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(0, idx, enc); }
fn ins_two(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(1, idx, enc); }
fn ins_38(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(2, idx, enc); }
fn ins_3a(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(3, idx, enc); }
fn ins_v1(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(4, idx, enc); }
fn ins_v2(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(5, idx, enc); }
fn ins_v3(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(6, idx, enc); }
fn ins_e1(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(7, idx, enc); }
fn ins_e2(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(8, idx, enc); }
fn ins_e3(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(9, idx, enc); }
fn ins_x8(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(10, idx, enc); }
fn ins_x9(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(11, idx, enc); }
fn ins_xa(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(12, idx, enc); }
fn ins_dn(&mut self, idx: u8, enc: X86InstructionEncoding) { self.ins(13, idx, enc); }
fn lookup(map: &[Option<X86InstructionEncoding>], op: u8) -> Option<&X86InstructionEncoding> {
map.get(op as usize).and_then(|e| e.as_ref())
}
pub fn lookup_primary(&self, op: u8) -> Option<&X86InstructionEncoding> { Self::lookup(&self.primary, op) }
pub fn lookup_two_byte(&self, op: u8) -> Option<&X86InstructionEncoding> { Self::lookup(&self.two_byte, op) }
pub fn lookup_0f38(&self, op: u8) -> Option<&X86InstructionEncoding> { Self::lookup(&self.three_byte_38, op) }
pub fn lookup_0f3a(&self, op: u8) -> Option<&X86InstructionEncoding> { Self::lookup(&self.three_byte_3a, op) }
pub fn lookup_by_mnemonic(&self, mnemonic: &str) -> Vec<&X86InstructionEncoding> {
let mut result = Vec::new();
if let Some(indices) = self.by_mnemonic.get(mnemonic) {
for &idx in indices {
let map_id = (idx >> 8) as u8;
let op = (idx & 0xFF) as u8;
let entry = match map_id {
0=>Self::lookup(&self.primary,op), 1=>Self::lookup(&self.two_byte,op),
2=>Self::lookup(&self.three_byte_38,op), 3=>Self::lookup(&self.three_byte_3a,op),
4=>Self::lookup(&self.vex_map1,op), 5=>Self::lookup(&self.vex_map2,op),
6=>Self::lookup(&self.vex_map3,op), 7=>Self::lookup(&self.evex_map1,op),
8=>Self::lookup(&self.evex_map2,op), 9=>Self::lookup(&self.evex_map3,op),
10=>Self::lookup(&self.xop_map8,op),11=>Self::lookup(&self.xop_map9,op),
12=>Self::lookup(&self.xop_map_a,op),13=>Self::lookup(&self.three_dnow,op),
_=>None,
};
if let Some(e) = entry { result.push(e); }
}
}
result
}
pub fn total_encodings(&self) -> usize {
let c = |v: &[Option<X86InstructionEncoding>]| v.iter().filter(|e| e.is_some()).count();
c(&self.primary)+c(&self.two_byte)+c(&self.three_byte_38)+c(&self.three_byte_3a)
+c(&self.vex_map1)+c(&self.vex_map2)+c(&self.vex_map3)
+c(&self.evex_map1)+c(&self.evex_map2)+c(&self.evex_map3)
+c(&self.xop_map8)+c(&self.xop_map9)+c(&self.xop_map_a)+c(&self.three_dnow)
}
}
macro_rules! e {
($mn:expr,$im:expr,$op:expr,$ef:expr) => {
X86InstructionEncoding::new($mn,$im,&[$op],OpcodeMap::Primary,MandatoryPrefix::None,$ef,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,false,false,false,false)
};
($mn:expr,$im:expr,$op:expr,$ef:expr,$ops:expr) => {
X86InstructionEncoding::new($mn,$im,&[$op],OpcodeMap::Primary,MandatoryPrefix::None,$ef,true,None,false,$ops,false,false,false,false,None,false,false,false,false,false,false,false,false)
};
($mn:expr,$im:expr,$op:expr,$ef:expr,$ops:expr,imm8) => {
X86InstructionEncoding::new($mn,$im,&[$op],OpcodeMap::Primary,MandatoryPrefix::None,$ef,true,None,false,$ops,true,false,false,false,None,false,false,false,false,false,false,false,false)
};
($mn:expr,$im:expr,$op:expr,$ef:expr,$ops:expr,+$ext:expr) => {
X86InstructionEncoding::new($mn,$im,&[$op],OpcodeMap::Primary,MandatoryPrefix::None,$ef,true,None,false,$ops,false,false,false,false,Some($ext),false,false,false,false,false,false,false,false)
};
}
fn build_primary_opcode_map(map: &mut X86OpcodeMap) {
use OperandType::*;
use EncodingForm::*;
let alu_bases = [(0x00,"ADD","add"),(0x08,"OR","or"),(0x10,"ADC","adc"),(0x18,"SBB","sbb"),
(0x20,"AND","and"),(0x28,"SUB","sub"),(0x30,"XOR","xor"),(0x38,"CMP","cmp")];
for &(base, mn, im) in &alu_bases {
for i in 0..8u8 {
map.ins_prim(base+i, X86InstructionEncoding::new(mn,im,&[base+i],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,i==7,true,true,mn!="CMP"));
}
}
for i in 0..16u8 {
map.ins_prim(0x40+i, e!("REX_PREFIX","rex",0x40+i,Legacy));
}
for i in 0..8u8 {
map.ins_prim(0x50+i, X86InstructionEncoding::new("PUSH","push",&[0x50+i],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,&[Reg64],false,false,false,false,Some(i),false,false,false,false,false,false,true,false));
map.ins_prim(0x58+i, X86InstructionEncoding::new("POP","pop",&[0x58+i],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,&[Reg64],false,false,false,false,Some(i),false,false,false,false,false,true,false,false));
}
map.ins_prim(0x60, e!("PUSHA","pusha",0x60,Legacy));
map.ins_prim(0x61, e!("POPA","popa",0x61,Legacy));
map.ins_prim(0x63, X86InstructionEncoding::new("MOVSXD","movsxd",&[0x63],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,true,None,true,&[Reg64,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0x68, X86InstructionEncoding::new("PUSH","push",&[0x68],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm32],false,false,true,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0x69, X86InstructionEncoding::new("IMUL","imul",&[0x69],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32,Imm32],false,false,true,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0x6A, X86InstructionEncoding::new("PUSH","push",&[0x6A],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm8],true,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0x6B, X86InstructionEncoding::new("IMUL","imul",&[0x6B],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
let jcc = [("JO","jo"),("JNO","jno"),("JB","jb"),("JAE","jae"),("JE","je"),("JNE","jne"),
("JBE","jbe"),("JA","ja"),("JS","js"),("JNS","jns"),("JP","jp"),("JNP","jnp"),
("JL","jl"),("JGE","jge"),("JLE","jle"),("JG","jg")];
for i in 0..16u8 {
map.ins_prim(0x70+i, X86InstructionEncoding::new(jcc[i as usize].0,jcc[i as usize].1,&[0x70+i],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm8],true,false,false,false,None,true,false,false,false,false,false,false,false));
}
let g1 = ["ADD","OR","ADC","SBB","AND","SUB","XOR","CMP"];
let g1i = ["add","or","adc","sbb","and","sub","xor","cmp"];
for ext in 0..8u8 {
map.ins_prim(0x80, X86InstructionEncoding::new(g1[ext as usize],g1i[ext as usize],&[0x80],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Imm8],true,false,false,false,Some(ext),false,false,false,false,false,true,true,g1[ext as usize]!="CMP"));
map.ins_prim(0x81, X86InstructionEncoding::new(g1[ext as usize],g1i[ext as usize],&[0x81],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Imm32],false,false,true,false,Some(ext),false,false,false,false,false,true,true,g1[ext as usize]!="CMP"));
map.ins_prim(0x83, X86InstructionEncoding::new(g1[ext as usize],g1i[ext as usize],&[0x83],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Imm8],true,false,false,false,Some(ext),false,false,false,false,false,true,true,g1[ext as usize]!="CMP"));
}
map.ins_prim(0x84, X86InstructionEncoding::new("TEST","test",&[0x84],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,true,true,false,true));
map.ins_prim(0x85, X86InstructionEncoding::new("TEST","test",&[0x85],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,true,true,false,true));
map.ins_prim(0x86, X86InstructionEncoding::new("XCHG","xchg",&[0x86],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,false,true,true,true));
map.ins_prim(0x87, X86InstructionEncoding::new("XCHG","xchg",&[0x87],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,true,true));
map.ins_prim(0x88, X86InstructionEncoding::new("MOV","mov",&[0x88],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0x89, X86InstructionEncoding::new("MOV","mov",&[0x89],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0x8A, X86InstructionEncoding::new("MOV","mov",&[0x8A],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Reg8,Mem8],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0x8B, X86InstructionEncoding::new("MOV","mov",&[0x8B],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0x8C, X86InstructionEncoding::new("MOV","mov",&[0x8C],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem16,SegReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0x8D, X86InstructionEncoding::new("LEA","lea",&[0x8D],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Reg64,Mem64],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0x8E, X86InstructionEncoding::new("MOV","mov",&[0x8E],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[SegReg,Mem16],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0x8F, X86InstructionEncoding::new("POP","pop",&[0x8F],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem64],false,false,false,false,Some(0),false,false,false,false,false,false,true,false));
map.ins_prim(0x90, e!("NOP","nop",0x90,Legacy));
for i in 1..8u8 {
map.ins_prim(0x90+i, X86InstructionEncoding::new("XCHG","xchg",&[0x90+i],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Reg32,Reg32],false,false,false,false,None,false,false,false,false,false,false,false,true));
}
map.ins_prim(0x98, e!("CBW_CWDE_CDQE","cbw/cwde/cdqe",0x98,LegacyREX));
map.ins_prim(0x99, e!("CWD_CDQ_CQO","cwd/cdq/cqo",0x99,LegacyREX));
map.ins_prim(0x9C, X86InstructionEncoding::new("PUSHF","pushf",&[0x9C],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,true,false));
map.ins_prim(0x9D, X86InstructionEncoding::new("POPF","popf",&[0x9D],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_prim(0x9E, e!("SAHF","sahf",0x9E,Legacy));
map.ins_prim(0x9F, e!("LAHF","lahf",0x9F,Legacy));
map.ins_prim(0xA0, X86InstructionEncoding::new("MOV","mov",&[0xA0],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Reg8,Mem8],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0xA1, X86InstructionEncoding::new("MOV","mov",&[0xA1],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_prim(0xA2, X86InstructionEncoding::new("MOV","mov",&[0xA2],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0xA3, X86InstructionEncoding::new("MOV","mov",&[0xA3],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_prim(0xA4, X86InstructionEncoding::new("MOVSB","movsb",&[0xA4],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,true,false));
map.ins_prim(0xA5, X86InstructionEncoding::new("MOVS","movs",&[0xA5],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,true,false));
map.ins_prim(0xA6, X86InstructionEncoding::new("CMPSB","cmpsb",&[0xA6],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_prim(0xA7, X86InstructionEncoding::new("CMPS","cmps",&[0xA7],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_prim(0xA8, X86InstructionEncoding::new("TEST","test",&[0xA8],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm8],true,false,false,false,None,false,false,false,false,true,false,false,true));
map.ins_prim(0xA9, X86InstructionEncoding::new("TEST","test",&[0xA9],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm32],false,false,true,false,None,false,false,false,false,true,false,false,true));
map.ins_prim(0xAA, X86InstructionEncoding::new("STOSB","stosb",&[0xAA],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,true,false));
map.ins_prim(0xAB, X86InstructionEncoding::new("STOS","stos",&[0xAB],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,true,false));
map.ins_prim(0xAC, X86InstructionEncoding::new("LODSB","lodsb",&[0xAC],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_prim(0xAD, X86InstructionEncoding::new("LODS","lods",&[0xAD],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_prim(0xAE, X86InstructionEncoding::new("SCASB","scasb",&[0xAE],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_prim(0xAF, X86InstructionEncoding::new("SCAS","scas",&[0xAF],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,true,false,false));
for i in 0..8u8 {
map.ins_prim(0xB0+i, X86InstructionEncoding::new("MOV","mov",&[0xB0+i],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Reg8,Imm8],true,false,false,false,Some(i),false,false,false,false,false,false,false,false));
map.ins_prim(0xB8+i, X86InstructionEncoding::new("MOV","mov",&[0xB8+i],OpcodeMap::Primary,MandatoryPrefix::None,LegacyREX,false,None,false,&[Reg32,Imm32],false,false,true,false,Some(i),false,false,false,false,false,false,false,false));
}
let shifts = [("ROL","rol"),("ROR","ror"),("RCL","rcl"),("RCR","rcr"),("SHL","shl"),("SHR","shr"),("SAL","sal"),("SAR","sar")];
for ext in 0..8u8 {
map.ins_prim(0xC0, X86InstructionEncoding::new(shifts[ext as usize].0,shifts[ext as usize].1,&[0xC0],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Imm8],true,false,false,false,Some(ext),false,false,false,false,false,true,true,false));
map.ins_prim(0xC1, X86InstructionEncoding::new(shifts[ext as usize].0,shifts[ext as usize].1,&[0xC1],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Imm8],true,false,false,false,Some(ext),false,false,false,false,false,true,true,false));
}
map.ins_prim(0xC2, X86InstructionEncoding::new("RET","ret",&[0xC2],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm16],false,true,false,false,None,false,false,true,true,true,false,false,false));
map.ins_prim(0xC3, X86InstructionEncoding::new("RET","ret",&[0xC3],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,true,true,true,false,false,false));
map.ins_prim(0xC6, X86InstructionEncoding::new("MOV","mov",&[0xC6],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Imm8],true,false,false,false,Some(0),false,false,false,false,false,false,true,false));
map.ins_prim(0xC7, X86InstructionEncoding::new("MOV","mov",&[0xC7],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Imm32],false,false,true,false,Some(0),false,false,false,false,false,false,true,false));
map.ins_prim(0xC8, X86InstructionEncoding::new("ENTER","enter",&[0xC8],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm16,Imm8],true,true,false,false,None,false,false,false,false,true,false,true,false));
map.ins_prim(0xC9, e!("LEAVE","leave",0xC9,LegacyREX));
map.ins_prim(0xCC, X86InstructionEncoding::new("INT3","int3",&[0xCC],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
map.ins_prim(0xCD, X86InstructionEncoding::new("INT","int",&[0xCD],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm8],true,false,false,false,None,false,false,false,true,true,false,false,false));
let d_ops: &[(u8, bool)] = &[(0xD0, true),(0xD1, false),(0xD2, true),(0xD3, false)];
for &(base, byte_op) in d_ops {
for ext in 0..8u8 {
let op_type = if byte_op { &[Mem8] as &[_] } else { &[Mem32] as &[_] };
map.ins_prim(base, X86InstructionEncoding::new(shifts[ext as usize].0,shifts[ext as usize].1,&[base],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,op_type,false,false,false,false,Some(ext),false,false,false,false,false,true,true,false));
}
}
map.ins_prim(0xE8, X86InstructionEncoding::new("CALL","call",&[0xE8],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm32],false,false,true,false,None,true,true,false,true,true,false,false,false));
map.ins_prim(0xE9, X86InstructionEncoding::new("JMP","jmp",&[0xE9],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm32],false,false,true,false,None,true,false,false,true,false,false,false,false));
map.ins_prim(0xEB, X86InstructionEncoding::new("JMP","jmp",&[0xEB],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,&[Imm8],true,false,false,false,None,true,false,false,true,false,false,false,false));
map.ins_prim(0xF4, X86InstructionEncoding::new("HLT","hlt",&[0xF4],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
map.ins_prim(0xF5, e!("CMC","cmc",0xF5,Legacy));
let g3 = [("TEST","test"),("TEST","test"),("NOT","not"),("NEG","neg"),("MUL","mul"),("IMUL","imul"),("DIV","div"),("IDIV","idiv")];
for ext in 0..8u8 {
map.ins_prim(0xF6, X86InstructionEncoding::new(g3[ext as usize].0,g3[ext as usize].1,&[0xF6],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8],false,false,false,false,Some(ext),false,false,false,false,ext<2,true,ext>=4,false));
map.ins_prim(0xF7, X86InstructionEncoding::new(g3[ext as usize].0,g3[ext as usize].1,&[0xF7],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32],false,false,false,false,Some(ext),false,false,false,false,ext<2,true,ext>=4,false));
}
map.ins_prim(0xF8, e!("CLC","clc",0xF8,Legacy));
map.ins_prim(0xF9, e!("STC","stc",0xF9,Legacy));
map.ins_prim(0xFA, X86InstructionEncoding::new("CLI","cli",&[0xFA],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,false,false));
map.ins_prim(0xFB, X86InstructionEncoding::new("STI","sti",&[0xFB],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,false,false));
map.ins_prim(0xFC, e!("CLD","cld",0xFC,Legacy));
map.ins_prim(0xFD, e!("STD","std",0xFD,Legacy));
map.ins_prim(0xFE, X86InstructionEncoding::new("INC","inc",&[0xFE],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8],false,false,false,false,Some(0),false,false,false,false,false,true,true,false));
let g5 = [("INC","inc"),("DEC","dec"),("CALL","call"),("CALL","call"),("JMP","jmp"),("JMP","jmp"),("PUSH","push"),("","")];
for ext in 0..7u8 {
if !g5[ext as usize].0.is_empty() {
map.ins_prim(0xFF, X86InstructionEncoding::new(g5[ext as usize].0,g5[ext as usize].1,&[0xFF],OpcodeMap::Primary,MandatoryPrefix::None,Legacy,true,None,false,&[Mem64],false,false,false,false,Some(ext),ext>=2,ext>=2,false,ext>=2,false,ext!=6,ext==6,false));
}
}
}
fn build_two_byte_opcode_map(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let g6 = [("SLDT","sldt"),("STR","str"),("LLDT","lldt"),("LTR","ltr"),("VERR","verr"),("VERW","verw"),("",""),("","")];
for ext in 0..6u8 {
map.ins_two(0x00, X86InstructionEncoding::new(g6[ext as usize].0,g6[ext as usize].1,&[0x00],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg16],false,false,false,false,Some(ext),false,false,false,false,false,true,false,false));
}
for ext in 0..8u8 {
map.ins_two(0x01, X86InstructionEncoding::new("SGDT_LGDT_SIDT_LIDT","sgdt/lgdt/sidt/lidt",&[0x01],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem64],false,false,false,false,Some(ext),false,false,false,false,false,false,true,false));
}
map.ins_two(0x02, X86InstructionEncoding::new("LAR","lar",&[0x02],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem16],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x03, X86InstructionEncoding::new("LSL","lsl",&[0x03],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x05, X86InstructionEncoding::new("SYSCALL","syscall",&[0x05],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
map.ins_two(0x06, e!("CLTS","clts",0x06,Legacy));
map.ins_two(0x07, X86InstructionEncoding::new("SYSRET","sysret",&[0x07],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
map.ins_two(0x08, e!("INVD","invd",0x08,Legacy));
map.ins_two(0x09, e!("WBINVD","wbinvd",0x09,Legacy));
map.ins_two(0x0B, X86InstructionEncoding::new("UD2","ud2",&[0x0B],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
map.ins_two(0x10, X86InstructionEncoding::new("MOVUPS","movups",&[0x10],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x11, X86InstructionEncoding::new("MOVUPS","movups",&[0x11],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x12, X86InstructionEncoding::new("MOVLPS_MOVHLPS","movlps/movhlps",&[0x12],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x13, X86InstructionEncoding::new("MOVLPS","movlps",&[0x13],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x14, X86InstructionEncoding::new("UNPCKLPS","unpcklps",&[0x14],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x15, X86InstructionEncoding::new("UNPCKHPS","unpckhps",&[0x15],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x16, X86InstructionEncoding::new("MOVHPS_MOVLHPS","movhps/movlhps",&[0x16],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x17, X86InstructionEncoding::new("MOVHPS","movhps",&[0x17],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
let pfetch = [("PREFETCHNTA","prefetchnta"),("PREFETCHT0","prefetcht0"),("PREFETCHT1","prefetcht1"),("PREFETCHT2","prefetcht2"),("",""),("",""),("",""),("","")];
for ext in 0..4u8 {
map.ins_two(0x18, X86InstructionEncoding::new(pfetch[ext as usize].0,pfetch[ext as usize].1,&[0x18],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8],false,false,false,false,Some(ext),false,false,false,false,false,true,false,false));
}
map.ins_two(0x1F, X86InstructionEncoding::new("NOP","nop",&[0x1F],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32],false,false,false,false,Some(0),false,false,false,false,false,true,false,false));
map.ins_two(0x20, X86InstructionEncoding::new("MOV","mov",&[0x20],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,CtrlReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x21, X86InstructionEncoding::new("MOV","mov",&[0x21],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,DebugReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x22, X86InstructionEncoding::new("MOV","mov",&[0x22],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[CtrlReg,Reg32],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x23, X86InstructionEncoding::new("MOV","mov",&[0x23],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[DebugReg,Reg32],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x28, X86InstructionEncoding::new("MOVAPS","movaps",&[0x28],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x29, X86InstructionEncoding::new("MOVAPS","movaps",&[0x29],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x2A, X86InstructionEncoding::new("CVTSI2SS","cvtsi2ss",&[0x2A],OpcodeMap::TwoByte,MandatoryPrefix::PF3,Legacy,true,None,false,&[XmmReg,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x2B, X86InstructionEncoding::new("MOVNTPS","movntps",&[0x2B],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x2C, X86InstructionEncoding::new("CVTTSS2SI","cvttss2si",&[0x2C],OpcodeMap::TwoByte,MandatoryPrefix::PF3,Legacy,true,None,false,&[Reg32,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x2D, X86InstructionEncoding::new("CVTTSD2SI","cvttsd2si",&[0x2D],OpcodeMap::TwoByte,MandatoryPrefix::PF2,Legacy,true,None,false,&[Reg32,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x2E, X86InstructionEncoding::new("UCOMISS","ucomiss",&[0x2E],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_two(0x2F, X86InstructionEncoding::new("UCOMISD","ucomisd",&[0x2F],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_two(0x30, e!("WRMSR","wrmsr",0x30,Legacy));
map.ins_two(0x31, e!("RDTSC","rdtsc",0x31,Legacy));
map.ins_two(0x32, e!("RDMSR","rdmsr",0x32,Legacy));
map.ins_two(0x33, e!("RDPMC","rdpmc",0x33,Legacy));
map.ins_two(0x34, X86InstructionEncoding::new("SYSENTER","sysenter",&[0x34],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
map.ins_two(0x35, X86InstructionEncoding::new("SYSEXIT","sysexit",&[0x35],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,true,true,false,false,false));
let cmov = [("CMOVO","cmovo"),("CMOVNO","cmovno"),("CMOVB","cmovb"),("CMOVAE","cmovae"),("CMOVE","cmove"),("CMOVNE","cmovne"),("CMOVBE","cmovbe"),("CMOVA","cmova"),("CMOVS","cmovs"),("CMOVNS","cmovns"),("CMOVP","cmovp"),("CMOVNP","cmovnp"),("CMOVL","cmovl"),("CMOVGE","cmovge"),("CMOVLE","cmovle"),("CMOVG","cmovg")];
for i in 0..16u8 {
map.ins_two(0x40+i, X86InstructionEncoding::new(cmov[i as usize].0,cmov[i as usize].1,&[0x40+i],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_two(0x50, X86InstructionEncoding::new("MOVMSKPS","movmskps",&[0x50],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
let sse_arith: [(u8,&str,&str,bool);14] = [
(0x51,"SQRTPS","sqrtps",false),(0x52,"RSQRTPS","rsqrtps",false),(0x53,"RCPPS","rcpps",false),
(0x54,"ANDPS","andps",true),(0x55,"ANDNPS","andnps",false),(0x56,"ORPS","orps",true),
(0x57,"XORPS","xorps",true),(0x58,"ADDPS","addps",true),(0x59,"MULPS","mulps",true),
(0x5A,"CVTPS2PD","cvtps2pd",false),(0x5B,"CVTDQ2PS","cvtdq2ps",false),
(0x5C,"SUBPS","subps",false),(0x5D,"MINPS","minps",true),(0x5E,"DIVPS","divps",false),
];
for &(op,mn,im,cm) in &sse_arith {
map.ins_two(op, X86InstructionEncoding::new(mn,im,&[op],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,cm));
}
map.ins_two(0x5F, X86InstructionEncoding::new("MAXPS","maxps",&[0x5F],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
let sse2_packed: [(u8,&str,&str);16] = [
(0x60,"PUNPCKLBW","punpcklbw"),(0x61,"PUNPCKLWD","punpcklwd"),(0x62,"PUNPCKLDQ","punpckldq"),
(0x63,"PACKSSWB","packsswb"),(0x64,"PCMPGTB","pcmpgtb"),(0x65,"PCMPGTW","pcmpgtw"),
(0x66,"PCMPGTD","pcmpgtd"),(0x67,"PACKUSWB","packuswb"),(0x68,"PUNPCKHBW","punpckhbw"),
(0x69,"PUNPCKHWD","punpckhwd"),(0x6A,"PUNPCKHDQ","punpckhdq"),(0x6B,"PACKSSDW","packssdw"),
(0x6C,"PUNPCKLQDQ","punpcklqdq"),(0x6D,"PUNPCKHQDQ","punpckhqdq"),(0x6E,"MOVD","movd"),
(0x6F,"MOVDQA","movdqa"),
];
for &(op,mn,im) in &sse2_packed {
map.ins_two(op, X86InstructionEncoding::new(mn,im,&[op],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,mn.contains("PCMP")));
}
map.ins_two(0x70, X86InstructionEncoding::new("PSHUFW","pshufw",&[0x70],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x71, X86InstructionEncoding::new("PSRLW_PSRAW_PSLLW","psrlw/psraw/psllw",&[0x71],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,Imm8],true,false,false,false,Some(2),false,false,false,false,false,true,false,false));
map.ins_two(0x72, X86InstructionEncoding::new("PSRLD_PSRAD_PSLLD","psrld/psrad/pslld",&[0x72],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,Imm8],true,false,false,false,Some(2),false,false,false,false,false,true,false,false));
map.ins_two(0x73, X86InstructionEncoding::new("PSRLQ_PSLLQ","psrlq/psllq",&[0x73],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,Imm8],true,false,false,false,Some(2),false,false,false,false,false,true,false,false));
map.ins_two(0x74, X86InstructionEncoding::new("PCMPEQB","pcmpeqb",&[0x74],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_two(0x75, X86InstructionEncoding::new("PCMPEQW","pcmpeqw",&[0x75],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_two(0x76, X86InstructionEncoding::new("PCMPEQD","pcmpeqd",&[0x76],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_two(0x77, e!("EMMS","emms",0x77,Legacy));
map.ins_two(0x78, X86InstructionEncoding::new("VMREAD","vmread",&[0x78],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg64,Reg64],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0x79, X86InstructionEncoding::new("VMWRITE","vmwrite",&[0x79],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg64,Reg64],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x7E, X86InstructionEncoding::new("MOVD","movd",&[0x7E],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[Mem32,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0x7F, X86InstructionEncoding::new("MOVDQA","movdqa",&[0x7F],OpcodeMap::TwoByte,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
let jcc32 = [("JO","jo"),("JNO","jno"),("JB","jb"),("JAE","jae"),("JE","je"),("JNE","jne"),
("JBE","jbe"),("JA","ja"),("JS","js"),("JNS","jns"),("JP","jp"),("JNP","jnp"),
("JL","jl"),("JGE","jge"),("JLE","jle"),("JG","jg")];
for i in 0..16u8 {
map.ins_two(0x80+i, X86InstructionEncoding::new(jcc32[i as usize].0,jcc32[i as usize].1,&[0x80+i],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,&[Imm32],false,false,true,false,None,true,false,false,false,false,false,false,false));
}
let setcc = [("SETO","seto"),("SETNO","setno"),("SETB","setb"),("SETAE","setae"),("SETE","sete"),("SETNE","setne"),("SETBE","setbe"),("SETA","seta"),("SETS","sets"),("SETNS","setns"),("SETP","setp"),("SETNP","setnp"),("SETL","setl"),("SETGE","setge"),("SETLE","setle"),("SETG","setg")];
for i in 0..16u8 {
map.ins_two(0x90+i, X86InstructionEncoding::new(setcc[i as usize].0,setcc[i as usize].1,&[0x90+i],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8],false,false,false,false,Some(0),false,false,false,false,false,false,true,false));
}
map.ins_two(0xA0, X86InstructionEncoding::new("PUSH","push",&[0xA0],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0xA1, X86InstructionEncoding::new("POP","pop",&[0xA1],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xA2, X86InstructionEncoding::new("CPUID","cpuid",&[0xA2],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,false,false));
map.ins_two(0xA3, X86InstructionEncoding::new("BT","bt",&[0xA3],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xA4, X86InstructionEncoding::new("SHLD","shld",&[0xA4],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32,Imm8],true,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xA5, X86InstructionEncoding::new("SHLD","shld",&[0xA5],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32,Reg8],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xAB, X86InstructionEncoding::new("BTS","bts",&[0xAB],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xAC, X86InstructionEncoding::new("SHRD","shrd",&[0xAC],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32,Imm8],true,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xAD, X86InstructionEncoding::new("SHRD","shrd",&[0xAD],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32,Reg8],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xAE, X86InstructionEncoding::new("FXSAVE","fxsave",&[0xAE],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem512],false,false,false,false,Some(0),false,false,false,false,true,false,true,false));
map.ins_two(0xAF, X86InstructionEncoding::new("IMUL","imul",&[0xAF],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xB0, X86InstructionEncoding::new("CMPXCHG","cmpxchg",&[0xB0],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xB1, X86InstructionEncoding::new("CMPXCHG","cmpxchg",&[0xB1],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xB6, X86InstructionEncoding::new("MOVZX","movzx",&[0xB6],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem8],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xB7, X86InstructionEncoding::new("MOVZX","movzx",&[0xB7],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem16],false,false,false,false,None,false,false,false,false,false,true,false,false));
for ext in 4..8u8 {
let bt = ["BT","BTS","BTR","BTC"];
let bti = ["bt","bts","btr","btc"];
map.ins_two(0xBA, X86InstructionEncoding::new(bt[ext as usize-4],bti[ext as usize-4],&[0xBA],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Imm8],true,false,false,false,Some(ext),false,false,false,false,false,true,false,false));
}
map.ins_two(0xBB, X86InstructionEncoding::new("BTC","btc",&[0xBB],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xBC, X86InstructionEncoding::new("BSF","bsf",&[0xBC],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xBD, X86InstructionEncoding::new("BSR","bsr",&[0xBD],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xBE, X86InstructionEncoding::new("MOVSX","movsx",&[0xBE],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem8],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xBF, X86InstructionEncoding::new("MOVSX","movsx",&[0xBF],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32,Mem16],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xC0, X86InstructionEncoding::new("XADD","xadd",&[0xC0],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem8,Reg8],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xC1, X86InstructionEncoding::new("XADD","xadd",&[0xC1],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,true,false));
map.ins_two(0xC2, X86InstructionEncoding::new("CMPPS","cmpps",&[0xC2],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_two(0xC3, X86InstructionEncoding::new("MOVNTI","movnti",&[0xC3],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_two(0xC6, X86InstructionEncoding::new("SHUFPS","shufps",&[0xC6],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_two(0xC7, X86InstructionEncoding::new("CMPXCHG8B","cmpxchg8b",&[0xC7],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Mem64],false,false,false,false,Some(1),false,false,false,false,false,true,true,false));
for i in 0..8u8 {
map.ins_two(0xC8+i, X86InstructionEncoding::new("BSWAP","bswap",&[0xC8+i],OpcodeMap::TwoByte,MandatoryPrefix::None,Legacy,true,None,false,&[Reg32],false,false,false,false,None,false,false,false,false,false,false,false,false));
}
}
fn build_0f38_opcode_map(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let ssse3: [(u8,&str);12] = [(0x00,"PSHUFB"),(0x01,"PHADDW"),(0x02,"PHADDD"),(0x03,"PHADDSW"),
(0x04,"PMADDUBSW"),(0x05,"PHSUBW"),(0x06,"PHSUBD"),(0x07,"PHSUBSW"),
(0x08,"PSIGNB"),(0x09,"PSIGNW"),(0x0A,"PSIGND"),(0x0B,"PMULHRSW")];
for &(op,mn) in &ssse3 {
map.ins_38(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_38(0x10, X86InstructionEncoding::new("PBLENDVB","pblendvb",&[0x10],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0x14, X86InstructionEncoding::new("BLENDVPS","blendvps",&[0x14],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0x15, X86InstructionEncoding::new("BLENDVPD","blendvpd",&[0x15],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0x17, X86InstructionEncoding::new("PTEST","ptest",&[0x17],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
let pmov: [(u8,&str);12] = [(0x20,"PMOVSXBW"),(0x21,"PMOVSXBD"),(0x22,"PMOVSXBQ"),(0x23,"PMOVSXWD"),(0x24,"PMOVSXWQ"),(0x25,"PMOVSXDQ"),(0x30,"PMOVZXBW"),(0x31,"PMOVZXBD"),(0x32,"PMOVZXBQ"),(0x33,"PMOVZXWD"),(0x34,"PMOVZXWQ"),(0x35,"PMOVZXDQ")];
for &(op,mn) in &pmov {
map.ins_38(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_38(0x28, X86InstructionEncoding::new("PMULDQ","pmuldq",&[0x28],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0x29, X86InstructionEncoding::new("PCMPEQQ","pcmpeqq",&[0x29],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_38(0x2B, X86InstructionEncoding::new("PACKUSDW","packusdw",&[0x2B],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0x37, X86InstructionEncoding::new("PCMPGTQ","pcmpgtq",&[0x37],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
let pminmax: [(u8,&str);8] = [(0x38,"PMINSB"),(0x39,"PMINSD"),(0x3A,"PMINUW"),(0x3B,"PMINUD"),(0x3C,"PMAXSB"),(0x3D,"PMAXSD"),(0x3E,"PMAXUW"),(0x3F,"PMAXUD")];
for &(op,mn) in &pminmax {
map.ins_38(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
}
map.ins_38(0x40, X86InstructionEncoding::new("PMULLD","pmulld",&[0x40],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
map.ins_38(0x41, X86InstructionEncoding::new("PHMINPOSUW","phminposuw",&[0x41],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0x80, X86InstructionEncoding::new("INVEPT","invept",&[0x80],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[Reg32,Mem128],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_38(0x81, X86InstructionEncoding::new("INVVPID","invvpid",&[0x81],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[Reg32,Mem128],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_38(0x82, X86InstructionEncoding::new("INVPCID","invpcid",&[0x82],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[Reg64,Mem128],false,false,false,false,None,false,false,false,false,true,true,false,false));
let sha: [(u8,&str);6] = [(0xC8,"SHA1NEXTE"),(0xC9,"SHA1MSG1"),(0xCA,"SHA1MSG2"),(0xCB,"SHA256RNDS2"),(0xCC,"SHA256MSG1"),(0xCD,"SHA256MSG2")];
for &(op,mn) in &sha {
map.ins_38(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::ThreeByte38,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
let aes: [(u8,&str);5] = [(0xDB,"AESIMC"),(0xDC,"AESENC"),(0xDD,"AESENCLAST"),(0xDE,"AESDEC"),(0xDF,"AESDECLAST")];
for &(op,mn) in &aes {
map.ins_38(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_38(0xF0, X86InstructionEncoding::new("MOVBE","movbe",&[0xF0],OpcodeMap::ThreeByte38,MandatoryPrefix::None,Legacy,true,None,false,&[Reg16,Mem16],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0xF1, X86InstructionEncoding::new("CRC32","crc32",&[0xF1],OpcodeMap::ThreeByte38,MandatoryPrefix::PF2,Legacy,true,None,false,&[Reg32,Mem8],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_38(0xF6, X86InstructionEncoding::new("ADCX","adcx",&[0xF6],OpcodeMap::ThreeByte38,MandatoryPrefix::P66,Legacy,true,None,false,&[Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,true));
map.ins_38(0xF8, X86InstructionEncoding::new("ENQCMD","enqcmd",&[0xF8],OpcodeMap::ThreeByte38,MandatoryPrefix::None,Legacy,true,None,false,&[Reg64,Mem512],false,false,false,false,None,false,false,false,false,true,true,true,false));
map.ins_38(0xF9, X86InstructionEncoding::new("ENQCMDS","enqcmds",&[0xF9],OpcodeMap::ThreeByte38,MandatoryPrefix::None,Legacy,true,None,false,&[Reg64,Mem512],false,false,false,false,None,false,false,false,false,true,true,true,false));
}
fn build_0f3a_opcode_map(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let rnd: [(u8,&str);8] = [(0x08,"ROUNDPS"),(0x09,"ROUNDPD"),(0x0A,"ROUNDSS"),(0x0B,"ROUNDSD"),(0x0C,"BLENDPS"),(0x0D,"BLENDPD"),(0x0E,"PBLENDW"),(0x0F,"PALIGNR")];
for &(op,mn) in &rnd {
map.ins_3a(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_3a(0x14, X86InstructionEncoding::new("PEXTRB","pextrb",&[0x14],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[Mem8,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_3a(0x15, X86InstructionEncoding::new("PEXTRW","pextrw",&[0x15],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[Reg32,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_3a(0x16, X86InstructionEncoding::new("PEXTRD","pextrd",&[0x16],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[Mem32,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_3a(0x17, X86InstructionEncoding::new("EXTRACTPS","extractps",&[0x17],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[Mem32,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_3a(0x20, X86InstructionEncoding::new("PINSRB","pinsrb",&[0x20],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,Mem8,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x21, X86InstructionEncoding::new("INSERTPS","insertps",&[0x21],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x22, X86InstructionEncoding::new("PINSRD","pinsrd",&[0x22],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,Mem32,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x40, X86InstructionEncoding::new("DPPS","dpps",&[0x40],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x41, X86InstructionEncoding::new("DPPD","dppd",&[0x41],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x42, X86InstructionEncoding::new("MPSADBW","mpsadbw",&[0x42],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x44, X86InstructionEncoding::new("PCLMULQDQ","pclmulqdq",&[0x44],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0x60, X86InstructionEncoding::new("PCMPESTRI","pcmpestri",&[0x60],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_3a(0x61, X86InstructionEncoding::new("PCMPESTRM","pcmpestrm",&[0x61],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_3a(0x62, X86InstructionEncoding::new("PCMPISTRI","pcmpistri",&[0x62],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_3a(0x63, X86InstructionEncoding::new("PCMPISTRM","pcmpistrm",&[0x63],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_3a(0xCC, X86InstructionEncoding::new("SHA1RNDS4","sha1rnds4",&[0xCC],OpcodeMap::ThreeByte3A,MandatoryPrefix::None,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_3a(0xDF, X86InstructionEncoding::new("AESKEYGENASSIST","aeskeygenassist",&[0xDF],OpcodeMap::ThreeByte3A,MandatoryPrefix::P66,Legacy,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
}
fn build_vex_opcode_maps(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let vex1_packed: [(u8,&str,MandatoryPrefix);18] = [
(0x58,"VADDPS",MandatoryPrefix::None),(0x58,"VADDPD",MandatoryPrefix::P66),
(0x59,"VMULPS",MandatoryPrefix::None),(0x59,"VMULPD",MandatoryPrefix::P66),
(0x5C,"VSUBPS",MandatoryPrefix::None),(0x5C,"VSUBPD",MandatoryPrefix::P66),
(0x5E,"VDIVPS",MandatoryPrefix::None),(0x5E,"VDIVPD",MandatoryPrefix::P66),
(0x5D,"VMINPS",MandatoryPrefix::None),(0x5D,"VMINPD",MandatoryPrefix::P66),
(0x5F,"VMAXPS",MandatoryPrefix::None),(0x5F,"VMAXPD",MandatoryPrefix::P66),
(0x54,"VANDPS",MandatoryPrefix::None),(0x55,"VANDNPS",MandatoryPrefix::None),
(0x56,"VORPS",MandatoryPrefix::None),(0x57,"VXORPS",MandatoryPrefix::None),
(0x51,"VSQRTPS",MandatoryPrefix::None),(0x51,"VSQRTPD",MandatoryPrefix::P66),
];
for &(op,mn,mp) in &vex1_packed {
map.ins_v1(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::VexMap1,mp,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,mn.contains("AND")||mn.contains("OR")||mn.contains("XOR")||mn.contains("MIN")||mn.contains("MAX")||mn.contains("ADD")||mn.contains("MUL")));
}
let vex1_scalar: [(u8,&str,MandatoryPrefix);12] = [
(0x58,"VADDSS",MandatoryPrefix::PF3),(0x58,"VADDSD",MandatoryPrefix::PF2),
(0x59,"VMULSS",MandatoryPrefix::PF3),(0x59,"VMULSD",MandatoryPrefix::PF2),
(0x5C,"VSUBSS",MandatoryPrefix::PF3),(0x5C,"VSUBSD",MandatoryPrefix::PF2),
(0x5E,"VDIVSS",MandatoryPrefix::PF3),(0x5E,"VDIVSD",MandatoryPrefix::PF2),
(0x5D,"VMINSS",MandatoryPrefix::PF3),(0x5D,"VMINSD",MandatoryPrefix::PF2),
(0x5F,"VMAXSS",MandatoryPrefix::PF3),(0x5F,"VMAXSD",MandatoryPrefix::PF2),
];
for &(op,mn,mp) in &vex1_scalar {
map.ins_v1(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::VexMap1,mp,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_v1(0x28, X86InstructionEncoding::new("VMOVAPS","vmovaps",&[0x28],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x10, X86InstructionEncoding::new("VMOVUPS","vmovups",&[0x10],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x10, X86InstructionEncoding::new("VMOVUPD","vmovupd",&[0x10],OpcodeMap::VexMap1,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x10, X86InstructionEncoding::new("VMOVSS","vmovss",&[0x10],OpcodeMap::VexMap1,MandatoryPrefix::PF3,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x10, X86InstructionEncoding::new("VMOVSD","vmovsd",&[0x10],OpcodeMap::VexMap1,MandatoryPrefix::PF2,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x12, X86InstructionEncoding::new("VMOVHLPS","vmovhlps",&[0x12],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x16, X86InstructionEncoding::new("VMOVLHPS","vmovlhps",&[0x16],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v1(0x77, X86InstructionEncoding::new("VZEROALL","vzeroall",&[0x77],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,false,false));
map.ins_v1(0x77, X86InstructionEncoding::new("VZEROUPPER","vzeroupper",&[0x77],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,true,false,false,false));
map.ins_v1(0xC2, X86InstructionEncoding::new("VCMPPS","vcmpps",&[0xC2],OpcodeMap::VexMap1,MandatoryPrefix::None,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_v1(0xC2, X86InstructionEncoding::new("VCMPPD","vcmppd",&[0xC2],OpcodeMap::VexMap1,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_v1(0x18, X86InstructionEncoding::new("VBROADCASTSS","vbroadcastss",&[0x18],OpcodeMap::VexMap1,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
let vex2_binop: [(u8,&str);16] = [(0xFC,"VPADDB"),(0xFD,"VPADDW"),(0xFE,"VPADDD"),(0xD4,"VPADDQ"),(0xF8,"VPSUBB"),(0xF9,"VPSUBW"),(0xFA,"VPSUBD"),(0xFB,"VPSUBQ"),(0xE5,"VPMULHW"),(0xD5,"VPMULLW"),(0xF4,"VPMULUDQ"),(0x74,"VPCMPEQB"),(0x75,"VPCMPEQW"),(0x76,"VPCMPEQD"),(0x64,"VPCMPGTB"),(0x65,"VPCMPGTW")];
for &(op,mn) in &vex2_binop {
map.ins_v2(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
}
let vex2_ssse3: [(u8,&str);13] = [(0x00,"VPSHUFB"),(0x01,"VPHADDW"),(0x02,"VPHADDD"),(0x03,"VPHADDSW"),(0x04,"VPMADDUBSW"),(0x05,"VPHSUBW"),(0x06,"VPHSUBD"),(0x07,"VPHSUBSW"),(0x08,"VPSIGNB"),(0x09,"VPSIGNW"),(0x0A,"VPSIGND"),(0x0B,"VPMULHRSW"),(0x1C,"VPABSB")];
for &(op,mn) in &vex2_ssse3 {
map.ins_v2(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_v2(0x1D, X86InstructionEncoding::new("VPABSW","vpabsw",&[0x1D],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x1E, X86InstructionEncoding::new("VPABSD","vpabsd",&[0x1E],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x40, X86InstructionEncoding::new("VPMULLD","vpmulld",&[0x40],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
map.ins_v2(0x37, X86InstructionEncoding::new("VPCMPGTQ","vpcmpgtq",&[0x37],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,true,true,false,false));
map.ins_v2(0x78, X86InstructionEncoding::new("VPBROADCASTB","vpbroadcastb",&[0x78],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x79, X86InstructionEncoding::new("VPBROADCASTW","vpbroadcastw",&[0x79],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x58, X86InstructionEncoding::new("VPBROADCASTD","vpbroadcastd",&[0x58],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x59, X86InstructionEncoding::new("VPBROADCASTQ","vpbroadcastq",&[0x59],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x47, X86InstructionEncoding::new("VPSLLVD","vpsllvd",&[0x47],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x45, X86InstructionEncoding::new("VPSRLVD","vpsrlvd",&[0x45],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x46, X86InstructionEncoding::new("VPSRAVD","vpsravd",&[0x46],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
let fma3: [(u8,&str);24] = [
(0x98,"VFMADD132PS"),(0x98,"VFMADD132PD"),(0x99,"VFMADD132SS"),(0x99,"VFMADD132SD"),
(0xA8,"VFMADD213PS"),(0xA8,"VFMADD213PD"),(0xA9,"VFMADD213SS"),(0xA9,"VFMADD213SD"),
(0xB8,"VFMADD231PS"),(0xB8,"VFMADD231PD"),(0xB9,"VFMADD231SS"),(0xB9,"VFMADD231SD"),
(0x9A,"VFMSUB132PS"),(0x9A,"VFMSUB132PD"),(0x9B,"VFMSUB132SS"),(0x9B,"VFMSUB132SD"),
(0xAA,"VFMSUB213PS"),(0xAA,"VFMSUB213PD"),(0xAB,"VFMSUB213SS"),(0xAB,"VFMSUB213SD"),
(0xBA,"VFMSUB231PS"),(0xBA,"VFMSUB231PD"),(0xBB,"VFMSUB231SS"),(0xBB,"VFMSUB231SD"),
];
for &(op,mn) in &fma3 {
map.ins_v3(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
map.ins_v3(0x00, X86InstructionEncoding::new("VPERMQ","vpermq",&[0x00],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[YmmReg,YmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x01, X86InstructionEncoding::new("VPERMPD","vpermpd",&[0x01],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[YmmReg,YmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x04, X86InstructionEncoding::new("VPERMILPS","vpermilps",&[0x04],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x05, X86InstructionEncoding::new("VPERMILPD","vpermilpd",&[0x05],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x18, X86InstructionEncoding::new("VINSERTF128","vinsertf128",&[0x18],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[YmmReg,YmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x19, X86InstructionEncoding::new("VEXTRACTF128","vextractf128",&[0x19],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,YmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x06, X86InstructionEncoding::new("VPERM2F128","vperm2f128",&[0x06],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[YmmReg,YmmReg,YmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF2, X86InstructionEncoding::new("ANDN","andn",&[0xF2],OpcodeMap::VexMap2,MandatoryPrefix::None,VEX,true,None,false,&[Reg32,Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF3, X86InstructionEncoding::new("BLSI","blsi",&[0xF3],OpcodeMap::VexMap2,MandatoryPrefix::None,VEX,true,None,false,&[Reg32,Mem32],false,false,false,false,Some(3),false,false,false,false,false,true,false,false));
map.ins_v2(0xF7, X86InstructionEncoding::new("BEXTR","bextr",&[0xF7],OpcodeMap::VexMap2,MandatoryPrefix::None,VEX,true,None,false,&[Reg32,Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF5, X86InstructionEncoding::new("BZHI","bzhi",&[0xF5],OpcodeMap::VexMap2,MandatoryPrefix::None,VEX,true,None,false,&[Reg32,Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF6, X86InstructionEncoding::new("MULX","mulx",&[0xF6],OpcodeMap::VexMap2,MandatoryPrefix::PF2,VEX,true,None,false,&[Reg32,Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF5, X86InstructionEncoding::new("PDEP","pdep",&[0xF5],OpcodeMap::VexMap2,MandatoryPrefix::PF2,VEX,true,None,false,&[Reg32,Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF5, X86InstructionEncoding::new("PEXT","pext",&[0xF5],OpcodeMap::VexMap2,MandatoryPrefix::PF3,VEX,true,None,false,&[Reg32,Reg32,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0xF0, X86InstructionEncoding::new("RORX","rorx",&[0xF0],OpcodeMap::VexMap3,MandatoryPrefix::PF2,VEX,true,None,false,&[Reg32,Mem32,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF7, X86InstructionEncoding::new("SARX","sarx",&[0xF7],OpcodeMap::VexMap2,MandatoryPrefix::PF3,VEX,true,None,false,&[Reg32,Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF7, X86InstructionEncoding::new("SHLX","shlx",&[0xF7],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[Reg32,Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xF7, X86InstructionEncoding::new("SHRX","shrx",&[0xF7],OpcodeMap::VexMap2,MandatoryPrefix::PF2,VEX,true,None,false,&[Reg32,Mem32,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x92, X86InstructionEncoding::new("VGATHERDPS","vgatherdps",&[0x92],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x93, X86InstructionEncoding::new("VGATHERDPD","vgatherdpd",&[0x93],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x90, X86InstructionEncoding::new("VPGATHERDD","vpgatherdd",&[0x90],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x91, X86InstructionEncoding::new("VPGATHERDQ","vpgatherdq",&[0x91],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xDC, X86InstructionEncoding::new("VAESENC","vaesenc",&[0xDC],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xDD, X86InstructionEncoding::new("VAESENCLAST","vaesenclast",&[0xDD],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xDE, X86InstructionEncoding::new("VAESDEC","vaesdec",&[0xDE],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xDF, X86InstructionEncoding::new("VAESDECLAST","vaesdeclast",&[0xDF],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0xCE, X86InstructionEncoding::new("VGF2P8AFFINEQB","vgf2p8affineqb",&[0xCE],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0xCF, X86InstructionEncoding::new("VGF2P8AFFINEINVQB","vgf2p8affineinvqb",&[0xCF],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0xCF, X86InstructionEncoding::new("VGF2P8MULB","vgf2p8mulb",&[0xCF],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x13, X86InstructionEncoding::new("VCVTPH2PS","vcvtph2ps",&[0x13],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX,true,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v3(0x1D, X86InstructionEncoding::new("VCVTPS2PH","vcvtps2ph",&[0x1D],OpcodeMap::VexMap3,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[XmmReg,XmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x16, X86InstructionEncoding::new("VPERMPS","vpermps",&[0x16],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[YmmReg,YmmReg,YmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_v2(0x36, X86InstructionEncoding::new("VPERMD","vpermd",&[0x36],OpcodeMap::VexMap2,MandatoryPrefix::P66,VEX3Byte,true,None,false,&[YmmReg,YmmReg,YmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
fn build_evex_opcode_maps(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let evex1_pf: [(u8,&str);12] = [(0x58,"VADDPS"),(0x59,"VMULPS"),(0x5C,"VSUBPS"),(0x5E,"VDIVPS"),(0x5D,"VMINPS"),(0x5F,"VMAXPS"),(0x54,"VANDPS"),(0x55,"VANDNPS"),(0x56,"VORPS"),(0x57,"VXORPS"),(0x51,"VSQRTPS"),(0x53,"VRCP14PS")];
for &(op,mn) in &evex1_pf {
map.ins_e1(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,mn.contains("AND")||mn.contains("OR")||mn.contains("XOR")||mn.contains("ADD")||mn.contains("MUL")||mn.contains("MIN")||mn.contains("MAX")));
}
let evex1_pd: [(u8,&str);12] = [(0x58,"VADDPD"),(0x59,"VMULPD"),(0x5C,"VSUBPD"),(0x5E,"VDIVPD"),(0x5D,"VMINPD"),(0x5F,"VMAXPD"),(0x54,"VANDPD"),(0x55,"VANDNPD"),(0x56,"VORPD"),(0x57,"VXORPD"),(0x51,"VSQRTPD"),(0x53,"VRCP14PD")];
for &(op,mn) in &evex1_pd {
map.ins_e1(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
}
map.ins_e1(0x58, X86InstructionEncoding::new("VADDSS","vaddss",&[0x58],OpcodeMap::EvexMap1,MandatoryPrefix::PF3,EVEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x58, X86InstructionEncoding::new("VADDSD","vaddsd",&[0x58],OpcodeMap::EvexMap1,MandatoryPrefix::PF2,EVEX,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x4E, X86InstructionEncoding::new("VRSQRT14PS","vrsqrt14ps",&[0x4E],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x42, X86InstructionEncoding::new("VGETEXPPS","vgetexpps",&[0x42],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x6F, X86InstructionEncoding::new("VMOVDQA32","vmovdqa32",&[0x6F],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x6F, X86InstructionEncoding::new("VMOVDQU32","vmovdqu32",&[0x6F],OpcodeMap::EvexMap1,MandatoryPrefix::PF3,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x8A, X86InstructionEncoding::new("VCOMPRESSPS","vcompressps",&[0x8A],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_e1(0x88, X86InstructionEncoding::new("VEXPANDPS","vexpandps",&[0x88],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x18, X86InstructionEncoding::new("VBROADCASTSS","vbroadcastss",&[0x18],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,Mem32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x19, X86InstructionEncoding::new("VBROADCASTSD","vbroadcastsd",&[0x19],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,Mem64],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e3(0x23, X86InstructionEncoding::new("VSHUFF32X4","vshuff32x4",&[0x23],OpcodeMap::EvexMap3,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e3(0x03, X86InstructionEncoding::new("VALIGND","valignd",&[0x03],OpcodeMap::EvexMap3,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e3(0x03, X86InstructionEncoding::new("VALIGNQ","valignq",&[0x03],OpcodeMap::EvexMap3,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e1(0x08, X86InstructionEncoding::new("VRNDSCALEPS","vrndscaleps",&[0x08],OpcodeMap::EvexMap1,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
let fma_evex: [(u8,&str);6] = [(0x98,"VFMADD132PS"),(0xA8,"VFMADD213PS"),(0xB8,"VFMADD231PS"),(0x98,"VFMADD132PD"),(0xA8,"VFMADD213PD"),(0xB8,"VFMADD231PD")];
for &(op,mn) in &fma_evex {
map.ins_e3(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::EvexMap3,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
let evex2_arith: [(u8,&str);8] = [(0xFC,"VPADDB"),(0xFD,"VPADDW"),(0xFE,"VPADDD"),(0xD4,"VPADDQ"),(0xF8,"VPSUBB"),(0xF9,"VPSUBW"),(0xFA,"VPSUBD"),(0xFB,"VPSUBQ")];
for &(op,mn) in &evex2_arith {
map.ins_e2(op, X86InstructionEncoding::new(mn,&mn.to_lowercase(),&[op],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
}
map.ins_e2(0x40, X86InstructionEncoding::new("VPMULLD","vpmulld",&[0x40],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
map.ins_e2(0x40, X86InstructionEncoding::new("VPMULLQ","vpmullq",&[0x40],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,true));
map.ins_e2(0x36, X86InstructionEncoding::new("VPERMD","vpermd",&[0x36],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x15, X86InstructionEncoding::new("VPROLVD","vprolvd",&[0x15],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x14, X86InstructionEncoding::new("VPRORVD","vprorvd",&[0x14],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x41, X86InstructionEncoding::new("KANDW","kandw",&[0x41],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,true));
map.ins_e2(0x42, X86InstructionEncoding::new("KANDNW","kandnw",&[0x42],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,false));
map.ins_e2(0x44, X86InstructionEncoding::new("KNOTW","knotw",&[0x44],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,false));
map.ins_e2(0x45, X86InstructionEncoding::new("KORW","korw",&[0x45],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,true));
map.ins_e2(0x46, X86InstructionEncoding::new("KXNORW","kxnorw",&[0x46],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,true));
map.ins_e2(0x47, X86InstructionEncoding::new("KXORW","kxorw",&[0x47],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,true));
map.ins_e2(0x4A, X86InstructionEncoding::new("KADDW","kaddw",&[0x4A],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Reg16],false,false,false,false,None,false,false,false,false,false,false,false,false));
map.ins_e2(0x32, X86InstructionEncoding::new("KSHIFTRW","kshiftrw",&[0x32],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16,Imm8],true,false,false,false,None,false,false,false,false,false,false,false,false));
map.ins_e2(0x99, X86InstructionEncoding::new("KTESTW","ktestw",&[0x99],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg16],false,false,false,false,None,false,false,false,false,true,false,false,false));
map.ins_e2(0x90, X86InstructionEncoding::new("KMOVW","kmovw",&[0x90],OpcodeMap::EvexMap2,MandatoryPrefix::None,EVEX,true,None,false,&[Reg16,Reg32],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x28, X86InstructionEncoding::new("VPMOVM2B","vpmovm2b",&[0x28],OpcodeMap::EvexMap2,MandatoryPrefix::PF3,EVEX,true,None,false,&[ZmmReg,Reg16],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x29, X86InstructionEncoding::new("VPMOVM2W","vpmovm2w",&[0x29],OpcodeMap::EvexMap2,MandatoryPrefix::PF3,EVEX,true,None,false,&[ZmmReg,Reg16],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x29, X86InstructionEncoding::new("VPMOVW2M","vpmovw2m",&[0x29],OpcodeMap::EvexMap2,MandatoryPrefix::PF2,EVEX,true,None,false,&[Reg16,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x38, X86InstructionEncoding::new("VPMOVD2M","vpmovd2m",&[0x38],OpcodeMap::EvexMap2,MandatoryPrefix::PF2,EVEX,true,None,false,&[Reg16,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0xB4, X86InstructionEncoding::new("VPMADD52LUQ","vpmadd52luq",&[0xB4],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0xB5, X86InstructionEncoding::new("VPMADD52HUQ","vpmadd52huq",&[0xB5],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x42, X86InstructionEncoding::new("VDBPSADBW","vdbpsadbw",&[0x42],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,ZmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x54, X86InstructionEncoding::new("VPOPCNTB","vpopcntb",&[0x54],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x55, X86InstructionEncoding::new("VPOPCNTW","vpopcntw",&[0x55],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0xC4, X86InstructionEncoding::new("VPCONFLICTD","vpconflictd",&[0xC4],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x44, X86InstructionEncoding::new("VPLZCNTD","vplzcntd",&[0x44],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e3(0x26, X86InstructionEncoding::new("VGETMANTPS","vgetmantps",&[0x26],OpcodeMap::EvexMap3,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg,Imm8],true,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x63, X86InstructionEncoding::new("VPCOMPRESSB","vpcompressb",&[0x63],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_e2(0x63, X86InstructionEncoding::new("VPCOMPRESSW","vpcompressw",&[0x63],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,false,true,false));
map.ins_e2(0x62, X86InstructionEncoding::new("VPEXPANDB","vpexpandb",&[0x62],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
map.ins_e2(0x62, X86InstructionEncoding::new("VPEXPANDW","vpexpandw",&[0x62],OpcodeMap::EvexMap2,MandatoryPrefix::P66,EVEX,true,None,false,&[ZmmReg,ZmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
fn build_xop_opcode_maps(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let xop8: [(u8,&str);18] = [(0x90,"VPHADDBD"),(0x91,"VPHADDBQ"),(0x92,"VPHADDWD"),(0x93,"VPHADDWQ"),(0x94,"VPHADDDQ"),(0x95,"VPHADDUBD"),(0x96,"VPHADDUBQ"),(0x97,"VPHADDUWD"),(0x98,"VPHADDUWQ"),(0x99,"VPHADDUDQ"),(0x9A,"VPHSUBBW"),(0x9B,"VPHSUBDQ"),(0x9C,"VPHSUBWD"),(0xC0,"VPROTB"),(0xC1,"VPROTW"),(0xC2,"VPROTD"),(0xC3,"VPROTQ"),(0xA2,"VPCMOV")];
for &(op,mn) in &xop8 {
map.ins_x8(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::XopMap8,MandatoryPrefix::None,XOP,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
let xop9: [(u8,&str);10] = [(0x80,"VPMACSSWW"),(0x81,"VPMACSSWD"),(0x82,"VPMACSSDQL"),(0x83,"VPMACSSDQH"),(0x84,"VPMACSSDD"),(0x85,"VPMACSWW"),(0x86,"VPMACSWD"),(0x87,"VPMACSDQL"),(0x88,"VPMACSDQH"),(0x89,"VPMACSDD")];
for &(op,mn) in &xop9 {
map.ins_x9(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::XopMap9,MandatoryPrefix::None,XOP,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
let xopa_: [(u8,&str);14] = [(0x08,"VPSHAB"),(0x09,"VPSHAW"),(0x0A,"VPSHAD"),(0x0B,"VPSHAQ"),(0x0C,"VPSHLB"),(0x0D,"VPSHLW"),(0x0E,"VPSHLD"),(0x0F,"VPSHLQ"),(0x80,"VFRCZPS"),(0x81,"VFRCZPD"),(0x82,"VFRCZSS"),(0x83,"VFRCZSD"),(0xA2,"VPPERM"),(0xCC,"VPCOMB")];
for &(op,mn) in &xopa_ {
map.ins_xa(op, X86InstructionEncoding::new(mn,&mn.to_lowercase()[1..],&[op],OpcodeMap::XopMapA,MandatoryPrefix::None,XOP,true,None,false,&[XmmReg,XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
}
fn build_3dnow_opcode_map(map: &mut X86OpcodeMap) {
use OperandType::*; use EncodingForm::*;
let td: [(u8,&str,&str);22] = [
(0x0C,"PI2FW","pi2fw"),(0x0D,"PI2FD","pi2fd"),(0x1C,"PF2IW","pf2iw"),(0x1D,"PF2ID","pf2id"),
(0x8A,"PFNACC","pfnacc"),(0x8E,"PFPNACC","pfpnacc"),(0x90,"PFCMPGE","pfcmpge"),
(0x94,"PFMIN","pfmin"),(0x96,"PFRCP","pfrcp"),(0x97,"PFRSQRT","pfrsqrt"),
(0x9A,"PFSUB","pfsub"),(0x9E,"PFADD","pfadd"),(0xA0,"PFCMPGT","pfcmpgt"),
(0xA4,"PFMAX","pfmax"),(0xA6,"PFRCPIT1","pfrcpit1"),(0xA7,"PFRSQIT1","pfrsqit1"),
(0xAA,"PFSUBR","pfsubr"),(0xAE,"PFACC","pfacc"),(0xB0,"PFCMPEQ","pfcmpeq"),
(0xB4,"PFMUL","pfmul"),(0xB6,"PFRCPIT2","pfrcpit2"),(0x0E,"FEMMS","femms"),
];
for &(op,mn,im) in &td {
let has_modrm = mn != "FEMMS";
map.ins_dn(op, X86InstructionEncoding::new(mn,im,&[op],OpcodeMap::ThreeDNow,MandatoryPrefix::None,Legacy,has_modrm,None,false,&[XmmReg,XmmReg],false,false,false,false,None,false,false,false,false,false,true,false,false));
}
}
#[derive(Debug, Clone)]
pub struct X86EncodingFull {
pub opcode_map: X86OpcodeMap,
pub default_mode: u8,
}
impl Default for X86EncodingFull {
fn default() -> Self {
let mut map = X86OpcodeMap::new();
build_primary_opcode_map(&mut map);
build_two_byte_opcode_map(&mut map);
build_0f38_opcode_map(&mut map);
build_0f3a_opcode_map(&mut map);
build_vex_opcode_maps(&mut map);
build_evex_opcode_maps(&mut map);
build_xop_opcode_maps(&mut map);
build_3dnow_opcode_map(&mut map);
Self { opcode_map: map, default_mode: 64 }
}
}
impl X86EncodingFull {
pub fn new() -> Self { Self::default() }
pub fn with_mode(mut self, mode: u8) -> Self { self.default_mode = mode; self }
pub fn lookup_by_mnemonic(&self, mnemonic: &str) -> Vec<&X86InstructionEncoding> {
self.opcode_map.lookup_by_mnemonic(mnemonic)
}
pub fn lookup_primary(&self, op: u8) -> Option<&X86InstructionEncoding> { self.opcode_map.lookup_primary(op) }
pub fn lookup_two_byte(&self, op: u8) -> Option<&X86InstructionEncoding> { self.opcode_map.lookup_two_byte(op) }
pub fn lookup_0f38(&self, op: u8) -> Option<&X86InstructionEncoding> { self.opcode_map.lookup_0f38(op) }
pub fn lookup_0f3a(&self, op: u8) -> Option<&X86InstructionEncoding> { self.opcode_map.lookup_0f3a(op) }
pub fn total_encodings(&self) -> usize { self.opcode_map.total_encodings() }
pub fn encode_prefix(&self, enc: &X86InstructionEncoding) -> X86PrefixEncoding {
let mut pfx = X86PrefixEncoding::new();
match enc.encoding_form {
EncodingForm::Legacy => {}
EncodingForm::LegacyREX => { if enc.rex_w { pfx = pfx.with_rex_w(); } }
EncodingForm::VEX => {
pfx = pfx.with_vex2(false, 0, false, enc.mandatory_prefix.vex_pp_bits());
}
EncodingForm::VEX3Byte => {
pfx = pfx.with_vex3(false, false, false, VEX_MMMMM_0F3A, false, 0, false, enc.mandatory_prefix.vex_pp_bits());
}
EncodingForm::EVEX => {
pfx = pfx.with_evex(false, false, false, false, false, false, false, false, 1, enc.mandatory_prefix.vex_pp_bits(), false, 0, false, false);
}
EncodingForm::XOP => {
pfx = pfx.with_xop(false, false, false, 8, false, 0, false, enc.mandatory_prefix.vex_pp_bits());
}
EncodingForm::None => {}
}
pfx
}
pub fn build_encoding_info(&self, mnemonic: &str) -> Option<InstrEncodingInfo> {
self.lookup_by_mnemonic(mnemonic).first().map(|enc| InstrEncodingInfo {
opcode: 0, mnemonic: enc.mnemonic.to_string(), intel_mnemonic: enc.intel_mnemonic.to_string(),
num_operands: enc.operand_types.len() as u8, encoding_form: enc.encoding_form,
base_opcode: enc.opcode_byte(), opcode_map: enc.opcode_map as u8,
mandatory_prefix: enc.mandatory_prefix.byte().unwrap_or(0),
requires_modrm: enc.has_modrm, modrm_extension: enc.modrm_extension.unwrap_or(0),
operand_types: vec![], is_terminator: enc.is_terminator, is_branch: enc.is_branch,
is_call: enc.is_call, is_return: enc.is_return,
is_compare: enc.mnemonic=="CMP"||enc.mnemonic=="TEST",
is_move_immediate: enc.has_imm8||enc.has_imm16||enc.has_imm32,
is_convert: false, has_side_effects: enc.has_side_effects,
may_load: enc.may_load, may_store: enc.may_store,
is_commutative: enc.is_commutative, is_three_address: false,
})
}
}
impl X86EncodingFull {
pub fn dispatch_encoding(&self, mnemonic: &str, has_rex_w: bool, use_vex: bool, use_evex: bool, use_xop: bool) -> Vec<&X86InstructionEncoding> {
let all = self.lookup_by_mnemonic(mnemonic);
all.into_iter().filter(|enc| {
if use_evex && !matches!(enc.encoding_form, EncodingForm::EVEX) { return false; }
if use_vex && !matches!(enc.encoding_form, EncodingForm::VEX | EncodingForm::VEX3Byte) { return false; }
if use_xop && !matches!(enc.encoding_form, EncodingForm::XOP) { return false; }
if !use_vex && !use_evex && !use_xop && matches!(enc.encoding_form, EncodingForm::VEX | EncodingForm::VEX3Byte | EncodingForm::EVEX | EncodingForm::XOP) { return false; }
if has_rex_w && !enc.rex_w { return false; }
true
}).collect()
}
pub fn encoding_counts_by_category(&self) -> EncodingsByCategory {
EncodingsByCategory {
legacy_count: self.opcode_map.primary.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.two_byte.iter().filter(|e|e.is_some()).count(),
sse_count: self.opcode_map.two_byte.iter().filter(|e|e.is_some()).count(),
sse2_count: self.opcode_map.two_byte.iter().filter(|e| {
if let Some(ref enc) = e { enc.mandatory_prefix == MandatoryPrefix::P66 } else { false }
}).count(),
ssse3_count: self.opcode_map.three_byte_38.iter().filter(|e|e.is_some()).count(),
sse41_count: self.opcode_map.three_byte_38.iter().filter(|e| {
if let Some(ref enc) = e { enc.opcode_byte() >= 0x38 && enc.opcode_byte() <= 0x41 } else { false }
}).count(),
sse42_count: self.opcode_map.three_byte_3a.iter().filter(|e|e.is_some()).count(),
avx_count: self.opcode_map.vex_map1.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.vex_map2.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.vex_map3.iter().filter(|e|e.is_some()).count(),
avx512_count: self.opcode_map.evex_map1.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.evex_map2.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.evex_map3.iter().filter(|e|e.is_some()).count(),
xop_count: self.opcode_map.xop_map8.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.xop_map9.iter().filter(|e|e.is_some()).count()
+ self.opcode_map.xop_map_a.iter().filter(|e|e.is_some()).count(),
tdnow_count: self.opcode_map.three_dnow.iter().filter(|e|e.is_some()).count(),
total: self.total_encodings(),
}
}
pub fn build_full_opcode_bytes(&self, enc: &X86InstructionEncoding) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend_from_slice(enc.opcode_map.escape_bytes());
bytes.extend_from_slice(enc.opcode_bytes);
bytes
}
}
#[derive(Debug, Clone, Default)]
pub struct EncodingsByCategory {
pub legacy_count: usize,
pub sse_count: usize,
pub sse2_count: usize,
pub ssse3_count: usize,
pub sse41_count: usize,
pub sse42_count: usize,
pub avx_count: usize,
pub avx512_count: usize,
pub xop_count: usize,
pub tdnow_count: usize,
pub total: usize,
}
impl EncodingsByCategory {
pub fn summary(&self) -> String {
format!("encodings: total={} legacy={} sse={} sse2={} ssse3={} sse4.1={} sse4.2={} avx={} avx512={} xop={} 3dnow={}",
self.total, self.legacy_count, self.sse_count, self.sse2_count,
self.ssse3_count, self.sse41_count, self.sse42_count,
self.avx_count, self.avx512_count, self.xop_count, self.tdnow_count)
}
}
pub fn decode_rex_prefix(rex: u8) -> Option<(bool, bool, bool, bool)> {
if rex < 0x40 || rex > 0x4F { return None; }
Some((
(rex & REX_W_BIT) != 0,
(rex & REX_R_BIT) != 0,
(rex & REX_X_BIT) != 0,
(rex & REX_B_BIT) != 0,
))
}
pub fn reg_needs_rex_r(regnum: u8) -> bool { regnum >= 8 }
pub fn reg_needs_rex_b(regnum: u8) -> bool { regnum >= 8 }
pub fn reg_needs_rex_x(regnum: u8) -> bool { regnum >= 8 }
#[derive(Debug, Clone, Copy, Default)]
pub struct VexDecodedFields {
pub is_3byte: bool,
pub r_inv: bool,
pub x_inv: bool,
pub b_inv: bool,
pub mmmmm: u8,
pub w: bool,
pub vvvv: u8,
pub l: bool,
pub pp: u8,
}
impl VexDecodedFields {
pub fn effective_reg_r(&self, reg: u8) -> u8 {
if self.r_inv { reg } else { reg | 0x08 }
}
pub fn effective_reg_x(&self, reg: u8) -> u8 {
if self.x_inv { reg } else { reg | 0x08 }
}
pub fn effective_reg_b(&self, reg: u8) -> u8 {
if self.b_inv { reg } else { reg | 0x08 }
}
pub fn true_vvvv(&self) -> u8 {
self.vvvv ^ 0x0F
}
}
pub fn decode_vex2(byte1: u8, byte2: u8) -> VexDecodedFields {
VexDecodedFields {
is_3byte: false,
r_inv: (byte2 & 0x80) == 0,
x_inv: true,
b_inv: true,
mmmmm: 1,
w: false,
vvvv: (byte2 >> 3) & 0x0F,
l: (byte2 & 0x04) != 0,
pp: byte2 & 0x03,
}
}
pub fn decode_vex3(byte1: u8, byte2: u8, byte3: u8) -> VexDecodedFields {
VexDecodedFields {
is_3byte: true,
r_inv: (byte2 & 0x80) == 0,
x_inv: (byte2 & 0x40) == 0,
b_inv: (byte2 & 0x20) == 0,
mmmmm: byte2 & 0x1F,
w: (byte3 & 0x80) != 0,
vvvv: (byte3 >> 3) & 0x0F,
l: (byte3 & 0x04) != 0,
pp: byte3 & 0x03,
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct EvexDecodedFields {
pub r_prime: bool,
pub x_prime: bool,
pub b_prime: bool,
pub r: bool,
pub x: bool,
pub b: bool,
pub mm: u8,
pub v_prime: bool,
pub w: bool,
pub vvvv: u8,
pub pp: u8,
pub z: bool,
pub l_prime: bool,
pub l: bool,
pub bcst: bool,
pub aaa: u8,
}
impl EvexDecodedFields {
pub fn vector_length(&self) -> u8 {
match (self.l_prime, self.l) {
(false, false) => 128,
(false, true) => 256,
(true, false) => 512,
(true, true) => 512, }
}
pub fn opmask_reg(&self) -> u8 { self.aaa }
pub fn is_zeroing(&self) -> bool { self.z }
pub fn is_broadcast(&self) -> bool { self.bcst }
}
pub fn decode_evex(p0: u8, p1: u8, p2: u8) -> EvexDecodedFields {
EvexDecodedFields {
r_prime: (p0 & 0x80) == 0,
x_prime: (p0 & 0x40) == 0,
b_prime: (p0 & 0x20) == 0,
r: (p0 & 0x10) == 0,
x: false, b: false, mm: p0 & 0x03,
v_prime: (p1 & 0x08) == 0,
w: (p1 & 0x80) != 0,
vvvv: (p1 >> 3) & 0x0F,
pp: p1 & 0x03,
z: (p2 & 0x80) != 0,
l_prime: (p2 & 0x20) != 0,
l: (p2 & 0x10) != 0,
bcst: (p2 & 0x10) != 0,
aaa: p2 & 0x07,
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct XopDecodedFields {
pub r_inv: bool,
pub x_inv: bool,
pub b_inv: bool,
pub mmmmm: u8,
pub w: bool,
pub vvvv: u8,
pub l: bool,
pub pp: u8,
}
pub fn decode_xop(byte1: u8, byte2: u8) -> XopDecodedFields {
XopDecodedFields {
r_inv: (byte1 & 0x80) == 0,
x_inv: (byte1 & 0x40) == 0,
b_inv: (byte1 & 0x20) == 0,
mmmmm: byte1 & 0x1F,
w: (byte2 & 0x80) != 0,
vvvv: (byte2 >> 3) & 0x0F,
l: (byte2 & 0x04) != 0,
pp: byte2 & 0x03,
}
}
pub fn opcode_map_description(map: OpcodeMap) -> &'static str {
match map {
OpcodeMap::Primary => "Primary (00-FF) — one-byte opcodes",
OpcodeMap::TwoByte => "Two-byte (0F xx) — escape-prefixed opcodes",
OpcodeMap::ThreeByte38 => "Three-byte (0F 38 xx) — SSE/AVX extended",
OpcodeMap::ThreeByte3A => "Three-byte (0F 3A xx) — SSE/AVX immediate",
OpcodeMap::VexMap1 => "VEX map 1 (0F) — VEX-encoded legacy",
OpcodeMap::VexMap2 => "VEX map 2 (0F 38) — VEX-encoded 0F38",
OpcodeMap::VexMap3 => "VEX map 3 (0F 3A) — VEX-encoded 0F3A",
OpcodeMap::EvexMap1 => "EVEX map 1 (0F) — EVEX-encoded 0F",
OpcodeMap::EvexMap2 => "EVEX map 2 (0F 38) — EVEX-encoded 0F38",
OpcodeMap::EvexMap3 => "EVEX map 3 (0F 3A) — EVEX-encoded 0F3A",
OpcodeMap::EvexMap5 => "EVEX map 5 — EVEX-encoded map 5",
OpcodeMap::EvexMap6 => "EVEX map 6 — EVEX-encoded map 6",
OpcodeMap::EvexMap7 => "EVEX map 7 — EVEX-encoded map 7",
OpcodeMap::XopMap8 => "XOP map 8 — integer horizontal ops",
OpcodeMap::XopMap9 => "XOP map 9 — integer multiply-accumulate",
OpcodeMap::XopMapA => "XOP map A — vector conditional ops",
OpcodeMap::ThreeDNow => "3DNow! (0F 0F) — AMD 3DNow! instructions",
}
}
pub fn encoding_form_description(form: EncodingForm) -> &'static str {
match form {
EncodingForm::Legacy => "Legacy (no prefix or mandatory prefix only)",
EncodingForm::LegacyREX => "Legacy + REX prefix (64-bit operand size)",
EncodingForm::VEX => "VEX 2-byte (C5) — compact AVX encoding",
EncodingForm::VEX3Byte => "VEX 3-byte (C4) — full AVX encoding",
EncodingForm::EVEX => "EVEX 4-byte (62) — AVX-512 encoding",
EncodingForm::XOP => "XOP 3-byte (8F) — AMD XOP encoding",
EncodingForm::None => "No encoding form (opcode-only)",
}
}
#[derive(Debug, Clone, Copy)]
pub struct ModRMAddressingMode {
pub mod_bits: u8,
pub rm_bits: u8,
pub mode_name: &'static str,
pub disp_size: u8,
pub needs_sib: bool,
pub is_rip_rel: bool,
pub is_register: bool,
}
impl ModRMAddressingMode {
pub fn from_modrm(modrm: u8) -> Self {
let mod_bits = X86ModRMEncoding::mod_field(modrm);
let rm_bits = X86ModRMEncoding::rm_field(modrm);
let (mode_name, disp_size, needs_sib, is_rip_rel, is_register) = match (mod_bits, rm_bits) {
(0, 5) => ("[RIP/EIP + disp32]", 4, false, true, false),
(0, 4) => ("[SIB + disp32]", 4, true, false, false),
(0, _) => ("[base]", 0, false, false, false),
(1, 4) => ("[SIB + disp8]", 1, true, false, false),
(1, _) => ("[base + disp8]", 1, false, false, false),
(2, 4) => ("[SIB + disp32]", 4, true, false, false),
(2, _) => ("[base + disp32]", 4, false, false, false),
(3, _) => ("register", 0, false, false, true),
_ => ("unknown", 0, false, false, false),
};
Self { mod_bits, rm_bits, mode_name, disp_size, needs_sib, is_rip_rel, is_register }
}
}
#[derive(Debug, Clone, Copy)]
pub struct SIBAddressingMode {
pub scale_value: u8,
pub index_reg32: &'static str,
pub base_reg32: &'static str,
pub index_reg64: &'static str,
pub base_reg64: &'static str,
pub is_abs_disp32: bool,
}
impl SIBAddressingMode {
pub fn from_sib_32(sib: u8) -> Self {
let scale = X86SIBEncoding::scale_value(X86SIBEncoding::scale_field(sib));
let idx = X86SIBEncoding::index_field(sib);
let base = X86SIBEncoding::base_field(sib);
let index_name = if idx == SIB::NO_INDEX { "(none)" } else { X86SIBEncoding::index_register_name_64(idx) };
let base_name = X86SIBEncoding::base_register_name_64(base);
let idx32 = Self::index_name_32(idx);
let bas32 = Self::base_name_32(base);
Self {
scale_value: scale,
index_reg32: idx32, base_reg32: bas32,
index_reg64: index_name, base_reg64: base_name,
is_abs_disp32: idx == SIB::NO_INDEX && base == SIB::RBP_BASE,
}
}
fn index_name_32(idx: u8) -> &'static str {
match idx { 0=>"EAX",1=>"ECX",2=>"EDX",3=>"EBX",4=>"(none)",5=>"EBP",6=>"ESI",7=>"EDI", _=>"??" }
}
fn base_name_32(base: u8) -> &'static str {
match base { 0=>"EAX",1=>"ECX",2=>"EDX",3=>"EBX",4=>"ESP",5=>"EBP",6=>"ESI",7=>"EDI", _=>"??" }
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VectorLength {
VL128,
VL256,
VL512,
VLIG, }
impl VectorLength {
pub const fn vex_l_bit(&self) -> bool {
matches!(self, Self::VL256)
}
pub const fn evex_ll_bits(&self) -> (bool, bool) {
match self {
Self::VL128 => (false, false),
Self::VL256 => (false, true),
Self::VL512 => (true, false),
Self::VLIG => (false, false),
}
}
pub const fn element_count(&self, element_size_bytes: u8) -> u16 {
let total_bytes: u16 = match self {
Self::VL128 => 16, Self::VL256 => 32, Self::VL512 => 64, Self::VLIG => 16,
};
total_bytes / element_size_bytes as u16
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EvexTupleType {
Full,
FullMem,
Half,
HalfMem,
Quarter,
QuarterMem,
Eighth,
EighthMem,
Scalar,
Mem128,
Tuple1Scalar,
Tuple2,
Tuple4,
Tuple8,
}
impl EvexTupleType {
pub const fn multiplier(&self) -> u8 {
match self {
Self::Full | Self::FullMem | Self::Tuple1Scalar => 1,
Self::Half | Self::HalfMem | Self::Tuple2 => 2,
Self::Quarter | Self::QuarterMem | Self::Tuple4 => 4,
Self::Eighth | Self::EighthMem | Self::Tuple8 => 8,
Self::Scalar | Self::Mem128 => 16,
}
}
pub const fn is_memory(&self) -> bool {
matches!(self, Self::FullMem | Self::HalfMem | Self::QuarterMem | Self::EighthMem)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EvexRoundingMode {
None,
RnSae, RdSae, RuSae, RzSae, Sae, }
impl EvexRoundingMode {
pub const fn rc_bits(&self) -> u8 {
match self {
Self::RnSae => 0b00, Self::RdSae => 0b01, Self::RuSae => 0b10, Self::RzSae => 0b11,
_ => 0,
}
}
pub const fn is_active(&self) -> bool { !matches!(self, Self::None) }
pub const fn has_sae(&self) -> bool { matches!(self, Self::RnSae | Self::RdSae | Self::RuSae | Self::RzSae | Self::Sae) }
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EvexBroadcastMode {
None,
Broadcast1To2,
Broadcast1To4,
Broadcast1To8,
Broadcast1To16,
Broadcast1To32,
}
impl EvexBroadcastMode {
pub const fn is_broadcast(&self) -> bool { !matches!(self, Self::None) }
pub const fn element_count(&self) -> u8 {
match self { Self::Broadcast1To2=>2,Self::Broadcast1To4=>4,Self::Broadcast1To8=>8,Self::Broadcast1To16=>16,Self::Broadcast1To32=>32,_=>1 }
}
pub const fn to_b_bit(&self) -> bool { self.is_broadcast() }
}
#[derive(Debug, Clone)]
pub struct IsaExtension {
pub name: &'static str,
pub cpuid_leaf: u32,
pub cpuid_sub_leaf: u32,
pub cpuid_reg: u8, pub cpuid_bit: u8,
pub year_introduced: u16,
pub example_cpu: &'static str,
}
pub static ISA_EXTENSIONS_CATALOG: &[IsaExtension] = &[
IsaExtension { name:"MMX", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:3,cpuid_bit:23,year_introduced:1997,example_cpu:"Pentium MMX" },
IsaExtension { name:"SSE", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:3,cpuid_bit:25,year_introduced:1999,example_cpu:"Pentium III" },
IsaExtension { name:"SSE2", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:3,cpuid_bit:26,year_introduced:2000,example_cpu:"Pentium 4" },
IsaExtension { name:"SSE3", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:0, year_introduced:2004,example_cpu:"Pentium 4 Prescott" },
IsaExtension { name:"SSSE3", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:9, year_introduced:2006,example_cpu:"Core 2 Duo" },
IsaExtension { name:"SSE4.1", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:19,year_introduced:2008,example_cpu:"Penryn" },
IsaExtension { name:"SSE4.2", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:20,year_introduced:2008,example_cpu:"Nehalem" },
IsaExtension { name:"AVX", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:28,year_introduced:2011,example_cpu:"Sandy Bridge" },
IsaExtension { name:"AVX2", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:5, year_introduced:2013,example_cpu:"Haswell" },
IsaExtension { name:"AVX-512F", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:16,year_introduced:2017,example_cpu:"Skylake-SP" },
IsaExtension { name:"AVX-512BW", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:30,year_introduced:2017,example_cpu:"Skylake-SP" },
IsaExtension { name:"AVX-512DQ", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:17,year_introduced:2017,example_cpu:"Skylake-SP" },
IsaExtension { name:"FMA", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:12,year_introduced:2012,example_cpu:"Haswell" },
IsaExtension { name:"BMI1", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:3, year_introduced:2013,example_cpu:"Haswell" },
IsaExtension { name:"BMI2", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:8, year_introduced:2013,example_cpu:"Haswell" },
IsaExtension { name:"AES", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:25,year_introduced:2010,example_cpu:"Westmere" },
IsaExtension { name:"SHA", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:29,year_introduced:2013,example_cpu:"Goldmont" },
IsaExtension { name:"XOP", cpuid_leaf:0x80000001,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:11,year_introduced:2011,example_cpu:"Bulldozer" },
IsaExtension { name:"F16C", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:29,year_introduced:2011,example_cpu:"Ivy Bridge" },
IsaExtension { name:"RDRAND", cpuid_leaf:1,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:30,year_introduced:2012,example_cpu:"Ivy Bridge" },
IsaExtension { name:"RDSEED", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:18,year_introduced:2014,example_cpu:"Broadwell" },
IsaExtension { name:"ADX", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:19,year_introduced:2014,example_cpu:"Broadwell" },
IsaExtension { name:"AVX-512VL", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:1,cpuid_bit:31,year_introduced:2017,example_cpu:"Skylake-SP" },
IsaExtension { name:"GFNI", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:8, year_introduced:2019,example_cpu:"Ice Lake" },
IsaExtension { name:"VAES", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:9, year_introduced:2019,example_cpu:"Ice Lake" },
IsaExtension { name:"VPCLMULQDQ",cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:10,year_introduced:2019,example_cpu:"Ice Lake" },
IsaExtension { name:"AVX-VNNI", cpuid_leaf:7,cpuid_sub_leaf:1,cpuid_reg:0,cpuid_bit:4, year_introduced:2021,example_cpu:"Alder Lake" },
IsaExtension { name:"AVX-IFMA", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:3,cpuid_bit:21,year_introduced:2019,example_cpu:"Cannon Lake" },
IsaExtension { name:"AVX-BF16", cpuid_leaf:7,cpuid_sub_leaf:1,cpuid_reg:0,cpuid_bit:5, year_introduced:2021,example_cpu:"Cooper Lake" },
IsaExtension { name:"AVX-FP16", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:3,cpuid_bit:23,year_introduced:2022,example_cpu:"Sapphire Rapids" },
IsaExtension { name:"CET", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:2,cpuid_bit:7, year_introduced:2020,example_cpu:"Tiger Lake" },
IsaExtension { name:"AMX", cpuid_leaf:7,cpuid_sub_leaf:0,cpuid_reg:3,cpuid_bit:24,year_introduced:2022,example_cpu:"Sapphire Rapids" },
IsaExtension { name:"AVX10.1", cpuid_leaf:7,cpuid_sub_leaf:1,cpuid_reg:3,cpuid_bit:19,year_introduced:2023,example_cpu:"Granite Rapids" },
];
pub fn lookup_isa_extension(name: &str) -> Option<&'static IsaExtension> {
ISA_EXTENSIONS_CATALOG.iter().find(|e| e.name.eq_ignore_ascii_case(name))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum X86ConditionCode {
O, NO, B, NB, Z, NZ, BE, A, S, NS, P, NP, L, GE, LE, G,
}
impl X86ConditionCode {
pub const fn mnemonic_jcc(&self) -> &'static str {
match self {
Self::O=>"JO",Self::NO=>"JNO",Self::B=>"JB",Self::NB=>"JAE",Self::Z=>"JE",Self::NZ=>"JNE",
Self::BE=>"JBE",Self::A=>"JA",Self::S=>"JS",Self::NS=>"JNS",Self::P=>"JP",Self::NP=>"JNP",
Self::L=>"JL",Self::GE=>"JGE",Self::LE=>"JLE",Self::G=>"JG",
}
}
pub const fn mnemonic_cmovcc(&self) -> &'static str {
match self {
Self::O=>"CMOVO",Self::NO=>"CMOVNO",Self::B=>"CMOVB",Self::NB=>"CMOVAE",Self::Z=>"CMOVE",Self::NZ=>"CMOVNE",
Self::BE=>"CMOVBE",Self::A=>"CMOVA",Self::S=>"CMOVS",Self::NS=>"CMOVNS",Self::P=>"CMOVP",Self::NP=>"CMOVNP",
Self::L=>"CMOVL",Self::GE=>"CMOVGE",Self::LE=>"CMOVLE",Self::G=>"CMOVG",
}
}
pub const fn mnemonic_setcc(&self) -> &'static str {
match self {
Self::O=>"SETO",Self::NO=>"SETNO",Self::B=>"SETB",Self::NB=>"SETAE",Self::Z=>"SETE",Self::NZ=>"SETNE",
Self::BE=>"SETBE",Self::A=>"SETA",Self::S=>"SETS",Self::NS=>"SETNS",Self::P=>"SETP",Self::NP=>"SETNP",
Self::L=>"SETL",Self::GE=>"SETGE",Self::LE=>"SETLE",Self::G=>"SETG",
}
}
pub const fn jcc_opcode_offset(&self) -> u8 {
match self { Self::O=>0,Self::NO=>1,Self::B=>2,Self::NB=>3,Self::Z=>4,Self::NZ=>5,Self::BE=>6,Self::A=>7,Self::S=>8,Self::NS=>9,Self::P=>10,Self::NP=>11,Self::L=>12,Self::GE=>13,Self::LE=>14,Self::G=>15 }
}
pub const fn from_jcc_opcode(opcode: u8) -> Option<Self> {
let base = opcode & 0x0F;
match base { 0=>Some(Self::O),1=>Some(Self::NO),2=>Some(Self::B),3=>Some(Self::NB),4=>Some(Self::Z),5=>Some(Self::NZ),6=>Some(Self::BE),7=>Some(Self::A),8=>Some(Self::S),9=>Some(Self::NS),10=>Some(Self::P),11=>Some(Self::NP),12=>Some(Self::L),13=>Some(Self::GE),14=>Some(Self::LE),15=>Some(Self::G), _=>None }
}
}
pub static GROUP_1_EXTENSIONS: [(&str, &str); 8] = [
("ADD","add"),("OR","or"),("ADC","adc"),("SBB","sbb"),("AND","and"),("SUB","sub"),("XOR","xor"),("CMP","cmp"),
];
pub static GROUP_2_EXTENSIONS: [(&str, &str); 8] = [
("ROL","rol"),("ROR","ror"),("RCL","rcl"),("RCR","rcr"),("SHL","shl"),("SHR","shr"),("SAL","sal"),("SAR","sar"),
];
pub static GROUP_3_EXTENSIONS: [(&str, &str); 8] = [
("TEST","test"),("TEST","test"),("NOT","not"),("NEG","neg"),("MUL","mul"),("IMUL","imul"),("DIV","div"),("IDIV","idiv"),
];
pub static GROUP_5_EXTENSIONS: [(&str, &str); 8] = [
("INC","inc"),("DEC","dec"),("CALL","call"),("CALL","call"),("JMP","jmp"),("JMP","jmp"),("PUSH","push"),("",""),
];
pub fn lookup_group_extension(group: u8, ext: u8) -> &'static str {
let table: &[(&str, &str)] = match group {
1 => &GROUP_1_EXTENSIONS,
2 => &GROUP_2_EXTENSIONS,
3 => &GROUP_3_EXTENSIONS,
5 => &GROUP_5_EXTENSIONS,
_ => return "UNKNOWN_GROUP",
};
if (ext as usize) < table.len() { table[ext as usize].0 } else { "UNKNOWN" }
}
#[cfg(test)]
mod tests {
use super::*;
fn engine() -> X86EncodingFull { X86EncodingFull::new() }
#[test] fn test_modrm_direct_register() { let b = ModRM::mod_direct(0,1); assert_eq!(b,0xC1); assert!(X86ModRMEncoding::is_register_reference(b)); }
#[test] fn test_modrm_memory_no_disp() { let b = ModRM::mod_mem_no_disp(0,0); assert_eq!(X86ModRMEncoding::mod_field(b),0); assert!(X86ModRMEncoding::is_memory_reference(b)); }
#[test] fn test_modrm_memory_disp8() { let b = ModRM::mod_mem_disp8(3,7); assert_eq!(X86ModRMEncoding::disp_size(b),1); }
#[test] fn test_modrm_memory_disp32() { let b = ModRM::mod_mem_disp32(5,2); assert_eq!(X86ModRMEncoding::disp_size(b),4); }
#[test] fn test_modrm_rip_relative() { let b = ModRM::mod_rip_rel(0); assert_eq!(X86ModRMEncoding::rm_field(b),5); assert_eq!(X86ModRMEncoding::mod_field(b),0); }
#[test] fn test_modrm_needs_sib() { assert!(X86ModRMEncoding::needs_sib(ModRM::mod_mem_no_disp(0,4))); assert!(!X86ModRMEncoding::needs_sib(ModRM::mod_mem_no_disp(0,0))); }
#[test] fn test_modrm_register_names() {
assert_eq!(X86ModRMEncoding::rm_register_name_64(0),"RAX");assert_eq!(X86ModRMEncoding::rm_register_name_64(7),"RDI");
assert_eq!(X86ModRMEncoding::rm_register_name_32(0),"EAX");assert_eq!(X86ModRMEncoding::rm_register_name_16(0),"AX");
assert_eq!(X86ModRMEncoding::rm_register_name_8(0,false),"AL");
}
#[test] fn test_all_256_modrm() { for i in 0..256u16 { let e=X86ModRMEncoding::ALL_MODRM_VALUES[i as usize]; assert_eq!(i,((e.0 as u16)<<6)|((e.1 as u16)<<3)|(e.2 as u16)); } }
#[test] fn test_sib_encode() { let s = SIB::scale_1(2,3); assert_eq!(s.encode(),0x53); assert_eq!(SIB::scale_field(s.encode()),0); assert_eq!(SIB::index_field(s.encode()),2); assert_eq!(SIB::base_field(s.encode()),3); }
#[test] fn test_sib_no_index() { let s = SIB::with_no_index(5); assert!(!X86SIBEncoding::has_index(s.encode())); }
#[test] fn test_sib_scales() { assert_eq!(SIB::scale_1(0,0).scale_value(),1); assert_eq!(SIB::scale_2(0,0).scale_value(),2); assert_eq!(SIB::scale_4(0,0).scale_value(),4); assert_eq!(SIB::scale_8(0,0).scale_value(),8); }
#[test] fn test_sib_rip() { assert!(X86SIBEncoding::is_rip_relative(ModRM::mod_mem_no_disp(0,4),SIB::rip_relative().encode())); }
#[test] fn test_prefix_empty() { assert!(X86PrefixEncoding::new().encode_bytes().is_empty()); }
#[test] fn test_prefix_lock() { assert_eq!(X86PrefixEncoding::new().with_lock().encode_bytes(),&[PREFIX_LOCK]); }
#[test] fn test_prefix_rep() { assert_eq!(X86PrefixEncoding::new().with_rep().encode_bytes(),&[PREFIX_REP]); }
#[test] fn test_prefix_repne() { assert_eq!(X86PrefixEncoding::new().with_repne().encode_bytes(),&[PREFIX_REPNE]); }
#[test] fn test_prefix_operand_size() { assert_eq!(X86PrefixEncoding::new().with_operand_size().encode_bytes(),&[PREFIX_OPERAND_SIZE]); }
#[test] fn test_prefix_address_size() { assert_eq!(X86PrefixEncoding::new().with_address_size().encode_bytes(),&[PREFIX_ADDRESS_SIZE]); }
#[test] fn test_prefix_rex_w() { assert_eq!(X86PrefixEncoding::new().with_rex_w().encode_bytes(),&[REX_W]); }
#[test] fn test_prefix_rex_rxb() { assert_eq!(X86PrefixEncoding::new().with_rex(false,true,true,true).encode_bytes(),&[0x47]); }
#[test] fn test_prefix_vex2() { let p=X86PrefixEncoding::new().with_vex2(false,0x0F,false,VEX_PP_NONE); let b=p.encode_bytes(); assert_eq!(b.len(),2); assert_eq!(b[0],VEX_2BYTE); }
#[test] fn test_prefix_vex3() { let p=X86PrefixEncoding::new().with_vex3(false,false,false,VEX_MAP_0F38,false,0x0F,false,VEX_PP_66); let b=p.encode_bytes(); assert_eq!(b.len(),3); assert_eq!(b[0],VEX_3BYTE); }
#[test] fn test_prefix_evex() { let p=X86PrefixEncoding::new().with_evex(false,false,false,false,false,false,false,false,2,1,false,0,false,false); let b=p.encode_bytes(); assert_eq!(b.len(),4); assert_eq!(b[0],EVEX_MAGIC); }
#[test] fn test_prefix_xop() { let p=X86PrefixEncoding::new().with_xop(false,false,false,XOP_MAP_8,false,0x0F,false,VEX_PP_NONE); let b=p.encode_bytes(); assert_eq!(b.len(),3); assert_eq!(b[0],XOP_MAGIC); }
#[test] fn test_prefix_multi() { assert_eq!(X86PrefixEncoding::new().with_lock().with_rep().with_operand_size().encode_bytes(),&[PREFIX_LOCK,PREFIX_REP,PREFIX_OPERAND_SIZE]); }
#[test] fn test_prefix_count() { assert_eq!(X86PrefixEncoding::new().with_lock().with_rex_w().prefix_byte_count(),2); }
#[test] fn test_opcode_map_num_escape() {
assert_eq!(OpcodeMap::Primary.num_escape_bytes(),0);assert_eq!(OpcodeMap::TwoByte.num_escape_bytes(),1);
assert_eq!(OpcodeMap::ThreeByte38.num_escape_bytes(),2);
}
#[test] fn test_opcode_map_escape_bytes() {
assert!(OpcodeMap::Primary.escape_bytes().is_empty());assert_eq!(OpcodeMap::TwoByte.escape_bytes(),&[0x0F]);
assert_eq!(OpcodeMap::ThreeByte38.escape_bytes(),&[0x0F,0x38]);
assert_eq!(OpcodeMap::ThreeByte3A.escape_bytes(),&[0x0F,0x3A]);
}
#[test] fn test_mandatory_prefix_vex_pp() {
assert_eq!(MandatoryPrefix::None.vex_pp_bits(),VEX_PP_NONE);assert_eq!(MandatoryPrefix::P66.vex_pp_bits(),VEX_PP_66);
assert_eq!(MandatoryPrefix::PF2.vex_pp_bits(),VEX_PP_F2);assert_eq!(MandatoryPrefix::PF3.vex_pp_bits(),VEX_PP_F3);
}
#[test] fn test_mandatory_prefix_byte() {
assert_eq!(MandatoryPrefix::None.byte(),None);assert_eq!(MandatoryPrefix::P66.byte(),Some(0x66));
assert_eq!(MandatoryPrefix::PF2.byte(),Some(0xF2));assert_eq!(MandatoryPrefix::PF3.byte(),Some(0xF3));
}
#[test] fn test_lookup_nop() { let e=engine(); let enc=e.lookup_primary(0x90).unwrap(); assert_eq!(enc.mnemonic,"NOP"); }
#[test] fn test_lookup_ret() { let e=engine(); let enc=e.lookup_primary(0xC3).unwrap(); assert_eq!(enc.mnemonic,"RET"); assert!(enc.is_return); assert!(enc.is_terminator); }
#[test] fn test_lookup_hlt() { let e=engine(); let enc=e.lookup_primary(0xF4).unwrap(); assert_eq!(enc.mnemonic,"HLT"); assert!(enc.has_side_effects); }
#[test] fn test_lookup_int3() { let e=engine(); let enc=e.lookup_primary(0xCC).unwrap(); assert_eq!(enc.mnemonic,"INT3"); assert!(enc.is_terminator); }
#[test] fn test_lookup_push_imm8() { let e=engine(); let enc=e.lookup_primary(0x6A).unwrap(); assert_eq!(enc.mnemonic,"PUSH"); assert!(enc.has_imm8); }
#[test] fn test_lookup_je() { let e=engine(); let enc=e.lookup_primary(0x74).unwrap(); assert_eq!(enc.mnemonic,"JE"); assert!(enc.is_branch); }
#[test] fn test_lookup_mov_r_rm() { let e=engine(); let enc=e.lookup_primary(0x8B).unwrap(); assert_eq!(enc.mnemonic,"MOV"); assert!(enc.may_load); }
#[test] fn test_lookup_mov_rm_r() { let e=engine(); let enc=e.lookup_primary(0x89).unwrap(); assert_eq!(enc.mnemonic,"MOV"); assert!(enc.may_store); }
#[test] fn test_lookup_xor() { let e=engine(); let enc=e.lookup_primary(0x31).unwrap(); assert_eq!(enc.mnemonic,"XOR"); assert!(enc.is_commutative); }
#[test] fn test_lookup_cmp() { let e=engine(); let enc=e.lookup_primary(0x39).unwrap(); assert_eq!(enc.mnemonic,"CMP"); }
#[test] fn test_lookup_lea() { let e=engine(); let enc=e.lookup_primary(0x8D).unwrap(); assert_eq!(enc.mnemonic,"LEA"); }
#[test] fn test_lookup_call_rel32() { let e=engine(); let enc=e.lookup_primary(0xE8).unwrap(); assert_eq!(enc.mnemonic,"CALL"); assert!(enc.is_call); assert!(enc.is_terminator); }
#[test] fn test_lookup_jmp_rel8() { let e=engine(); let enc=e.lookup_primary(0xEB).unwrap(); assert_eq!(enc.mnemonic,"JMP"); assert!(enc.is_branch); assert!(enc.is_terminator); }
#[test] fn test_lookup_jmp_rel32() { let e=engine(); let enc=e.lookup_primary(0xE9).unwrap(); assert_eq!(enc.mnemonic,"JMP"); assert!(enc.is_terminator); }
#[test] fn test_lookup_enter() { let e=engine(); let enc=e.lookup_primary(0xC8).unwrap(); assert_eq!(enc.mnemonic,"ENTER"); assert!(enc.has_imm16); assert!(enc.has_imm8); }
#[test] fn test_lookup_leave() { let e=engine(); let enc=e.lookup_primary(0xC9).unwrap(); assert_eq!(enc.mnemonic,"LEAVE"); }
#[test] fn test_lookup_movsxd() { let e=engine(); let enc=e.lookup_primary(0x63).unwrap(); assert_eq!(enc.mnemonic,"MOVSXD"); assert!(enc.rex_w); }
#[test] fn test_lookup_push_r64() { let e=engine(); let enc=e.lookup_primary(0x50).unwrap(); assert_eq!(enc.mnemonic,"PUSH"); }
#[test] fn test_lookup_pop_r64() { let e=engine(); let enc=e.lookup_primary(0x58).unwrap(); assert_eq!(enc.mnemonic,"POP"); }
#[test] fn test_lookup_test_rm_r() { let e=engine(); let enc=e.lookup_primary(0x85).unwrap(); assert_eq!(enc.mnemonic,"TEST"); assert!(enc.is_commutative); }
#[test] fn test_lookup_cmp_rm_imm8() { let e=engine(); let enc=e.lookup_primary(0x83).unwrap(); assert_eq!(enc.mnemonic,"CMP"); assert!(enc.modrm_extension.is_some()); }
#[test] fn test_lookup_cpuid() { let e=engine(); let enc=e.lookup_two_byte(0xA2).unwrap(); assert_eq!(enc.mnemonic,"CPUID"); assert!(enc.has_side_effects); }
#[test] fn test_lookup_rdtsc() { let e=engine(); let enc=e.lookup_two_byte(0x31).unwrap(); assert_eq!(enc.mnemonic,"RDTSC"); }
#[test] fn test_lookup_syscall() { let e=engine(); let enc=e.lookup_two_byte(0x05).unwrap(); assert_eq!(enc.mnemonic,"SYSCALL"); assert!(enc.has_side_effects); assert!(enc.is_terminator); }
#[test] fn test_lookup_cmove() { let e=engine(); let enc=e.lookup_two_byte(0x44).unwrap(); assert_eq!(enc.mnemonic,"CMOVE"); }
#[test] fn test_lookup_cmovg() { let e=engine(); let enc=e.lookup_two_byte(0x4F).unwrap(); assert_eq!(enc.mnemonic,"CMOVG"); }
#[test] fn test_lookup_sete() { let e=engine(); let enc=e.lookup_two_byte(0x94).unwrap(); assert_eq!(enc.mnemonic,"SETE"); }
#[test] fn test_lookup_imul() { let e=engine(); let enc=e.lookup_two_byte(0xAF).unwrap(); assert_eq!(enc.mnemonic,"IMUL"); }
#[test] fn test_lookup_bswap() { let e=engine(); let enc=e.lookup_two_byte(0xC8).unwrap(); assert_eq!(enc.mnemonic,"BSWAP"); }
#[test] fn test_lookup_xadd() { let e=engine(); let enc=e.lookup_two_byte(0xC0).unwrap(); assert_eq!(enc.mnemonic,"XADD"); }
#[test] fn test_lookup_shld() { let e=engine(); let enc=e.lookup_two_byte(0xA4).unwrap(); assert_eq!(enc.mnemonic,"SHLD"); assert!(enc.has_imm8); }
#[test] fn test_lookup_shrd() { let e=engine(); let enc=e.lookup_two_byte(0xAC).unwrap(); assert_eq!(enc.mnemonic,"SHRD"); assert!(enc.has_imm8); }
#[test] fn test_lookup_cmpxchg() { let e=engine(); let enc=e.lookup_two_byte(0xB1).unwrap(); assert_eq!(enc.mnemonic,"CMPXCHG"); }
#[test] fn test_lookup_cmpxchg8b() { let e=engine(); let enc=e.lookup_two_byte(0xC7).unwrap(); assert_eq!(enc.mnemonic,"CMPXCHG8B"); }
#[test] fn test_lookup_movzx() { let e=engine(); let enc=e.lookup_two_byte(0xB6).unwrap(); assert_eq!(enc.mnemonic,"MOVZX"); }
#[test] fn test_lookup_movsx() { let e=engine(); let enc=e.lookup_two_byte(0xBE).unwrap(); assert_eq!(enc.mnemonic,"MOVSX"); }
#[test] fn test_lookup_bsf() { let e=engine(); let enc=e.lookup_two_byte(0xBC).unwrap(); assert_eq!(enc.mnemonic,"BSF"); }
#[test] fn test_lookup_bsr() { let e=engine(); let enc=e.lookup_two_byte(0xBD).unwrap(); assert_eq!(enc.mnemonic,"BSR"); }
#[test] fn test_lookup_bt() { let e=engine(); let enc=e.lookup_two_byte(0xA3).unwrap(); assert_eq!(enc.mnemonic,"BT"); }
#[test] fn test_lookup_bts() { let e=engine(); let enc=e.lookup_two_byte(0xAB).unwrap(); assert_eq!(enc.mnemonic,"BTS"); }
#[test] fn test_lookup_btc() { let e=engine(); let enc=e.lookup_two_byte(0xBB).unwrap(); assert_eq!(enc.mnemonic,"BTC"); }
#[test] fn test_lookup_ud2() { let e=engine(); let enc=e.lookup_two_byte(0x0B).unwrap(); assert_eq!(enc.mnemonic,"UD2"); assert!(enc.is_terminator); }
#[test] fn test_lookup_addps() { let e=engine(); let enc=e.lookup_two_byte(0x58).unwrap(); assert_eq!(enc.mnemonic,"ADDPS"); assert!(enc.is_commutative); }
#[test] fn test_lookup_andps() { let e=engine(); let enc=e.lookup_two_byte(0x54).unwrap(); assert_eq!(enc.mnemonic,"ANDPS"); assert!(enc.is_commutative); }
#[test] fn test_lookup_movaps() { let e=engine(); let enc=e.lookup_two_byte(0x28).unwrap(); assert_eq!(enc.mnemonic,"MOVAPS"); assert!(enc.may_load); }
#[test] fn test_lookup_movdqa() { let e=engine(); let enc=e.lookup_two_byte(0x6F).unwrap(); assert_eq!(enc.mnemonic,"MOVDQA"); }
#[test] fn test_lookup_xorps() { let e=engine(); let enc=e.lookup_two_byte(0x57).unwrap(); assert_eq!(enc.mnemonic,"XORPS"); assert!(enc.is_commutative); }
#[test] fn test_lookup_emms() { let e=engine(); let enc=e.lookup_two_byte(0x77).unwrap(); assert_eq!(enc.mnemonic,"EMMS"); }
#[test] fn test_lookup_pshufb() { let e=engine(); let enc=e.lookup_0f38(0x00).unwrap(); assert_eq!(enc.mnemonic,"PSHUFB"); }
#[test] fn test_lookup_pmulld() { let e=engine(); let enc=e.lookup_0f38(0x40).unwrap(); assert_eq!(enc.mnemonic,"PMULLD"); assert!(enc.is_commutative); }
#[test] fn test_lookup_aesenc() { let e=engine(); let enc=e.lookup_0f38(0xDC).unwrap(); assert_eq!(enc.mnemonic,"AESENC"); }
#[test] fn test_lookup_sha1nexte() { let e=engine(); let enc=e.lookup_0f38(0xC8).unwrap(); assert_eq!(enc.mnemonic,"SHA1NEXTE"); }
#[test] fn test_lookup_adcx() { let e=engine(); let enc=e.lookup_0f38(0xF6).unwrap(); assert_eq!(enc.mnemonic,"ADCX"); }
#[test] fn test_lookup_crc32() { let e=engine(); let enc=e.lookup_0f38(0xF1).unwrap(); assert_eq!(enc.mnemonic,"CRC32"); }
#[test] fn test_lookup_movbe() { let e=engine(); let enc=e.lookup_0f38(0xF0).unwrap(); assert_eq!(enc.mnemonic,"MOVBE"); }
#[test] fn test_lookup_ptest() { let e=engine(); let enc=e.lookup_0f38(0x17).unwrap(); assert_eq!(enc.mnemonic,"PTEST"); }
#[test] fn test_lookup_phminposuw() { let e=engine(); let enc=e.lookup_0f38(0x41).unwrap(); assert_eq!(enc.mnemonic,"PHMINPOSUW"); }
#[test] fn test_lookup_roundps() { let e=engine(); let enc=e.lookup_0f3a(0x08).unwrap(); assert_eq!(enc.mnemonic,"ROUNDPS"); assert!(enc.has_imm8); }
#[test] fn test_lookup_palignr() { let e=engine(); let enc=e.lookup_0f3a(0x0F).unwrap(); assert_eq!(enc.mnemonic,"PALIGNR"); assert!(enc.has_imm8); }
#[test] fn test_lookup_pclmulqdq() { let e=engine(); let enc=e.lookup_0f3a(0x44).unwrap(); assert_eq!(enc.mnemonic,"PCLMULQDQ"); }
#[test] fn test_lookup_sha1rnds4() { let e=engine(); let enc=e.lookup_0f3a(0xCC).unwrap(); assert_eq!(enc.mnemonic,"SHA1RNDS4"); assert!(enc.has_imm8); }
#[test] fn test_lookup_aeskeygenassist() { let e=engine(); let enc=e.lookup_0f3a(0xDF).unwrap(); assert_eq!(enc.mnemonic,"AESKEYGENASSIST"); assert!(enc.has_imm8); }
#[test] fn test_lookup_extractps() { let e=engine(); let enc=e.lookup_0f3a(0x17).unwrap(); assert_eq!(enc.mnemonic,"EXTRACTPS"); assert!(enc.has_imm8); }
#[test] fn test_lookup_insertps() { let e=engine(); let enc=e.lookup_0f3a(0x21).unwrap(); assert_eq!(enc.mnemonic,"INSERTPS"); assert!(enc.has_imm8); }
#[test] fn test_lookup_dpps() { let e=engine(); let enc=e.lookup_0f3a(0x40).unwrap(); assert_eq!(enc.mnemonic,"DPPS"); assert!(enc.has_imm8); }
#[test] fn test_lookup_pcmpestri() { let e=engine(); let enc=e.lookup_0f3a(0x60).unwrap(); assert_eq!(enc.mnemonic,"PCMPESTRI"); assert!(enc.has_imm8); }
#[test] fn test_lookup_pcmpistrm() { let e=engine(); let enc=e.lookup_0f3a(0x63).unwrap(); assert_eq!(enc.mnemonic,"PCMPISTRM"); assert!(enc.has_imm8); }
#[test] fn test_by_mnemonic_mov() { assert!(engine().lookup_by_mnemonic("MOV").len()>5); }
#[test] fn test_by_mnemonic_add() { assert!(!engine().lookup_by_mnemonic("ADD").is_empty()); }
#[test] fn test_by_mnemonic_nonexistent() { assert!(engine().lookup_by_mnemonic("NONEXISTENT").is_empty()); }
#[test] fn test_by_mnemonic_vaddps() { let encs=engine().lookup_by_mnemonic("VADDPS"); assert!(!encs.is_empty()); assert!(encs.iter().any(|e| matches!(e.encoding_form,EncodingForm::VEX))); }
#[test] fn test_by_mnemonic_vaesenc() { assert!(!engine().lookup_by_mnemonic("VAESENC").is_empty()); }
#[test] fn test_by_mnemonic_vfmadd132ps() { assert!(!engine().lookup_by_mnemonic("VFMADD132PS").is_empty()); }
#[test] fn test_by_mnemonic_andn() { assert!(!engine().lookup_by_mnemonic("ANDN").is_empty()); }
#[test] fn test_by_mnemonic_bextr() { assert!(!engine().lookup_by_mnemonic("BEXTR").is_empty()); }
#[test] fn test_by_mnemonic_rorx() { assert!(!engine().lookup_by_mnemonic("RORX").is_empty()); }
#[test] fn test_by_mnemonic_vpaddd_evex() { assert!(!engine().lookup_by_mnemonic("VPADDD").is_empty()); }
#[test] fn test_by_mnemonic_vcompressps() { assert!(!engine().lookup_by_mnemonic("VCOMPRESSPS").is_empty()); }
#[test] fn test_by_mnemonic_kandw() { assert!(!engine().lookup_by_mnemonic("KANDW").is_empty()); }
#[test] fn test_by_mnemonic_vprotb() { assert!(!engine().lookup_by_mnemonic("VPROTB").is_empty()); }
#[test] fn test_by_mnemonic_vpcmov() { assert!(!engine().lookup_by_mnemonic("VPCMOV").is_empty()); }
#[test] fn test_by_mnemonic_pfadd() { assert!(!engine().lookup_by_mnemonic("PFADD").is_empty()); }
#[test] fn test_by_mnemonic_femms() { assert!(!engine().lookup_by_mnemonic("FEMMS").is_empty()); }
#[test] fn test_est_len_simple() { let enc=X86InstructionEncoding::new("T","t",&[0x90],OpcodeMap::Primary,MandatoryPrefix::None,EncodingForm::Legacy,false,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,false,false,false,false); assert_eq!(enc.estimated_length(false,0),1); }
#[test] fn test_est_len_modrm() { let enc=X86InstructionEncoding::new("T","t",&[0x84],OpcodeMap::Primary,MandatoryPrefix::None,EncodingForm::Legacy,true,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,false,false,false,false); assert_eq!(enc.estimated_length(false,0),2); }
#[test] fn test_est_len_sib_disp() { let enc=X86InstructionEncoding::new("T","t",&[0x84],OpcodeMap::Primary,MandatoryPrefix::None,EncodingForm::Legacy,true,None,false,NO_OPS,false,false,false,false,None,false,false,false,false,false,false,false,false); assert_eq!(enc.estimated_length(true,4),7); }
#[test] fn test_engine_default() { let e=X86EncodingFull::default(); assert_eq!(e.default_mode,64); assert!(e.total_encodings()>0); }
#[test] fn test_engine_with_mode() { assert_eq!(X86EncodingFull::new().with_mode(32).default_mode,32); }
#[test] fn test_build_encoding_info() { let info=engine().build_encoding_info("NOP"); assert!(info.is_some()); assert_eq!(info.unwrap().mnemonic,"NOP"); }
#[test] fn test_build_encoding_info_nonexistent() { assert!(engine().build_encoding_info("NONEXISTENT").is_none()); }
#[test] fn test_total_encodings_gt_800() { assert!(engine().total_encodings()>=800); }
#[test] fn test_primary_map_gt_180() { assert!(engine().opcode_map.primary.iter().filter(|e|e.is_some()).count()>=180); }
#[test] fn test_two_byte_map_gt_90() { assert!(engine().opcode_map.two_byte.iter().filter(|e|e.is_some()).count()>=90); }
#[test] fn test_0f38_map_gt_40() { assert!(engine().opcode_map.three_byte_38.iter().filter(|e|e.is_some()).count()>=40); }
#[test] fn test_0f3a_map_gt_15() { assert!(engine().opcode_map.three_byte_3a.iter().filter(|e|e.is_some()).count()>=15); }
#[test] fn test_vex_maps_have_entries() {
let v1=engine().opcode_map.vex_map1.iter().filter(|e|e.is_some()).count();
let v2=engine().opcode_map.vex_map2.iter().filter(|e|e.is_some()).count();
let v3=engine().opcode_map.vex_map3.iter().filter(|e|e.is_some()).count();
assert!(v1+v2+v3>0);
}
#[test] fn test_evex_maps_have_entries() {
let e1=engine().opcode_map.evex_map1.iter().filter(|e|e.is_some()).count();
let e2=engine().opcode_map.evex_map2.iter().filter(|e|e.is_some()).count();
let e3=engine().opcode_map.evex_map3.iter().filter(|e|e.is_some()).count();
assert!(e1+e2+e3>0);
}
#[test] fn test_xop_maps_have_entries() {
let x8=engine().opcode_map.xop_map8.iter().filter(|e|e.is_some()).count();
let x9=engine().opcode_map.xop_map9.iter().filter(|e|e.is_some()).count();
let xa=engine().opcode_map.xop_map_a.iter().filter(|e|e.is_some()).count();
assert!(x8+x9+xa>0);
}
#[test] fn test_3dnow_map_has_entries() { assert!(engine().opcode_map.three_dnow.iter().filter(|e|e.is_some()).count()>0); }
#[test] fn test_sib_absolute_disp32() { assert!(X86SIBEncoding::is_absolute_disp32(SIB::new(0,SIB::NO_INDEX,SIB::RBP_BASE).encode())); }
#[test] fn test_modrm_needs_disp_rip() { assert!(X86ModRMEncoding::needs_displacement(ModRM::mod_rip_rel(0))); }
#[test] fn test_modrm_no_disp_register() { assert!(!X86ModRMEncoding::needs_displacement(ModRM::mod_direct(0,0))); }
#[test] fn test_default_encoding_engine() { let _ = X86EncodingFull::default(); }
#[test] fn test_modrm_all_modes_distinct() {
let m0 = ModRM::mod_mem_no_disp(0, 0);
let m1 = ModRM::mod_mem_disp8(0, 0);
let m2 = ModRM::mod_mem_disp32(0, 0);
let m3 = ModRM::mod_direct(0, 0);
assert_ne!(X86ModRMEncoding::mod_field(m0), X86ModRMEncoding::mod_field(m1));
assert_ne!(X86ModRMEncoding::mod_field(m1), X86ModRMEncoding::mod_field(m2));
assert_ne!(X86ModRMEncoding::mod_field(m2), X86ModRMEncoding::mod_field(m3));
}
#[test] fn test_modrm_rm_register_direct_maps_correctly() {
for rm in 0..8u8 {
let b = ModRM::mod_direct(0, rm);
assert_eq!(X86ModRMEncoding::rm_field(b), rm);
assert!(X86ModRMEncoding::is_register_reference(b));
}
}
#[test] fn test_modrm_reg_field_preserved() {
for reg in 0..8u8 {
let b = ModRM::mod_direct(reg, 0);
assert_eq!(X86ModRMEncoding::reg_field(b), reg);
}
}
#[test] fn test_modrm_disp_size_all_modes() {
assert_eq!(X86ModRMEncoding::disp_size(ModRM::mod_mem_no_disp(0, 0)), 0);
assert_eq!(X86ModRMEncoding::disp_size(ModRM::mod_mem_no_disp(0, 5)), 4);
assert_eq!(X86ModRMEncoding::disp_size(ModRM::mod_mem_disp8(0, 0)), 1);
assert_eq!(X86ModRMEncoding::disp_size(ModRM::mod_mem_disp32(0, 0)), 4);
assert_eq!(X86ModRMEncoding::disp_size(ModRM::mod_direct(0, 0)), 0);
}
#[test] fn test_modrm_sib_needed_only_for_rm4() {
for rm in 0..8u8 {
let b = ModRM::mod_mem_no_disp(0, rm);
assert_eq!(X86ModRMEncoding::needs_sib(b), rm == 4);
}
}
#[test] fn test_modrm_addressing_mode_lookup_all() {
let m = ModRMAddressingMode::from_modrm(ModRM::mod_direct(3, 7));
assert!(m.is_register);
assert!(!m.needs_sib);
let m = ModRMAddressingMode::from_modrm(ModRM::mod_mem_no_disp(0, 5));
assert!(m.is_rip_rel);
assert_eq!(m.disp_size, 4);
let m = ModRMAddressingMode::from_modrm(ModRM::mod_mem_no_disp(0, 4));
assert!(m.needs_sib);
}
#[test] fn test_sib_all_scale_encodings() {
assert_eq!(SIB::scale_1(0, 0).scale_bits, 0);
assert_eq!(SIB::scale_2(0, 0).scale_bits, 1);
assert_eq!(SIB::scale_4(0, 0).scale_bits, 2);
assert_eq!(SIB::scale_8(0, 0).scale_bits, 3);
}
#[test] fn test_sib_all_index_values() {
for idx in 0..8u8 {
let s = SIB::scale_1(idx, 0);
assert_eq!(SIB::index_field(s.encode()), idx);
}
}
#[test] fn test_sib_all_base_values() {
for base in 0..8u8 {
let s = SIB::scale_1(0, base);
assert_eq!(SIB::base_field(s.encode()), base);
}
}
#[test] fn test_sib_absolute_disp32_detection() {
assert!(X86SIBEncoding::is_absolute_disp32(SIB::new(0, SIB::NO_INDEX, SIB::RBP_BASE).encode()));
assert!(!X86SIBEncoding::is_absolute_disp32(SIB::new(0, 0, SIB::RBP_BASE).encode()));
assert!(!X86SIBEncoding::is_absolute_disp32(SIB::new(0, SIB::NO_INDEX, 0).encode()));
}
#[test] fn test_sib_addressing_mode_lookup() {
let m = SIBAddressingMode::from_sib_32(SIB::scale_2(3, 4).encode());
assert_eq!(m.scale_value, 2);
assert!(!m.is_abs_disp32);
let m = SIBAddressingMode::from_sib_32(SIB::new(0, SIB::NO_INDEX, SIB::RBP_BASE).encode());
assert!(m.is_abs_disp32);
}
#[test] fn test_decode_rex_w() {
let (w, r, x, b) = decode_rex_prefix(REX_W).unwrap();
assert!(w); assert!(!r); assert!(!x); assert!(!b);
}
#[test] fn test_decode_rex_wrxb() {
let (w, r, x, b) = decode_rex_prefix(REX_WRXB).unwrap();
assert!(w); assert!(r); assert!(x); assert!(b);
}
#[test] fn test_decode_rex_bare() {
let (w, r, x, b) = decode_rex_prefix(REX_BASE).unwrap();
assert!(!w); assert!(!r); assert!(!x); assert!(!b);
}
#[test] fn test_decode_rex_invalid() {
assert!(decode_rex_prefix(0x00).is_none());
assert!(decode_rex_prefix(0x50).is_none());
}
#[test] fn test_decode_vex2() {
let v = decode_vex2(0xC5, 0xF8);
assert!(!v.is_3byte);
assert!(!v.l);
assert_eq!(v.pp, 0);
}
#[test] fn test_decode_vex3() {
let v = decode_vex3(0xC4, 0xE2, 0x78);
assert!(v.is_3byte);
assert_eq!(v.mmmmm, 2);
assert!(!v.w);
}
#[test] fn test_vex_decoded_effective_reg() {
let v = VexDecodedFields { r_inv: true};
assert_eq!(v.effective_reg_r(0), 0);
let v = VexDecodedFields { r_inv: false};
assert_eq!(v.effective_reg_r(0), 8);
}
#[test] fn test_decode_evex_512() {
let d = decode_evex(0x61, 0x78, 0x20);
assert_eq!(d.vector_length(), 512);
}
#[test] fn test_decode_evex_256() {
let d = decode_evex(0x61, 0x78, 0x10);
assert_eq!(d.vector_length(), 256);
}
#[test] fn test_decode_evex_128() {
let d = decode_evex(0x61, 0x78, 0x00);
assert_eq!(d.vector_length(), 128);
}
#[test] fn test_decode_evex_masking() {
let d = decode_evex(0x61, 0x78, 0x83);
assert!(d.is_zeroing());
assert_eq!(d.opmask_reg(), 3);
assert!(d.is_broadcast());
}
#[test] fn test_decode_xop() {
let x = decode_xop(0x88, 0x78);
assert_eq!(x.mmmmm, 8);
assert!(!x.w);
}
#[test] fn test_isa_catalog_size() { assert!(ISA_EXTENSIONS_CATALOG.len() >= 30); }
#[test] fn test_lookup_isa_sse() { assert!(lookup_isa_extension("SSE").is_some()); }
#[test] fn test_lookup_isa_avx() { assert!(lookup_isa_extension("AVX").is_some()); }
#[test] fn test_lookup_isa_avx512f() { assert!(lookup_isa_extension("AVX-512F").is_some()); }
#[test] fn test_lookup_isa_nonexistent() { assert!(lookup_isa_extension("NONEXISTENT_ISA").is_none()); }
#[test] fn test_cond_code_jcc_roundtrip() {
for cc in &[X86ConditionCode::O,X86ConditionCode::NO,X86ConditionCode::B,X86ConditionCode::NB,
X86ConditionCode::Z,X86ConditionCode::NZ,X86ConditionCode::BE,X86ConditionCode::A,
X86ConditionCode::S,X86ConditionCode::NS,X86ConditionCode::P,X86ConditionCode::NP,
X86ConditionCode::L,X86ConditionCode::GE,X86ConditionCode::LE,X86ConditionCode::G] {
let off = cc.jcc_opcode_offset();
let decoded = X86ConditionCode::from_jcc_opcode(0x70 + off).unwrap();
assert_eq!(std::mem::discriminant(cc), std::mem::discriminant(&decoded));
}
}
#[test] fn test_group1_extensions() { assert_eq!(lookup_group_extension(1, 0), "ADD"); assert_eq!(lookup_group_extension(1, 5), "SUB"); assert_eq!(lookup_group_extension(1, 7), "CMP"); }
#[test] fn test_group2_extensions() { assert_eq!(lookup_group_extension(2, 0), "ROL"); assert_eq!(lookup_group_extension(2, 4), "SHL"); assert_eq!(lookup_group_extension(2, 7), "SAR"); }
#[test] fn test_group3_extensions() { assert_eq!(lookup_group_extension(3, 0), "TEST"); assert_eq!(lookup_group_extension(3, 4), "MUL"); assert_eq!(lookup_group_extension(3, 7), "IDIV"); }
#[test] fn test_group5_extensions() { assert_eq!(lookup_group_extension(5, 2), "CALL"); assert_eq!(lookup_group_extension(5, 4), "JMP"); assert_eq!(lookup_group_extension(5, 6), "PUSH"); }
#[test] fn test_vector_length_vex_l() { assert!(!VectorLength::VL128.vex_l_bit()); assert!(VectorLength::VL256.vex_l_bit()); }
#[test] fn test_vector_length_evex_ll() { assert_eq!(VectorLength::VL512.evex_ll_bits(), (true, false)); assert_eq!(VectorLength::VL256.evex_ll_bits(), (false, true)); }
#[test] fn test_vector_length_element_count() { assert_eq!(VectorLength::VL128.element_count(4), 4); assert_eq!(VectorLength::VL256.element_count(8), 4); assert_eq!(VectorLength::VL512.element_count(4), 16); }
#[test] fn test_evex_tuple_multipliers() { assert_eq!(EvexTupleType::Full.multiplier(), 1); assert_eq!(EvexTupleType::Half.multiplier(), 2); assert_eq!(EvexTupleType::Quarter.multiplier(), 4); assert_eq!(EvexTupleType::Eighth.multiplier(), 8); }
#[test] fn test_evex_tuple_memory() { assert!(EvexTupleType::FullMem.is_memory()); assert!(!EvexTupleType::Full.is_memory()); }
#[test] fn test_evex_rounding_active() { assert!(EvexRoundingMode::RnSae.is_active()); assert!(EvexRoundingMode::Sae.has_sae()); assert!(!EvexRoundingMode::None.is_active()); }
#[test] fn test_evex_rounding_rc_bits() { assert_eq!(EvexRoundingMode::RnSae.rc_bits(), 0); assert_eq!(EvexRoundingMode::RdSae.rc_bits(), 1); assert_eq!(EvexRoundingMode::RzSae.rc_bits(), 3); }
#[test] fn test_evex_broadcast() { assert!(EvexBroadcastMode::Broadcast1To8.is_broadcast()); assert!(!EvexBroadcastMode::None.is_broadcast()); assert!(EvexBroadcastMode::Broadcast1To4.to_b_bit()); }
#[test] fn test_dispatch_encoding_vaddps_vex() {
let e = engine();
let v = e.dispatch_encoding("VADDPS", false, true, false, false);
assert!(!v.is_empty());
}
#[test] fn test_dispatch_encoding_add_legacy() {
let e = engine();
let v = e.dispatch_encoding("ADD", false, false, false, false);
assert!(!v.is_empty());
}
#[test] fn test_build_full_opcode_bytes() {
let e = engine();
let enc = e.lookup_primary(0x90).unwrap();
let bytes = e.build_full_opcode_bytes(enc);
assert_eq!(bytes, &[0x90]);
}
#[test] fn test_build_full_opcode_bytes_0f38() {
let e = engine();
let enc = e.lookup_0f38(0x00).unwrap();
let bytes = e.build_full_opcode_bytes(enc);
assert_eq!(bytes, &[0x0F, 0x38, 0x00]);
}
#[test] fn test_encoding_counts_by_category() {
let e = engine();
let cat = e.encoding_counts_by_category();
assert!(cat.total > 0);
let summary = cat.summary();
assert!(summary.contains("total="));
}
#[test] fn test_opcode_map_description_primary() { assert!(opcode_map_description(OpcodeMap::Primary).contains("Primary")); }
#[test] fn test_opcode_map_description_evex() { assert!(opcode_map_description(OpcodeMap::EvexMap1).contains("EVEX")); }
#[test] fn test_opcode_map_description_xop() { assert!(opcode_map_description(OpcodeMap::XopMap8).contains("XOP")); }
#[test] fn test_encoding_form_desc_legacy() { assert!(encoding_form_description(EncodingForm::Legacy).contains("Legacy")); }
#[test] fn test_encoding_form_desc_vex() { assert!(encoding_form_description(EncodingForm::VEX).contains("VEX")); }
#[test] fn test_encoding_form_desc_evex() { assert!(encoding_form_description(EncodingForm::EVEX).contains("EVEX")); }
#[test] fn test_all_rex_combinations() {
for &(byte, _name, w, r, x, b) in &ALL_REX_COMBINATIONS {
let decoded = decode_rex_prefix(byte).unwrap();
assert_eq!(decoded.0, w); assert_eq!(decoded.1, r); assert_eq!(decoded.2, x); assert_eq!(decoded.3, b);
}
}
#[test] fn test_all_legacy_prefixes_known() {
for &p in &ALL_LEGACY_PREFIXES {
if p == 0x00 { continue; }
assert!(p >= 0x26 && p <= 0xF3);
}
}
#[test] fn test_no_duplicate_primary_keys() {
let e = engine();
let mut seen = std::collections::HashSet::new();
for (i, entry) in e.opcode_map.primary.iter().enumerate() {
if entry.is_some() { assert!(seen.insert(i), "Duplicate primary opcode at {:02X}", i); }
}
}
#[test] fn test_no_duplicate_two_byte_keys() {
let e = engine();
let mut seen = std::collections::HashSet::new();
for (i, entry) in e.opcode_map.two_byte.iter().enumerate() {
if entry.is_some() { assert!(seen.insert(i), "Duplicate two-byte opcode at {:02X}", i); }
}
}
#[test] fn test_modrm_all_values_decode() {
for byte in 0..=255u8 {
let m = X86ModRMEncoding::mod_field(byte);
let r = X86ModRMEncoding::reg_field(byte);
let rm = X86ModRMEncoding::rm_field(byte);
assert!(m <= 3); assert!(r <= 7); assert!(rm <= 7);
let _ = X86ModRMEncoding::is_memory_reference(byte);
let _ = X86ModRMEncoding::is_register_reference(byte);
let _ = X86ModRMEncoding::disp_size(byte);
let _ = X86ModRMEncoding::needs_sib(byte);
let _ = ModRMAddressingMode::from_modrm(byte);
}
}
#[test] fn test_sib_all_values_decode() {
for byte in 0..=255u8 {
let s = X86SIBEncoding::scale_field(byte);
let i = X86SIBEncoding::index_field(byte);
let b = X86SIBEncoding::base_field(byte);
assert!(s <= 3); assert!(i <= 7); assert!(b <= 7);
let _ = X86SIBEncoding::has_index(byte);
let _ = X86SIBEncoding::is_absolute_disp32(byte);
let _ = SIBAddressingMode::from_sib_32(byte);
}
}
#[test] fn test_mov_has_many_variants() { assert!(engine().lookup_by_mnemonic("MOV").len() >= 8); }
#[test] fn test_push_has_many_variants() { assert!(engine().lookup_by_mnemonic("PUSH").len() >= 3); }
#[test] fn test_jmp_has_variants() { assert!(engine().lookup_by_mnemonic("JMP").len() >= 3); }
#[test] fn test_xor_exists() { assert!(!engine().lookup_by_mnemonic("XOR").is_empty()); }
#[test] fn test_syscall_exists() { assert!(!engine().lookup_by_mnemonic("SYSCALL").is_empty()); }
#[test] fn test_lea_exists() { assert!(!engine().lookup_by_mnemonic("LEA").is_empty()); }
#[test] fn test_vaddps_exists() { assert!(!engine().lookup_by_mnemonic("VADDPS").is_empty()); }
#[test] fn test_vzeroupper_exists() { assert!(!engine().lookup_by_mnemonic("VZEROUPPER").is_empty()); }
#[test] fn test_vbroadcastss_exists() { assert!(!engine().lookup_by_mnemonic("VBROADCASTSS").is_empty()); }
#[test] fn test_vpermd_exists() { assert!(!engine().lookup_by_mnemonic("VPERMD").is_empty()); }
#[test] fn test_vshuff32x4_exists() { assert!(!engine().lookup_by_mnemonic("VSHUFF32X4").is_empty()); }
#[test] fn test_vpaddd_exists() { assert!(!engine().lookup_by_mnemonic("VPADDD").is_empty()); }
#[test] fn test_vpmulld_exists() { assert!(!engine().lookup_by_mnemonic("VPMULLD").is_empty()); }
#[test] fn test_vprolvd_exists() { assert!(!engine().lookup_by_mnemonic("VPROLVD").is_empty()); }
#[test] fn test_vgetexpps_exists() { assert!(!engine().lookup_by_mnemonic("VGETEXPPS").is_empty()); }
#[test] fn test_vrcp14ps_exists() { assert!(!engine().lookup_by_mnemonic("VRCP14PS").is_empty()); }
#[test] fn test_vpmovm2b_exists() { assert!(!engine().lookup_by_mnemonic("VPMOVM2B").is_empty()); }
#[test] fn test_vpmadd52luq_exists() { assert!(!engine().lookup_by_mnemonic("VPMADD52LUQ").is_empty()); }
#[test] fn test_vpopcntb_exists() { assert!(!engine().lookup_by_mnemonic("VPOPCNTB").is_empty()); }
#[test] fn test_vgf2p8affineqb_exists() { assert!(!engine().lookup_by_mnemonic("VGF2P8AFFINEQB").is_empty()); }
#[test] fn test_vcvtph2ps_exists() { assert!(!engine().lookup_by_mnemonic("VCVTPH2PS").is_empty()); }
#[test] fn test_vgatherdps_exists() { assert!(!engine().lookup_by_mnemonic("VGATHERDPS").is_empty()); }
#[test] fn test_pshufb_exists() { assert!(!engine().lookup_by_mnemonic("PSHUFB").is_empty()); }
#[test] fn test_aesenc_exists() { assert!(!engine().lookup_by_mnemonic("AESENC").is_empty()); }
#[test] fn test_sha1rnds4_exists() { assert!(!engine().lookup_by_mnemonic("SHA1RNDS4").is_empty()); }
#[test] fn test_crc32_exists() { assert!(!engine().lookup_by_mnemonic("CRC32").is_empty()); }
#[test] fn test_adcx_exists() { assert!(!engine().lookup_by_mnemonic("ADCX").is_empty()); }
#[test] fn test_movbe_exists() { assert!(!engine().lookup_by_mnemonic("MOVBE").is_empty()); }
#[test] fn test_pclmulqdq_exists() { assert!(!engine().lookup_by_mnemonic("PCLMULQDQ").is_empty()); }
#[test] fn test_vex_entries_have_correct_map() {
let e = engine();
for entry in e.opcode_map.vex_map1.iter().flatten() {
assert!(matches!(entry.encoding_form, EncodingForm::VEX | EncodingForm::VEX3Byte));
assert!(matches!(entry.opcode_map, OpcodeMap::VexMap1));
}
}
#[test] fn test_evex_entries_have_correct_form() {
let e = engine();
for entry in e.opcode_map.evex_map1.iter().flatten() {
assert!(matches!(entry.encoding_form, EncodingForm::EVEX));
}
}
#[test] fn test_xop_entries_have_correct_form() {
let e = engine();
for entry in e.opcode_map.xop_map8.iter().flatten() {
assert!(matches!(entry.encoding_form, EncodingForm::XOP));
assert!(matches!(entry.opcode_map, OpcodeMap::XopMap8));
}
}
#[test] fn test_all_bswap_variants() {
let e = engine();
for i in 0..8u8 {
assert!(e.lookup_two_byte(0xC8 + i).is_some(), "Missing BSWAP at 0F {:02X}", 0xC8 + i);
}
}
#[test] fn test_all_16_jcc_rel8_present() {
let e = engine();
for i in 0..16u8 { assert!(e.lookup_primary(0x70 + i).is_some(), "Missing Jcc rel8 at {:02X}", 0x70 + i); }
}
#[test] fn test_all_16_jcc_rel32_present() {
let e = engine();
for i in 0..16u8 { assert!(e.lookup_two_byte(0x80 + i).is_some(), "Missing Jcc rel32 at 0F {:02X}", 0x80 + i); }
}
#[test] fn test_all_16_cmovcc_present() {
let e = engine();
for i in 0..16u8 { assert!(e.lookup_two_byte(0x40 + i).is_some(), "Missing CMOVcc at 0F {:02X}", 0x40 + i); }
}
#[test] fn test_all_16_setcc_present() {
let e = engine();
for i in 0..16u8 { assert!(e.lookup_two_byte(0x90 + i).is_some(), "Missing SETcc at 0F {:02X}", 0x90 + i); }
}
#[test] fn test_prefix_roundtrip_vex2() {
let pfx = X86PrefixEncoding::new().with_vex2(true, 0x0A, true, VEX_PP_66);
let bytes = pfx.encode_bytes();
assert_eq!(bytes.len(), 2);
assert_eq!(bytes[0], VEX_2BYTE);
}
#[test] fn test_prefix_roundtrip_evex_full() {
let pfx = X86PrefixEncoding::new().with_evex(true, false, true, false, true, false, true, true, 2, 1, true, 5, true, true);
let bytes = pfx.encode_bytes();
assert_eq!(bytes.len(), 4);
assert_eq!(bytes[0], EVEX_MAGIC);
}
#[test] fn test_opcode_map_vex_mmmmm_value() {
assert_eq!(OpcodeMap::VexMap1.vex_mmmmm(), VEX_MMMMM_0F);
assert_eq!(OpcodeMap::VexMap2.vex_mmmmm(), VEX_MMMMM_0F38);
assert_eq!(OpcodeMap::VexMap3.vex_mmmmm(), VEX_MMMMM_0F3A);
}
#[test] fn test_opcode_map_evex_mm_value() {
assert_eq!(OpcodeMap::EvexMap1.evex_mm(), 1);
assert_eq!(OpcodeMap::EvexMap2.evex_mm(), 2);
assert_eq!(OpcodeMap::EvexMap3.evex_mm(), 3);
assert_eq!(OpcodeMap::EvexMap5.evex_mm(), 5);
assert_eq!(OpcodeMap::EvexMap6.evex_mm(), 6);
assert_eq!(OpcodeMap::EvexMap7.evex_mm(), 7);
}
#[test] fn test_all_condition_codes_have_mnemonics() {
let ccs = [X86ConditionCode::O,X86ConditionCode::NO,X86ConditionCode::B,X86ConditionCode::NB,
X86ConditionCode::Z,X86ConditionCode::NZ,X86ConditionCode::BE,X86ConditionCode::A,
X86ConditionCode::S,X86ConditionCode::NS,X86ConditionCode::P,X86ConditionCode::NP,
X86ConditionCode::L,X86ConditionCode::GE,X86ConditionCode::LE,X86ConditionCode::G];
for cc in &ccs {
assert!(!cc.mnemonic_jcc().is_empty());
assert!(!cc.mnemonic_cmovcc().is_empty());
assert!(!cc.mnemonic_setcc().is_empty());
assert!(cc.jcc_opcode_offset() < 16);
}
}
#[test] fn test_reg_needs_rex() {
assert!(!reg_needs_rex_r(0));
assert!(reg_needs_rex_r(8));
assert!(!reg_needs_rex_b(0));
assert!(reg_needs_rex_b(8));
assert!(!reg_needs_rex_x(0));
assert!(reg_needs_rex_x(9));
}
#[test] fn test_vex_true_vvvv() {
let f = VexDecodedFields { vvvv: 0x0F};
assert_eq!(f.true_vvvv(), 0);
let f = VexDecodedFields { vvvv: 0x00};
assert_eq!(f.true_vvvv(), 0x0F);
}
#[test] fn test_evex_decoded_fields() {
let f = EvexDecodedFields { l_prime: true, l: false};
assert_eq!(f.vector_length(), 512);
let f = EvexDecodedFields { z: true, aaa: 7};
assert!(f.is_zeroing());
assert_eq!(f.opmask_reg(), 7);
}
}