juicebox_asm/
mem.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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
);