use crate::{ backend::{elf, symbol::Symbol}, io::CompilerMsg, }; use std::collections::HashMap; pub struct LinkedProgram { pub code: Vec, pub start: Option, } pub struct UnlinkedProgram { pub fns: Vec>, pub ro_data: Vec<(Vec, Symbol)>, pub sym_count: usize, pub start: Option, } pub struct UnlinkedFunction { pub instrs: Vec, pub sym: Symbol, // locations within the function for loops & such / goto pub locations: HashMap, } impl UnlinkedProgram { pub fn link(self) -> Result { let mut data = Vec::new(); let mut sym_table = SymTable::new(self.sym_count); let mut missing = HashMap::>::new(); for (val, id) in self.ro_data { sym_table.insert(id, Addr(data.len() as u64)); data.extend(val); } // align data.resize(data.len() + (4 - data.len() % 4), 0); for f in self.fns { let addr = Addr(data.len() as u64); let mut added = vec![(f.sym, addr)]; sym_table.insert(f.sym, addr); for (i, instr) in f.instrs.into_iter().enumerate() { let i_pos = Addr(data.len() as u64); if let Some(sym) = f.locations.get(&i) { sym_table.insert(*sym, i_pos); added.push((*sym, i_pos)); } if let Some((sym, marker)) = instr.encode(&mut data, &mut sym_table)? { let info = (instr, marker); if let Some(vec) = missing.get_mut(&sym) { vec.push(info); } else { missing.insert(sym, vec![info]); } } } for (sym, addr) in added { if let Some(vec) = missing.remove(&sym) { for (i, marker) in vec { i.insert_sym(&mut data, marker, addr); } } } } assert!(missing.is_empty()); Ok(LinkedProgram { code: data, start: self .start .map(|s| sym_table.get(s).expect("start symbol doesn't exist")), }) } } #[derive(Debug, Clone, Copy, PartialEq)] pub struct Addr(u64); impl Addr { pub const ZERO: Self = Self(!0); pub fn val(&self) -> u64 { self.0 } } pub struct SymTable(Vec); impl SymTable { pub fn new(len: usize) -> Self { Self(vec![Addr::ZERO; len]) } pub fn insert(&mut self, sym: Symbol, addr: Addr) { self.0[sym.val()] = addr; } pub fn get(&self, sym: Symbol) -> Option { match self.0[sym.val()] { Addr::ZERO => None, addr => Some(addr), } } } impl LinkedProgram { pub fn to_elf(&self) -> Vec { elf::create(&self.code, self.start.expect("no start")) } }