use crate::core::operand::RegType;
use super::opcode::Opcode;
pub const X86_BYTE_REX: u8 = 0x40;
pub const X86_BYTE_REX_W: u8 = 0x08;
pub const X86_BYTE_INVALID_REX: u8 = 0x80;
pub const X86_BYTE_VEX2: u8 = 0xC5;
pub const X86_BYTE_VEX3: u8 = 0xC4;
pub const X86_BYTE_XOP3: u8 = 0x8F;
pub const X86_BYTE_EVEX: u8 = 0x62;
pub const VEX_VVVVV_SHIFT: u32 = 7;
pub static OPCODE_PP_TABLE: [u8; 8] = [0x00, 0x66, 0xF3, 0xF2, 0x00, 0x00, 0x00, 0x9B];
#[derive(Clone, Copy, Debug, Default)]
pub struct X86OpcodeMm {
pub size: u8,
pub data: [u8; 3],
}
impl X86OpcodeMm {
pub const fn new(size: u8, data: [u8; 3]) -> Self {
Self { size, data }
}
}
#[rustfmt::skip]
pub static OPCODE_MM_TABLE: [X86OpcodeMm; 16] = [
X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(1, [0x0F, 0x00, 0]), X86OpcodeMm::new(2, [0x0F, 0x38, 0]), X86OpcodeMm::new(2, [0x0F, 0x3A, 0]), X86OpcodeMm::new(2, [0x0F, 0x01, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), X86OpcodeMm::new(0, [0x00, 0x00, 0]), ];
#[rustfmt::skip]
pub static SEGMENT_PREFIX_TABLE: [u8; 8] = [
0x00, 0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65, 0x00, ];
#[rustfmt::skip]
pub static OPCODE_PUSH_SREG_TABLE: [u32; 8] = [
Opcode::K000000, Opcode::K000000 | 0x06, Opcode::K000000 | 0x0E, Opcode::K000000 | 0x16, Opcode::K000000 | 0x1E, Opcode::K000F00 | 0xA0, Opcode::K000F00 | 0xA8, 0,
];
#[rustfmt::skip]
pub static OPCODE_POP_SREG_TABLE: [u32; 8] = [
Opcode::K000000, Opcode::K000000 | 0x07, Opcode::K000000, Opcode::K000000 | 0x17, Opcode::K000000 | 0x1F, Opcode::K000F00 | 0xA1, Opcode::K000F00 | 0xA9, 0,
];
pub const MEM_INFO_BASE_GP: u8 = 0x01;
pub const MEM_INFO_INDEX: u8 = 0x02;
pub const MEM_INFO_BASE_LABEL: u8 = 0x10;
pub const MEM_INFO_BASE_RIP: u8 = 0x20;
pub const MEM_INFO_67H_X86: u8 = 0x40;
pub const MEM_INFO_67H_X64: u8 = 0x80;
const fn mem_info(x: u32) -> u8 {
let b = x & 0x1F;
let i = (x >> 5) & 0x1F;
let (gp16, gp32, gp64, vec128, vec256, vec512) = (
RegType::Gp16 as u32,
RegType::Gp32 as u32,
RegType::Gp64 as u32,
RegType::Vec128 as u32,
RegType::Vec256 as u32,
RegType::Vec512 as u32,
);
let base = if b >= gp16 && b <= gp64 {
MEM_INFO_BASE_GP
} else if b == RegType::PC as u32 {
MEM_INFO_BASE_RIP
} else if b == RegType::LabelTag as u32 {
MEM_INFO_BASE_LABEL
} else {
0
};
let index = if (i >= gp16 && i <= gp64) || (i >= vec128 && i <= vec512) {
MEM_INFO_INDEX
} else {
0
};
let h67 = if (b == gp16 && i == RegType::None as u32)
|| (b == RegType::None as u32 && i == gp16)
|| (b == gp16 && i == gp16)
|| (b == gp16 && i == vec128)
|| (b == gp16 && i == vec256)
|| (b == gp16 && i == vec512)
|| (b == RegType::LabelTag as u32 && i == gp16)
{
MEM_INFO_67H_X86
} else if (b == gp32 && i == RegType::None as u32)
|| (b == RegType::None as u32 && i == gp32)
|| (b == gp32 && i == gp32)
|| (b == gp32 && i == vec128)
|| (b == gp32 && i == vec256)
|| (b == gp32 && i == vec512)
|| (b == RegType::LabelTag as u32 && i == gp32)
{
MEM_INFO_67H_X64
} else {
0
};
base | index | h67 | 0x04 | 0x08
}
pub static MEM_INFO_TABLE: [u8; 1024] = {
let mut table = [0u8; 1024];
let mut x = 0usize;
while x < 1024 {
table[x] = mem_info(x as u32);
x += 1;
}
table
};
pub static VEX_PREFIX_TABLE: [u32; 16] = {
let mut table = [0u32; 16];
let mut x = 0usize;
while x < 16 {
table[x] = (if x & 0x08 != 0 {
X86_BYTE_XOP3 as u32
} else {
X86_BYTE_VEX3 as u32
}) | (0xF << 19)
| (0x7 << 13);
x += 1;
}
table
};
pub static LL_BY_SIZE_DIV_16_TABLE: [u32; 16] = {
let mut table = [0u32; 16];
let mut x = 0usize;
while x < 16 {
table[x] = if x & (64 >> 4) != 0 {
2 << Opcode::LL_SHIFT
} else if x & (32 >> 4) != 0 {
1 << Opcode::LL_SHIFT
} else {
0
};
x += 1;
}
table
};
pub static LL_BY_REG_TYPE_TABLE: [u32; 16] = {
let mut table = [0u32; 16];
let mut x = 0usize;
while x < 16 {
table[x] = if x == RegType::Vec512 as usize {
2 << Opcode::LL_SHIFT
} else if x == RegType::Vec256 as usize {
1 << Opcode::LL_SHIFT
} else {
0
};
x += 1;
}
table
};
pub static CDISP8_SHL_TABLE: [u32; 32] = {
let mut table = [0u32; 32];
let mut x = 0usize;
while x < 32 {
let tt = (x >> 3) as u32;
let ll = (x & 0x3) as u32;
let w = ((x >> 2) & 0x1) as u32;
let shift = match tt {
0 => 0, 1 => {
if ll == 0 {
0
} else if ll == 1 {
1
} else {
2
}
} 2 => {
if ll == 0 {
w
} else if ll == 1 {
1 + w
} else {
2 + w
}
} 3 => {
if ll == 0 {
0
} else if ll == 1 {
2
} else {
3
}
} _ => unreachable!(),
};
table[x] = shift << Opcode::CDSHL_SHIFT;
x += 1;
}
table
};
#[rustfmt::skip]
pub static MOD16_BASE_TABLE: [u8; 8] = [
0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0x06, 0x04, 0x05, ];
pub static MOD16_BASE_INDEX_TABLE: [u8; 64] = {
const BX: u32 = 3;
const BP: u32 = 5;
const SI: u32 = 6;
const DI: u32 = 7;
let mut table = [0xFFu8; 64];
let mut x = 0usize;
while x < 64 {
let b = (x >> 3) as u32;
let i = (x & 0x7) as u32;
table[x] = if (b == BX && i == SI) || (b == SI && i == BX) {
0x00
} else if (b == BX && i == DI) || (b == DI && i == BX) {
0x01
} else if (b == BP && i == SI) || (b == SI && i == BP) {
0x02
} else if (b == BP && i == DI) || (b == DI && i == BP) {
0x03
} else {
0xFF
};
x += 1;
}
table
};
#[rustfmt::skip]
#[cfg(test)]
pub static NOP_TABLE: [[u8; 9]; 9] = [
[0x90, 0, 0, 0, 0, 0, 0, 0, 0],
[0x66, 0x90, 0, 0, 0, 0, 0, 0, 0],
[0x0F, 0x1F, 0x00, 0, 0, 0, 0, 0, 0],
[0x0F, 0x1F, 0x40, 0x00, 0, 0, 0, 0, 0],
[0x0F, 0x1F, 0x44, 0x00, 0x00, 0, 0, 0, 0],
[0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00, 0, 0, 0],
[0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00, 0, 0],
[0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0],
[0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00],
];
#[cfg(test)]
mod tests {
use super::*;
const fn rt(t: RegType) -> u32 {
t as u32
}
#[test]
fn mem_info_spot_checks() {
let (gp16, gp32, gp64, vec256) = (
rt(RegType::Gp16),
rt(RegType::Gp32),
rt(RegType::Gp64),
rt(RegType::Vec256),
);
let at = |b: u32, i: u32| MEM_INFO_TABLE[(b | (i << 5)) as usize];
assert_eq!(at(0, 0), 0x04 | 0x08);
assert_eq!(at(gp64, 0), MEM_INFO_BASE_GP | 0x04 | 0x08);
assert_eq!(at(gp16, 0), MEM_INFO_BASE_GP | MEM_INFO_67H_X86 | 0x0C);
assert_eq!(
at(gp32, vec256),
MEM_INFO_BASE_GP | MEM_INFO_INDEX | MEM_INFO_67H_X64 | 0x0C
);
assert_eq!(at(rt(RegType::PC), 0), MEM_INFO_BASE_RIP | 0x0C);
assert_eq!(
at(rt(RegType::LabelTag), gp32),
MEM_INFO_BASE_LABEL | MEM_INFO_INDEX | MEM_INFO_67H_X64 | 0x0C
);
}
#[test]
fn ll_tables() {
assert_eq!(LL_BY_SIZE_DIV_16_TABLE[1], 0);
assert_eq!(LL_BY_SIZE_DIV_16_TABLE[2], 1 << Opcode::LL_SHIFT);
assert_eq!(LL_BY_SIZE_DIV_16_TABLE[4], 2 << Opcode::LL_SHIFT);
assert_eq!(
LL_BY_REG_TYPE_TABLE[RegType::Vec512 as usize],
2 << Opcode::LL_SHIFT
);
assert_eq!(
LL_BY_REG_TYPE_TABLE[RegType::Vec256 as usize],
1 << Opcode::LL_SHIFT
);
assert_eq!(LL_BY_REG_TYPE_TABLE[RegType::Vec128 as usize], 0);
}
#[test]
fn cdisp8_shl_spot_checks() {
assert_eq!(CDISP8_SHL_TABLE[0], 0);
assert_eq!(CDISP8_SHL_TABLE[8], 0);
assert_eq!(CDISP8_SHL_TABLE[9], 1 << Opcode::CDSHL_SHIFT);
assert_eq!(CDISP8_SHL_TABLE[11], 2 << Opcode::CDSHL_SHIFT);
assert_eq!(CDISP8_SHL_TABLE[24], 0);
assert_eq!(CDISP8_SHL_TABLE[25], 2 << Opcode::CDSHL_SHIFT);
assert_eq!(CDISP8_SHL_TABLE[26], 3 << Opcode::CDSHL_SHIFT);
}
#[test]
fn mod16_tables() {
assert_eq!(MOD16_BASE_TABLE[3], 0x07); assert_eq!(MOD16_BASE_TABLE[0], 0xFF); assert_eq!(MOD16_BASE_INDEX_TABLE[(3 << 3) | 6], 0x00); assert_eq!(MOD16_BASE_INDEX_TABLE[(7 << 3) | 5], 0x03); assert_eq!(MOD16_BASE_INDEX_TABLE[0], 0xFF);
}
}