asmpeach/assembler/generator/
generate.rs1use crate::assembler::resource::{Opcode, RelaSymbol, Symbol};
2use indexmap::map::IndexMap;
3
4#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Copy, Clone)]
5struct RelativeJumpSpec {
6 operand_offset: isize,
7 address: isize,
8 is_label: bool,
9}
10
11impl RelativeJumpSpec {
12 fn new_label(addr: isize) -> Self {
13 Self {
14 operand_offset: 0,
15 address: addr,
16 is_label: true,
17 }
18 }
19 fn new_jump(offset: isize) -> Self {
20 Self {
21 operand_offset: offset,
22 address: offset,
23 is_label: false,
24 }
25 }
26}
27
28pub fn generate_main(symbols: &mut IndexMap<String, Symbol>) -> IndexMap<String, Vec<RelaSymbol>> {
29 let mut reloc_syms = IndexMap::new();
30
31 for (sym_name, sym) in symbols.iter_mut() {
32 let (mut sym_codes, relocs_in_sym) = gen_symbol_code(sym);
33 reloc_syms.insert(sym_name.to_string(), relocs_in_sym);
34
35 let mut extra_bytes: Vec<u8> = Vec::new();
37
38 let rest_bytes = sym_codes.len() % 4;
39 for _ in 0..(4 - rest_bytes) {
40 extra_bytes.push(0x00);
41 }
42 sym_codes.append(&mut extra_bytes);
43
44 sym.codes = sym_codes;
45 }
46
47 reloc_syms
48}
49
50fn gen_symbol_code(sym: &Symbol) -> (Vec<u8>, Vec<RelaSymbol>) {
51 let mut relative_jump_offset: IndexMap<String, Vec<RelativeJumpSpec>> = IndexMap::new();
52 let mut code_offset = 0;
53
54 let mut symbol_codes = Vec::new();
55 let mut relocations = Vec::new();
56
57 for group in sym.groups.iter() {
59 if let Some(specs) = relative_jump_offset.get(&group.label) {
61 for spec in specs {
62 let relative_offset = code_offset - spec.address;
64
65 for (idx, addr) in (relative_offset as u32).to_le_bytes().iter().enumerate() {
66 symbol_codes[idx + (spec.operand_offset - 4) as usize] = *addr;
67 }
68 }
69 } else {
70 if !group.label.ends_with("_entry") {
72 relative_jump_offset.insert(
74 group.label.to_string(),
75 vec![RelativeJumpSpec::new_label(code_offset)],
76 );
77 }
78 }
79
80 for inst in group.insts.iter() {
81 match &inst.opcode {
85 Opcode::CALLFUNC(func) => {
86 let mut inst_bytes = vec![0xe8, 0x00, 0x00, 0x00, 0x00];
88
89 let rela64 = new_rela64(func.copy_label(), code_offset);
90 relocations.push(rela64);
91
92 code_offset += inst_bytes.len() as isize;
93 symbol_codes.append(&mut inst_bytes);
94 }
95
96 Opcode::JELABEL { label } => {
98 let mut inst_bytes = inst.to_bytes();
99 inst_bytes.append(&mut vec![0x00, 0x00, 0x00, 0x00]);
100 code_offset += inst_bytes.len() as isize;
101 symbol_codes.append(&mut inst_bytes);
102
103 resolve_jump(
104 label,
105 code_offset,
106 &mut relative_jump_offset,
107 &mut symbol_codes,
108 );
109 }
110 Opcode::JLELABEL { label } => {
111 let mut inst_bytes = inst.to_bytes();
112 inst_bytes.append(&mut vec![0x00, 0x00, 0x00, 0x00]);
113 code_offset += inst_bytes.len() as isize;
114 symbol_codes.append(&mut inst_bytes);
115
116 resolve_jump(
117 label,
118 code_offset,
119 &mut relative_jump_offset,
120 &mut symbol_codes,
121 );
122 }
123 Opcode::JMPLABEL { label } => {
124 let mut inst_bytes = inst.to_bytes();
125 inst_bytes.append(&mut vec![0x00, 0x00, 0x00, 0x00]);
126 code_offset += inst_bytes.len() as isize;
127 symbol_codes.append(&mut inst_bytes);
128
129 resolve_jump(
130 label,
131 code_offset,
132 &mut relative_jump_offset,
133 &mut symbol_codes,
134 );
135 }
136 _ => {
137 let mut inst_bytes = inst.to_bytes();
138 code_offset += inst_bytes.len() as isize;
139 symbol_codes.append(&mut inst_bytes);
140 }
141 }
142 }
143 }
144
145 (symbol_codes, relocations)
146}
147
148fn resolve_jump(
149 label: &str,
150 length: isize,
151 relative_jump: &mut IndexMap<String, Vec<RelativeJumpSpec>>,
152 sym_codes: &mut Vec<u8>,
153) {
154 if let Some(specs) = relative_jump.get_mut(label) {
155 for spec in specs.iter() {
156 if !spec.is_label {
158 continue;
159 }
160
161 let relative_offset = spec.address - length;
163 for (idx, addr) in (relative_offset as i32).to_le_bytes().iter().enumerate() {
164 sym_codes[idx + (length - 4) as usize] = *addr;
165 }
166 }
167
168 specs.push(RelativeJumpSpec::new_jump(length));
169 } else {
170 relative_jump.insert(label.to_string(), vec![RelativeJumpSpec::new_jump(length)]);
172 }
173}
174
175fn new_rela64(name: String, offset: isize) -> RelaSymbol {
176 let mut rela64: RelaSymbol = Default::default();
177 rela64.rela64.set_addend(-4);
178 rela64.name = name;
179
180 rela64.rela64.set_offset(offset as u64 + 1);
182
183 rela64
184}