I thought I might be able to make it easier with macro in exchange for readability, but the current (v1.72) rustc does not seem to be able to pattern match on range (e.g. 0..10
), so this seems to be strictly possible only with proc_macro.
use crate::error::{bail, Result};
use seq_macro::seq;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) struct Register {
pub(crate) lit: &'static str,
pub(crate) size: DataSizeSuffix,
pub(crate) base_offset: u8,
/// Need rex prefix?
pub(crate) rex_required: bool,
}
#[derive(Clone, Debug, Copy, Default, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum DataSizeSuffix {
Byte,
Word,
Long,
Quad,
#[default]
Unknown,
}
macro_rules! register_tuple {
(0, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "AX"), 0, $size) };
(1, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "CX"), 1, $size) };
(2, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "DX"), 2, $size) };
(3, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "BX"), 3, $size) };
(4, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "SP"), 4, $size) };
(5, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "BP"), 5, $size) };
(6, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "SI"), 6, $size) };
(7, $size:expr $(, $prefix:tt)?) => { register_tuple!(concat!($($prefix,)? "DI"), 7, $size) };
($lit:expr, $base_offset:expr, $size:expr) => {
register_tuple!($lit, $base_offset, $size, false)
};
($lit:expr, $base_offset:expr, $size:expr, $rex_required:expr) => {
(
$lit,
Register {
lit: $lit,
base_offset: $base_offset,
size: $size,
rex_required: $rex_required,
},
)
};
}
#[rustfmt::skip]
macro_rules! gpr_64bit_tuple {
(0) => { register_tuple!(0, DataSizeSuffix::Quad, "R") };
(1) => { register_tuple!(1, DataSizeSuffix::Quad, "R") };
(2) => { register_tuple!(2, DataSizeSuffix::Quad, "R") };
(3) => { register_tuple!(3, DataSizeSuffix::Quad, "R") };
(4) => { register_tuple!(4, DataSizeSuffix::Quad, "R") };
(5) => { register_tuple!(5, DataSizeSuffix::Quad, "R") };
(6) => { register_tuple!(6, DataSizeSuffix::Quad, "R") };
(7) => { register_tuple!(7, DataSizeSuffix::Quad, "R") };
($size:tt) => {
register_tuple!(concat!("R", $size), $size, DataSizeSuffix::Quad)
};
}
#[rustfmt::skip]
macro_rules! gpr_32bit_tuple {
(0) => { register_tuple!(0, DataSizeSuffix::Long, "E") };
(1) => { register_tuple!(1, DataSizeSuffix::Long, "E") };
(2) => { register_tuple!(2, DataSizeSuffix::Long, "E") };
(3) => { register_tuple!(3, DataSizeSuffix::Long, "E") };
(4) => { register_tuple!(4, DataSizeSuffix::Long, "E") };
(5) => { register_tuple!(5, DataSizeSuffix::Long, "E") };
(6) => { register_tuple!(6, DataSizeSuffix::Long, "E") };
(7) => { register_tuple!(7, DataSizeSuffix::Long, "E") };
($size:tt) => {
register_tuple!(concat!("R", $size, "D"), $size, DataSizeSuffix::Long)
};
}
#[rustfmt::skip]
macro_rules! gpr_16bit_tuple {
(0) => { register_tuple!(0, DataSizeSuffix::Word) };
(1) => { register_tuple!(1, DataSizeSuffix::Word) };
(2) => { register_tuple!(2, DataSizeSuffix::Word) };
(3) => { register_tuple!(3, DataSizeSuffix::Word) };
(4) => { register_tuple!(4, DataSizeSuffix::Word) };
(5) => { register_tuple!(5, DataSizeSuffix::Word) };
(6) => { register_tuple!(6, DataSizeSuffix::Word) };
(7) => { register_tuple!(7, DataSizeSuffix::Word) };
($size:tt) => {
gpr_16bit_tuple!(concat!("R", stringify!($size), "W"), $size)
};
($lit:expr, $size:tt) => {
register_tuple!($lit, $size, DataSizeSuffix::Word)
};
}
macro_rules! gpr_8bit_tuple {
($lit:tt) => {
register_tuple!(concat!("R", $lit, "B"), $lit, DataSizeSuffix::Byte)
};
}
#[rustfmt::skip]
const GENERAL_REGISTERS: [(&str, Register); 72] = [
// 64bit
register_tuple!( "RAX", 0, DataSizeSuffix::Quad),
register_tuple!( "RCX", 1, DataSizeSuffix::Quad),
register_tuple!( "RDX", 2, DataSizeSuffix::Quad),
register_tuple!( "RBX", 3, DataSizeSuffix::Quad),
register_tuple!( "RSP", 4, DataSizeSuffix::Quad),
register_tuple!( "RBP", 5, DataSizeSuffix::Quad),
register_tuple!( "RSI", 6, DataSizeSuffix::Quad),
register_tuple!( "RDI", 7, DataSizeSuffix::Quad),
register_tuple!( "R8", 8, DataSizeSuffix::Quad),
register_tuple!( "R9", 9, DataSizeSuffix::Quad),
register_tuple!( "R10", 10, DataSizeSuffix::Quad),
register_tuple!( "R11", 11, DataSizeSuffix::Quad),
register_tuple!( "R12", 12, DataSizeSuffix::Quad),
register_tuple!( "R13", 13, DataSizeSuffix::Quad),
register_tuple!( "R14", 14, DataSizeSuffix::Quad),
register_tuple!( "R15", 15, DataSizeSuffix::Quad),
// 32bit
register_tuple!( "EAX", 0, DataSizeSuffix::Long),
register_tuple!( "ECX", 1, DataSizeSuffix::Long),
register_tuple!( "EDX", 2, DataSizeSuffix::Long),
register_tuple!( "EBX", 3, DataSizeSuffix::Long),
register_tuple!( "ESP", 4, DataSizeSuffix::Long),
register_tuple!( "EBP", 5, DataSizeSuffix::Long),
register_tuple!( "ESI", 6, DataSizeSuffix::Long),
register_tuple!( "EDI", 7, DataSizeSuffix::Long),
register_tuple!( "R8D", 8, DataSizeSuffix::Long),
register_tuple!( "R9D", 9, DataSizeSuffix::Long),
register_tuple!("R10D", 10, DataSizeSuffix::Long),
register_tuple!("R11D", 11, DataSizeSuffix::Long),
register_tuple!("R12D", 12, DataSizeSuffix::Long),
register_tuple!("R13D", 13, DataSizeSuffix::Long),
register_tuple!("R14D", 14, DataSizeSuffix::Long),
register_tuple!("R15D", 15, DataSizeSuffix::Long),
// 16bit
register_tuple!( "AX", 0, DataSizeSuffix::Word),
register_tuple!( "CX", 1, DataSizeSuffix::Word),
register_tuple!( "DX", 2, DataSizeSuffix::Word),
register_tuple!( "BX", 3, DataSizeSuffix::Word),
register_tuple!( "SP", 4, DataSizeSuffix::Word),
register_tuple!( "BP", 5, DataSizeSuffix::Word),
register_tuple!( "SI", 6, DataSizeSuffix::Word),
register_tuple!( "DI", 7, DataSizeSuffix::Word),
register_tuple!( "R8W", 8, DataSizeSuffix::Word),
register_tuple!( "R9W", 9, DataSizeSuffix::Word),
register_tuple!("R10W", 10, DataSizeSuffix::Word),
register_tuple!("R11W", 11, DataSizeSuffix::Word),
register_tuple!("R12W", 12, DataSizeSuffix::Word),
register_tuple!("R13W", 13, DataSizeSuffix::Word),
register_tuple!("R14W", 14, DataSizeSuffix::Word),
register_tuple!("R15W", 15, DataSizeSuffix::Word),
// 8bit
register_tuple!( "AL", 0, DataSizeSuffix::Byte),
register_tuple!( "CL", 1, DataSizeSuffix::Byte),
register_tuple!( "DL", 2, DataSizeSuffix::Byte),
register_tuple!( "BL", 3, DataSizeSuffix::Byte),
register_tuple!( "AH", 4, DataSizeSuffix::Byte),
register_tuple!( "BP", 5, DataSizeSuffix::Byte),
register_tuple!( "CH", 5, DataSizeSuffix::Byte),
register_tuple!( "DH", 6, DataSizeSuffix::Byte),
register_tuple!( "BH", 7, DataSizeSuffix::Byte),
register_tuple!( "SPL", 4, DataSizeSuffix::Byte, true),
register_tuple!( "BPL", 5, DataSizeSuffix::Byte, true),
register_tuple!( "SIL", 6, DataSizeSuffix::Byte, true),
register_tuple!( "DIL", 7, DataSizeSuffix::Byte, true),
register_tuple!( "R8B", 8, DataSizeSuffix::Byte),
register_tuple!( "R9B", 9, DataSizeSuffix::Byte),
register_tuple!("R10B", 10, DataSizeSuffix::Byte),
register_tuple!("R11B", 11, DataSizeSuffix::Byte),
register_tuple!("R12B", 12, DataSizeSuffix::Byte),
register_tuple!("R13B", 13, DataSizeSuffix::Byte),
register_tuple!("R14B", 14, DataSizeSuffix::Byte),
register_tuple!("R15B", 15, DataSizeSuffix::Byte),
// instruction pointers(counter)
register_tuple!( "RIP", 0, DataSizeSuffix::Quad),
register_tuple!( "EIP", 0, DataSizeSuffix::Long),
register_tuple!( "IP", 0, DataSizeSuffix::Word),
];
macro_rules! xmm_entry {
($index:expr) => {
(
concat!("XMM", stringify!($index)),
Register {
lit: concat!("XMM", stringify!($index)),
base_offset: $index,
size: DataSizeSuffix::Unknown,
rex_required: false,
},
)
};
}
seq!(N in 0..16 {
const XMM_REGISTERS: [(&str, Register); 16] = [
#(xmm_entry!(N),)*
];
});
/// Get(Copy) general register from GENERAL global const by str key.
pub(crate) fn get_reg_by(key: &str) -> Result<Register> {
let e = GENERAL_REGISTERS
.binary_search_by(|(k, _)| k.cmp(&key))
.map(|x| GENERAL_REGISTERS[x].1);
match e {
Ok(v) => Ok(v),
Err(l) => bail!("Couldn't find register. index: {}", l),
}
}
/// Get(Copy) XMM register from XMM global const by str key.
pub(crate) fn get_xmm_by(key: &str) -> Result<Register> {
let e = XMM_REGISTERS
.binary_search_by(|(k, _)| k.cmp(&key))
.map(|x| XMM_REGISTERS[x].1);
match e {
Ok(v) => Ok(v),
Err(l) => bail!("Couldn't find register. index: {}", l),
}
}
#[test]
fn show_registers() {
dbg!(GENERAL_REGISTERS);
// dbg!(XMM_REGISTERS);
}