elf_assembler/assembler/x64/
context.rs1use std::collections::HashMap;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum X64Register {
10 RAX,
12 RBX,
13 RCX,
14 RDX,
15 RSI,
16 RDI,
17 RBP,
18 RSP,
19 R8,
20 R9,
21 R10,
22 R11,
23 R12,
24 R13,
25 R14,
26 R15,
27
28 EAX,
30 EBX,
31 ECX,
32 EDX,
33 ESI,
34 EDI,
35 EBP,
36 ESP,
37 R8D,
39 R9D,
41 R10D,
43 R11D,
45 R12D,
47 R13D,
49 R14D,
51 R15D,
53}
54
55#[derive(Debug, Clone)]
57pub struct Label {
58 pub name: String,
60 pub offset: Option<usize>,
62 pub fixup_locations: Vec<usize>,
64}
65
66#[derive(Debug, Clone)]
68pub struct RelocationInfo {
69 pub offset: usize,
71 pub reloc_type: RelocationType,
73 pub symbol: String,
75}
76
77#[derive(Debug, Clone, Copy)]
79pub enum RelocationType {
80 Rel32,
82 Abs64,
84 RipRel32,
86}
87
88#[derive(Debug, Clone)]
90pub struct FunctionCall {
91 pub name: String,
93 pub call_offset: usize,
95 pub is_import: bool,
97}
98
99#[derive(Debug)]
101pub struct X64Context {
102 pub code: Vec<u8>,
104
105 pub stack_offset: i32,
107
108 pub labels: HashMap<String, Label>,
110
111 pub relocations: Vec<RelocationInfo>,
113
114 pub function_calls: Vec<FunctionCall>,
116
117 pub string_constants: HashMap<String, usize>,
119
120 pub register_usage: HashMap<X64Register, bool>,
122
123 pub stack_size: u32,
125}
126
127impl X64Context {
128 pub fn new() -> Self {
130 Self {
131 code: Vec::new(),
132 stack_offset: 0,
133 labels: HashMap::new(),
134 relocations: Vec::new(),
135 function_calls: Vec::new(),
136 string_constants: HashMap::new(),
137 register_usage: HashMap::new(),
138 stack_size: 0,
139 }
140 }
141
142 pub fn emit_bytes(&mut self, bytes: &[u8]) {
144 self.code.extend_from_slice(bytes);
145 }
146
147 pub fn current_position(&self) -> usize {
149 self.code.len()
150 }
151
152 pub fn define_label(&mut self, name: &str) {
154 let offset = self.current_position();
155
156 if let Some(label) = self.labels.get_mut(name) {
157 label.offset = Some(offset);
159 self.fixup_label(name, offset);
160 }
161 else {
162 self.labels
164 .insert(name.to_string(), Label { name: name.to_string(), offset: Some(offset), fixup_locations: Vec::new() });
165 }
166 }
167
168 pub fn reference_label(&mut self, name: &str) -> usize {
170 let current_pos = self.current_position();
171
172 if let Some(label) = self.labels.get_mut(name) {
173 if let Some(offset) = label.offset {
174 return self.calculate_relative_offset(current_pos, offset);
176 }
177 else {
178 label.fixup_locations.push(current_pos);
180 }
181 }
182 else {
183 let label = Label { name: name.to_string(), offset: None, fixup_locations: vec![current_pos] };
185 self.labels.insert(name.to_string(), label);
186 }
187
188 0 }
190
191 fn fixup_label(&mut self, name: &str, label_offset: usize) {
193 if let Some(label) = self.labels.get_mut(name) {
194 let fixup_positions: Vec<usize> = label.fixup_locations.clone();
196
197 for fixup_pos in fixup_positions {
198 let relative_offset = self.calculate_relative_offset(fixup_pos, label_offset);
199 let bytes = (relative_offset as i32).to_le_bytes();
201 for (i, &byte) in bytes.iter().enumerate() {
202 if fixup_pos + i < self.code.len() {
203 self.code[fixup_pos + i] = byte;
204 }
205 }
206 }
207
208 if let Some(label) = self.labels.get_mut(name) {
210 label.fixup_locations.clear();
211 }
212 }
213 }
214
215 fn calculate_relative_offset(&self, from: usize, to: usize) -> usize {
217 if to >= from {
218 to - from
219 }
220 else {
221 0 }
224 }
225
226 pub fn allocate_stack(&mut self, size: u32) -> i32 {
228 self.stack_offset -= size as i32;
229 self.stack_size = self.stack_size.max((-self.stack_offset) as u32);
230 self.stack_offset
231 }
232
233 pub fn add_string_constant(&mut self, value: &str) -> usize {
235 if let Some(&offset) = self.string_constants.get(value) {
236 offset
237 }
238 else {
239 let offset = self.string_constants.len() * 8; self.string_constants.insert(value.to_string(), offset);
241 offset
242 }
243 }
244
245 pub fn add_function_call(&mut self, name: &str, is_import: bool) {
247 let call_offset = self.current_position();
248 self.function_calls.push(FunctionCall { name: name.to_string(), call_offset, is_import });
249 }
250
251 pub fn add_relocation(&mut self, reloc_type: RelocationType, symbol: &str) {
253 let offset = self.current_position();
254 self.relocations.push(RelocationInfo { offset, reloc_type, symbol: symbol.to_string() });
255 }
256}
257
258impl Default for X64Context {
259 fn default() -> Self {
260 Self::new()
261 }
262}