198 lines
5.0 KiB
Rust
198 lines
5.0 KiB
Rust
#[derive(Clone, Copy, PartialEq)]
|
|
pub struct Reg {
|
|
val: u8,
|
|
high: bool,
|
|
width: Width,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
|
#[repr(u8)]
|
|
pub enum Width {
|
|
B8 = 0,
|
|
B16 = 1,
|
|
B32 = 2,
|
|
B64 = 3,
|
|
}
|
|
|
|
def_regs! {
|
|
0b0000 : rax eax ax al,
|
|
0b0001 : rcx ecx cx cl !_,
|
|
0b0010 : rdx edx dx dl,
|
|
0b0011 : rbx ebx bx bl,
|
|
|
|
0b0100 : rsp esp sp spl norex=ah !_,
|
|
0b0101 : rbp ebp bp bpl norex=ch,
|
|
0b0110 : rsi esi si sil norex=dh !_,
|
|
0b0111 : rdi edi di dil norex=bh,
|
|
|
|
0b1000 : r8 r8d r8w r8b,
|
|
0b1001 : r9 r9d r9w r9b !_,
|
|
0b1010 : r10 r10d r10w r10b,
|
|
0b1011 : r11 r11d r11w r11b,
|
|
0b1100 : r12 r12d r12w r12b !_,
|
|
0b1101 : r13 r13d r13w r13b,
|
|
0b1110 : r14 r14d r14w r14b,
|
|
0b1111 : r15 r15d r15w r15b,
|
|
}
|
|
|
|
impl Reg {
|
|
pub fn base(&self) -> u8 {
|
|
self.val & 0b111
|
|
}
|
|
/// checks if register is not one of the first 8 (0-7)
|
|
pub fn gt8(&self) -> bool {
|
|
self.val >= 0b1000
|
|
}
|
|
pub fn gt4(&self) -> bool {
|
|
self.val >= 0b0100
|
|
}
|
|
|
|
pub fn width(&self) -> Width {
|
|
self.width
|
|
}
|
|
|
|
pub fn not8(&self) -> u8 {
|
|
self.width.not8()
|
|
}
|
|
|
|
pub fn high(&self) -> bool {
|
|
self.high
|
|
}
|
|
|
|
/// if self has 64 bit width, changes width to 32 bit
|
|
pub fn lower64(&self) -> Self {
|
|
let mut new = *self;
|
|
new.width = new.width.min(Width::B32);
|
|
new
|
|
}
|
|
|
|
pub fn requires_rex(&self) -> bool {
|
|
self.gt8()
|
|
|| self.width == Width::B64
|
|
|| (self.gt4() && self.width == Width::B8 && !self.high)
|
|
}
|
|
|
|
pub fn incompatible(&self, other: &Reg) -> bool {
|
|
(self.requires_rex() && other.high) || (self.high && other.requires_rex())
|
|
}
|
|
|
|
const fn new(val: u8, width: Width, high: bool) -> Self {
|
|
Self { val, high, width }
|
|
}
|
|
}
|
|
|
|
impl Width {
|
|
pub const fn max_val(&self) -> u64 {
|
|
match self {
|
|
Self::B64 => u64::MAX,
|
|
Self::B32 => u32::MAX as u64,
|
|
Self::B16 => u16::MAX as u64,
|
|
Self::B8 { .. } => u8::MAX as u64,
|
|
}
|
|
}
|
|
|
|
pub fn min(self, other: Self) -> Self {
|
|
if self <= other { self } else { other }
|
|
}
|
|
|
|
pub const fn bytes(&self) -> usize {
|
|
match self {
|
|
Self::B64 => 8,
|
|
Self::B32 => 4,
|
|
Self::B16 => 2,
|
|
Self::B8 { .. } => 1,
|
|
}
|
|
}
|
|
|
|
/// greater than 8 bits
|
|
pub const fn not8(&self) -> u8 {
|
|
!matches!(self, Self::B8) as u8
|
|
}
|
|
}
|
|
|
|
macro_rules! filter {
|
|
($($filtered:ident)*; ! $_:tt $($item:ident)*; $($rest:tt)*) => {
|
|
filter!($($filtered)* $($item)*; $($rest)*)
|
|
};
|
|
($($filtered:ident)*; $($item:ident)*; $($rest:tt)*) => {
|
|
filter!($($filtered)*; $($rest)*)
|
|
};
|
|
($($filtered:ident)*;) => {
|
|
[$($filtered, )*]
|
|
};
|
|
}
|
|
use filter;
|
|
|
|
macro_rules! def_regs {
|
|
($($val:literal : $B64:ident $B32:ident $B16:ident $B8:ident $(norex=$B8H:ident)? $(!$imp:tt)?,)*) => {
|
|
$(
|
|
#[allow(non_upper_case_globals)]
|
|
pub const $B64: Reg = Reg::new($val, Width::B64, false);
|
|
#[allow(non_upper_case_globals)]
|
|
pub const $B32: Reg = Reg::new($val, Width::B32, false);
|
|
#[allow(non_upper_case_globals)]
|
|
pub const $B16: Reg = Reg::new($val, Width::B16, false);
|
|
#[allow(non_upper_case_globals)]
|
|
pub const $B8 : Reg = Reg::new($val, Width::B8 , false);
|
|
$(
|
|
#[allow(non_upper_case_globals)]
|
|
pub const $B8H: Reg = Reg::new($val, Width::B8, true);
|
|
)?
|
|
)*
|
|
|
|
impl Reg {
|
|
// #[cfg(test)]
|
|
// pub const ALL: &[Reg] = &[
|
|
// $( $B64, $B32, $B16, $B8, $($B8H,)? )*
|
|
// ];
|
|
|
|
#[cfg(test)]
|
|
pub const IMPORTANT: &[Reg] = &
|
|
filter!(; $($(!$imp)? $B64 $B32 $B16 $B8 $($B8H)?; )* )
|
|
;
|
|
|
|
pub fn parse(s: &str) -> Option<Self> {
|
|
Some(match s.to_lowercase().as_str() {
|
|
$(
|
|
stringify!($B64) => $B64,
|
|
stringify!($B32) => $B32,
|
|
stringify!($B16) => $B16,
|
|
stringify!($B8 ) => $B8,
|
|
$(
|
|
stringify!($B8H) => $B8H,
|
|
)?
|
|
)*
|
|
_ => return None,
|
|
})
|
|
}
|
|
}
|
|
impl std::fmt::Display for Reg {
|
|
#[allow(non_upper_case_globals)]
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "{}", match *self {
|
|
$(
|
|
$B64 => stringify!($B64),
|
|
$B32 => stringify!($B32),
|
|
$B16 => stringify!($B16),
|
|
$B8 => stringify!($B8),
|
|
$(
|
|
$B8H => stringify!($B8H),
|
|
)?
|
|
)*
|
|
_ => "UNKNOWN",
|
|
})
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
use def_regs;
|
|
|
|
use crate::arch::x86_64::Imm;
|
|
|
|
impl From<Reg> for Width {
|
|
fn from(value: Reg) -> Self {
|
|
value.width
|
|
}
|
|
}
|