osom_encoders_x86_64/models/
memory.rs

1use crate::models::{GPR, Immediate8, Immediate32};
2
3/// Represents the scale factor for the index register in a memory operand.
4///
5/// # Values
6///
7/// - `Scale1` - The index register is multiplied by 1.
8/// - `Scale2` - The index register is multiplied by 2.
9/// - `Scale4` - The index register is multiplied by 4.
10/// - `Scale8` - The index register is multiplied by 8.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12#[repr(u8)]
13#[must_use]
14pub enum Scale {
15    Scale1 = 1, // We start from 1 to allow Option<Scale> optimization
16    Scale2,
17    Scale4,
18    Scale8,
19}
20
21impl Scale {
22    #[inline(always)]
23    pub(crate) const fn index(self) -> u8 {
24        match self {
25            Self::Scale1 => 0b00,
26            Self::Scale2 => 0b01,
27            Self::Scale4 => 0b10,
28            Self::Scale8 => 0b11,
29        }
30    }
31}
32
33/// Represents the offset for a memory operand.
34///
35/// # Values
36///
37/// - `None` - No offset.
38/// - `Bit8` - 8-bit signed immediate offset.
39/// - `Bit32` - 32-bit signed immediate offset.
40///
41/// # Notes
42///
43/// The offset is always understood as signed integer.
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
45#[repr(u8)]
46#[must_use]
47pub enum Offset {
48    None,
49    Bit8(Immediate8),
50    Bit32(Immediate32),
51}
52
53impl Offset {
54    /// Converts the offset to a 32-bit signed immediate value.
55    ///
56    /// # Returns
57    ///
58    /// * `0` if offset is `None`.
59    /// * `Immediate32::from_imm8_sign_extended(offset)` if offset is `Bit8`.
60    /// * `offset` if offset is `Bit32`.
61    #[inline(always)]
62    pub const fn as_sign_extended_imm32(self) -> Immediate32 {
63        match self {
64            Self::None => Immediate32::from_u32(0),
65            Self::Bit8(imm8) => Immediate32::from_imm8_sign_extended(imm8),
66            Self::Bit32(imm32) => imm32,
67        }
68    }
69}
70
71impl Offset {
72    #[inline(always)]
73    pub const fn from_i8(value: i8) -> Self {
74        Self::Bit8(Immediate8::from_i8(value))
75    }
76
77    #[inline(always)]
78    pub const fn from_i32(value: i32) -> Self {
79        Self::Bit32(Immediate32::from_i32(value))
80    }
81}
82
83/// Represents a memory operand.
84///
85/// # Safety
86///
87/// Not all combinations of are valid for a given instruction.
88/// For specifics refer to the Intel x86 manual.
89///
90/// In particular all the GPRs have to be 64-bit wide.
91#[derive(Debug, Clone, PartialEq, Eq, Hash)]
92#[must_use]
93pub enum Memory {
94    /// Represents a based memory operand, i.e. `[base + offset]`.
95    Based { base: GPR, offset: Offset },
96
97    /// Represents a scaled memory operand, i.e. `[index * scale + offset]`.
98    ///
99    /// # Safety
100    ///
101    /// `index == GPR::RSP` is not allowed.
102    Scaled { index: GPR, scale: Scale, offset: Offset },
103
104    /// Represents a based scaled memory operand, i.e. `[base + index * scale + offset]`.
105    ///
106    /// # Safety
107    ///
108    /// `index == GPR::RSP` is not allowed.
109    BasedScaled {
110        base: GPR,
111        index: GPR,
112        scale: Scale,
113        offset: Offset,
114    },
115
116    /// Represents a RIP-relative memory operand, i.e. `[RIP + offset]`.
117    RelativeToRIP { offset: Offset },
118}
119
120#[must_use]
121pub(crate) struct BaseIndexIsExtended {
122    pub base_is_extended: bool,
123    pub index_is_extended: bool,
124}
125
126impl Memory {
127    #[inline(always)]
128    pub(crate) const fn base_index_is_extended(&self) -> BaseIndexIsExtended {
129        match self {
130            Self::Based { base, .. } => BaseIndexIsExtended {
131                base_is_extended: base.is_extended(),
132                index_is_extended: false,
133            },
134            Self::Scaled { index, .. } => BaseIndexIsExtended {
135                base_is_extended: false,
136                index_is_extended: index.is_extended(),
137            },
138            Self::BasedScaled { base, index, .. } => BaseIndexIsExtended {
139                base_is_extended: base.is_extended(),
140                index_is_extended: index.is_extended(),
141            },
142            Self::RelativeToRIP { .. } => BaseIndexIsExtended {
143                base_is_extended: false,
144                index_is_extended: false,
145            },
146        }
147    }
148}