osom_asm_x86_64/models/
memory.rs1use osom_encoders_x86_64::models as enc_models;
2
3use super::{GPR, Immediate, Label, Scale, Size};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6#[must_use]
7#[repr(u8)]
8pub(crate) enum MemoryImpl {
9 Based {
10 base: GPR,
11 offset: Immediate,
12 },
13 Scaled {
14 index: GPR,
15 scale: Scale,
16 offset: Immediate,
17 },
18 BasedScaled {
19 base: GPR,
20 index: GPR,
21 scale: Scale,
22 offset: Immediate,
23 },
24 Label {
25 label: Label,
26 },
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, Hash)]
31#[must_use]
32#[repr(transparent)]
33pub struct Memory {
34 value: MemoryImpl,
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Hash)]
38#[repr(u8)]
39#[must_use]
40pub enum NewMemoryError {
41 GPRNotBit64,
42 RSPNotAllowedAsIndex,
43}
44
45impl Memory {
46 #[inline]
47 pub fn based(base: GPR, offset: Immediate) -> Result<Self, NewMemoryError> {
48 if base.size() != Size::Bit64 {
49 return Err(NewMemoryError::GPRNotBit64);
50 }
51
52 Ok(Self {
53 value: MemoryImpl::Based { base, offset },
54 })
55 }
56
57 #[inline]
58 pub fn scaled(index: GPR, scale: Scale, offset: Immediate) -> Result<Self, NewMemoryError> {
59 if index.size() != Size::Bit64 {
60 return Err(NewMemoryError::GPRNotBit64);
61 }
62
63 if index == GPR::RSP {
64 return Err(NewMemoryError::RSPNotAllowedAsIndex);
65 }
66
67 Ok(Self {
68 value: MemoryImpl::Scaled { index, scale, offset },
69 })
70 }
71
72 #[inline]
73 pub fn based_scaled(base: GPR, index: GPR, scale: Scale, offset: Immediate) -> Result<Self, NewMemoryError> {
74 if base.size() != Size::Bit64 {
75 return Err(NewMemoryError::GPRNotBit64);
76 }
77
78 if index.size() != Size::Bit64 {
79 return Err(NewMemoryError::GPRNotBit64);
80 }
81
82 if index == GPR::RSP {
83 return Err(NewMemoryError::RSPNotAllowedAsIndex);
84 }
85
86 Ok(Self {
87 value: MemoryImpl::BasedScaled {
88 base,
89 index,
90 scale,
91 offset,
92 },
93 })
94 }
95
96 #[inline(always)]
98 pub const fn label(label: Label) -> Self {
99 Self {
100 value: MemoryImpl::Label { label },
101 }
102 }
103
104 #[inline(always)]
105 pub(crate) fn get_label(&self) -> Option<&Label> {
106 match &self.value {
107 MemoryImpl::Label { label } => Some(label),
108 _ => None,
109 }
110 }
111
112 pub(crate) fn as_enc_mem(&self) -> enc_models::Memory {
113 const fn imm_to_offset(offset: Immediate) -> enc_models::Offset {
114 let val = offset.value();
115 if val == 0 {
116 return enc_models::Offset::None;
117 }
118
119 match offset.real_size() {
120 Size::Bit8 => enc_models::Offset::Bit8(enc_models::Immediate8::from_i8(val as i8)),
121 Size::Bit16 | Size::Bit32 => enc_models::Offset::Bit32(enc_models::Immediate32::from_i32(val)),
122 _ => panic!("Invalid offset size"),
123 }
124 }
125
126 match &self.value {
127 MemoryImpl::Based { base, offset } => enc_models::Memory::Based {
128 base: base.as_enc_gpr(),
129 offset: imm_to_offset(*offset),
130 },
131 MemoryImpl::Scaled { index, scale, offset } => enc_models::Memory::Scaled {
132 index: index.as_enc_gpr(),
133 scale: scale.as_enc_scale(),
134 offset: imm_to_offset(*offset),
135 },
136 MemoryImpl::BasedScaled {
137 base,
138 index,
139 scale,
140 offset,
141 } => enc_models::Memory::BasedScaled {
142 base: base.as_enc_gpr(),
143 index: index.as_enc_gpr(),
144 scale: scale.as_enc_scale(),
145 offset: imm_to_offset(*offset),
146 },
147 MemoryImpl::Label { label: _ } => {
148 enc_models::Memory::RelativeToRIP {
150 offset: enc_models::Offset::None,
151 }
152 }
153 }
154 }
155}