diff options
Diffstat (limited to 'src/mem.rs')
-rw-r--r-- | src/mem.rs | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/mem.rs b/src/mem.rs new file mode 100644 index 0000000..6a87eb8 --- /dev/null +++ b/src/mem.rs @@ -0,0 +1,116 @@ +//! Definition of different addressing modes and memory operande used as input +//! and ouput operands in various instructions. + +use crate::Reg64; + +#[derive(Clone, Copy)] +pub(crate) enum AddrMode { + /// An indirect memory operand, eg `mov [rax], rcx`. + Indirect, + /// An indirect memory operand with additional displacement, eg `mov [rax + 0x10], rcx`. + IndirectDisp, + /// An indirect memory operand in the form base + index, eg `mov [rax + rcx], rdx`. + IndirectBaseIndex, +} + +/// Trait to interact with memory operands. +pub(crate) trait Mem { + /// Get the addressing mode [`AddrMode`] of the memory operand. + fn mode(&self) -> AddrMode; + + /// Get the base address register of the memory operand. + fn base(&self) -> Reg64; + + /// Get the index register of the memory operand. + fn index(&self) -> Reg64; + + /// Get the displacement of the memory operand. + fn disp(&self) -> i32; + + /// Check if memory operand is 64 bit. + fn is_64() -> bool; +} + +macro_rules! impl_mem { + ($(#[$doc:meta] $name:ident)+) => { + $( + #[$doc] + pub struct $name { + mode: AddrMode, + base: Reg64, + index: Reg64, + disp: i32, + } + + impl Mem for $name { + fn mode(&self) -> AddrMode { + self.mode + } + + fn base(&self) -> Reg64 { + self.base + } + + fn index(&self) -> Reg64 { + self.index + } + + fn disp(&self) -> i32 { + self.disp + } + + fn is_64() -> bool { + use std::any::TypeId; + TypeId::of::<Self>() == TypeId::of::<Mem64>() + } + } + + impl $name { + /// Create a memory operand with `indirect` addressing mode. + /// For example `mov [rax], rcx`. + pub fn indirect(base: Reg64) -> Self { + Self { + mode: AddrMode::Indirect, + base, + index: Reg64::rax, /* zero index */ + disp: 0, + } + } + + /// Create a memory operand with `indirect + displacement` + /// addressing mode. + /// For example `mov [rax + 0x10], rcx`. + pub fn indirect_disp(base: Reg64, disp: i32) -> Self { + Self { + mode: AddrMode::IndirectDisp, + base, + index: Reg64::rax, /* zero index */ + disp, + } + } + + /// Create a memory operand with `base + index` addressing mode. + /// For example `mov [rax + rcx], rdx`. + pub fn indirect_base_index(base: Reg64, index: Reg64) -> Self { + Self { + mode: AddrMode::IndirectBaseIndex, + base, + index, + disp: 0, + } + } + } + )+ + } +} + +impl_mem!( + /// A memory operand with `byte` size (8 bit). + Mem8 + /// A memory operand with `word` size (16 bit). + Mem16 + /// A memory operand with `dword` size (32 bit). + Mem32 + /// A memory operand with `qword` size (64 bit). + Mem64 +); |