elf_assembler/assembler/x64/
code_builder.rs1use super::context::{RelocationType, X64Context};
6
7#[derive(Debug)]
11pub struct X64CodeBuilder {
12 context: X64Context,
13}
14
15impl X64CodeBuilder {
16 pub fn new() -> Self {
18 Self { context: X64Context::new() }
19 }
20
21 pub fn context_mut(&mut self) -> &mut X64Context {
23 &mut self.context
24 }
25
26 pub fn context(&self) -> &X64Context {
28 &self.context
29 }
30
31 pub fn code(&self) -> &[u8] {
33 &self.context.code
34 }
35
36 pub fn finish(self) -> X64Context {
38 self.context
39 }
40
41 pub fn function_prologue(&mut self) -> &mut Self {
43 let bytes = vec![
44 0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x20, ];
48 self.context.emit_bytes(&bytes);
49 self
50 }
51
52 pub fn function_epilogue(&mut self) -> &mut Self {
54 let bytes = vec![
55 0x48, 0x89, 0xEC, 0x5D, 0xC3, ];
59 self.context.emit_bytes(&bytes);
60 self
61 }
62
63 pub fn exit_program(&mut self, exit_code: i32) -> &mut Self {
65 self.context.emit_bytes(&[0xB9]);
67 self.context.emit_bytes(&exit_code.to_le_bytes());
68
69 self.context.add_function_call("ExitProcess", true);
71 self.context.add_relocation(RelocationType::RipRel32, "ExitProcess");
72 self.context.emit_bytes(&[0xFF, 0x15, 0x00, 0x00, 0x00, 0x00]); self
75 }
76
77 pub fn load_immediate(&mut self, value: i64) {
79 if value >= i32::MIN as i64 && value <= i32::MAX as i64 {
81 self.context.emit_bytes(&[0xB8]);
82 self.context.emit_bytes(&(value as i32).to_le_bytes());
83 }
84 else {
85 self.context.emit_bytes(&[0x48, 0xB8]);
86 self.context.emit_bytes(&value.to_le_bytes());
87 }
88 }
89
90 pub fn load_string_address(&mut self, string_id: &str) {
91 self.context.add_string_constant(string_id);
93
94 self.context.emit_bytes(&[0x48, 0x8D, 0x05]);
96 let _offset = self.context.reference_label(&format!("str_{}", string_id));
97 self.context.emit_bytes(&[0x00, 0x00, 0x00, 0x00]); }
99
100 pub fn store_local(&mut self, _offset: i32) {
101 let stack_offset = self.context.allocate_stack(8);
102 if stack_offset >= -128 && stack_offset <= 127 {
104 self.context.emit_bytes(&[0x48, 0x89, 0x45]);
105 self.context.emit_bytes(&[stack_offset as u8]);
106 }
107 else {
108 self.context.emit_bytes(&[0x48, 0x89, 0x85]);
109 self.context.emit_bytes(&stack_offset.to_le_bytes());
110 }
111 }
112
113 pub fn load_local(&mut self, offset: i32) {
114 if offset >= -128 && offset <= 127 {
116 self.context.emit_bytes(&[0x48, 0x8B, 0x45]);
117 self.context.emit_bytes(&[offset as u8]);
118 }
119 else {
120 self.context.emit_bytes(&[0x48, 0x8B, 0x85]);
121 self.context.emit_bytes(&offset.to_le_bytes());
122 }
123 }
124
125 pub fn add_operation(&mut self) {
126 self.context.emit_bytes(&[
128 0x5B, 0x58, 0x48, 0x01, 0xD8, 0x50, ]);
133 }
134
135 pub fn sub_operation(&mut self) {
136 self.context.emit_bytes(&[
138 0x5B, 0x58, 0x48, 0x29, 0xD8, 0x50, ]);
143 }
144
145 pub fn mul_operation(&mut self) {
146 self.context.emit_bytes(&[
148 0x5B, 0x58, 0x48, 0x0F, 0xAF, 0xC3, 0x50, ]);
153 }
154
155 pub fn call_printf(&mut self) {
156 self.context.add_function_call("printf", true);
158
159 self.context.emit_bytes(&[0xFF, 0x15, 0x00, 0x00, 0x00, 0x00]);
161 }
162
163 pub fn pop_stack(&mut self) {
164 self.context.emit_bytes(&[0x58]);
166 }
167
168 pub fn conditional_jump_false(&mut self, label: &str) {
169 self.context.emit_bytes(&[0x48, 0x85, 0xC0]); self.context.emit_bytes(&[0x0F, 0x84]); let _offset = self.context.reference_label(label);
173 self.context.emit_bytes(&[0x00, 0x00, 0x00, 0x00]); }
175
176 pub fn unconditional_jump(&mut self, label: &str) {
177 self.context.emit_bytes(&[0xE9]); let _offset = self.context.reference_label(label);
180 self.context.emit_bytes(&[0x00, 0x00, 0x00, 0x00]); }
182
183 pub fn hello_world_program() -> Vec<u8> {
185 let mut builder = X64CodeBuilder::new();
186
187 builder.function_prologue();
189
190 builder.load_string_address("Hello, World!\n");
192
193 builder.call_printf();
195
196 builder.exit_program(0);
198
199 builder.finish().code
200 }
201
202 pub fn message_box_program() -> Vec<u8> {
204 let mut builder = X64CodeBuilder::new();
205
206 builder.function_prologue();
208
209 builder.context_mut().emit_bytes(&[0x41, 0xB9, 0x00, 0x00, 0x00, 0x00]);
212
213 builder.context_mut().emit_bytes(&[0x49, 0xB8]);
215 builder.context_mut().emit_bytes(&0x2100u64.to_le_bytes()); builder.context_mut().emit_bytes(&[0x48, 0xBA]);
219 builder.context_mut().emit_bytes(&0x2000u64.to_le_bytes()); builder.context_mut().emit_bytes(&[0x48, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
223
224 builder.context_mut().emit_bytes(&[0xFF, 0x15, 0x00, 0x00, 0x00, 0x00]);
226
227 builder.exit_program(0);
229
230 builder.finish().code
231 }
232}