add (de-)serializable ObjectFile

linker: add add_procedure_front()
This commit is contained in:
Michael Sippel 2024-10-18 20:57:20 +02:00
parent 90bca05e2c
commit 3a55cd32dd
Signed by: senvas
GPG key ID: F96CF119C34B64A6
3 changed files with 126 additions and 33 deletions

View file

@ -4,3 +4,5 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
serde = { version = "1.0", features = ["derive"] }

View file

@ -2,10 +2,11 @@ use {
crate::{ crate::{
VM_Word, VM_Instruction, VM_Word, VM_Instruction,
linker::LinkAddr linker::LinkAddr
} },
serde::{Serialize, Deserialize}
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AssemblyWord { pub enum AssemblyWord {
Symbol( LinkAddr ), Symbol( LinkAddr ),
Lit( VM_Word ) Lit( VM_Word )

View file

@ -1,12 +1,13 @@
use { use {
std::collections::HashMap, std::collections::HashMap,
crate::{VM_Word, assembler::AssemblyWord} crate::{VM_Word, assembler::AssemblyWord},
serde::{Serialize, Deserialize}
}; };
#[derive(Clone, Debug)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub enum LinkAddr { pub enum LinkAddr {
Absolute(VM_Word), Absolute(VM_Word),
Relative{ Relative {
symbol: String, symbol: String,
offset: VM_Word offset: VM_Word
} }
@ -16,7 +17,7 @@ impl std::fmt::Display for LinkAddr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self { match self {
LinkAddr::Absolute(addr) => LinkAddr::Absolute(addr) =>
write!(f, "{:x}", addr), write!(f, "{:#08x}", addr),
LinkAddr::Relative{ symbol, offset } => LinkAddr::Relative{ symbol, offset } =>
if *offset == 0 { if *offset == 0 {
write!(f, "{}", symbol) write!(f, "{}", symbol)
@ -27,14 +28,24 @@ impl std::fmt::Display for LinkAddr {
} }
} }
#[derive(Serialize, Deserialize, Debug)]
struct ObjAddr {
section_id: usize,
offset: i64
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Section { pub struct Section {
addr: VM_Word, pub addr: VM_Word,
data: Vec< AssemblyWord > pub data: Vec< AssemblyWord >
} }
pub struct Linker { pub struct Linker {
symbols: HashMap<String, Section>, pub sections: Vec<Section>,
next_addr: VM_Word pub symbols: HashMap<String, ObjAddr>,
// internal linker state
pub next_addr: VM_Word
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -43,17 +54,38 @@ pub enum LinkError {
RelativeAddrOutOfBounds( String, VM_Word ) RelativeAddrOutOfBounds( String, VM_Word )
} }
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectFile {
pub symbols: Vec< (String, VM_Word) >,
pub code: Vec< AssemblyWord >,
}
impl Linker { impl Linker {
pub fn new() -> Self { pub fn new() -> Self {
Linker { Linker {
sections: Vec::new(),
symbols: HashMap::new(), symbols: HashMap::new(),
next_addr: 0 next_addr: 0
} }
} }
pub fn import(&mut self, source_name: &str, obj_file: ObjectFile) {
let section_id = self.add_procedure(
&source_name,
obj_file.code
);
for (symbol, offset) in obj_file.symbols {
self.symbols.insert(symbol, ObjAddr {
section_id,
offset
});
}
}
pub fn link_partial(self) -> Result<Vec<AssemblyWord>, LinkError> { pub fn link_partial(self) -> Result<Vec<AssemblyWord>, LinkError> {
let mut bytecode = vec![ AssemblyWord::Lit(0); self.next_addr as usize ]; let mut bytecode = vec![ AssemblyWord::Lit(0); self.next_addr as usize ];
for (sym, Section{ mut addr, data }) in self.symbols.iter() { for Section{ mut addr, data } in self.sections.iter() {
for w in data { for w in data {
bytecode[ addr as usize ] = self.resolve_link(w.clone())?; bytecode[ addr as usize ] = self.resolve_link(w.clone())?;
addr += 1; addr += 1;
@ -93,7 +125,10 @@ impl Linker {
pub fn get_link_addr(&self, name: &String) -> Option<VM_Word> { pub fn get_link_addr(&self, name: &String) -> Option<VM_Word> {
match self.symbols.get(name) { match self.symbols.get(name) {
Some(section) => Some(section.addr), Some(ObjAddr{ section_id, offset }) =>{
let section = self.sections.get(*section_id).unwrap();
Some(section.addr + offset)
},
None => None None => None
} }
} }
@ -106,19 +141,31 @@ impl Linker {
} }
} }
pub fn get_symbol_range( &self, name: &str ) -> Option<(i64, usize)> {
if let Some(ObjAddr{ section_id, offset }) = self.symbols.get(name) {
if let Some(Section{ data, addr }) = self.sections.get(*section_id) {
Some((*addr as i64 + *offset as i64, data.len()))
} else {
None
}
} else {
None
}
}
pub fn resolve_link_addr(&self, addr: LinkAddr) -> Result<LinkAddr, LinkError> { pub fn resolve_link_addr(&self, addr: LinkAddr) -> Result<LinkAddr, LinkError> {
match addr { match addr {
LinkAddr::Absolute(w) => Ok(LinkAddr::Absolute(w)), LinkAddr::Absolute(w) => Ok(LinkAddr::Absolute(w)),
LinkAddr::Relative{ symbol, offset } => { LinkAddr::Relative{ symbol, offset } => {
match self.symbols.get(&symbol){ if let Some((symbol_addr, len)) = self.get_symbol_range(&symbol) {
Some(Section{ addr, data }) => { if offset < len as i64 && offset >= 0 {
if offset < data.len() as i64 && offset >= 0 { Ok(LinkAddr::Absolute( symbol_addr + offset as i64 ))
Ok(LinkAddr::Absolute( *addr as i64 + offset as i64 )) } else {
} else { eprintln!("symbol {} @ {}+{}", symbol, symbol_addr, len);
Err(LinkError::RelativeAddrOutOfBounds(symbol, offset)) Err(LinkError::RelativeAddrOutOfBounds(symbol, offset))
} }
}, } else {
None => Ok(LinkAddr::Relative{ symbol, offset }) Ok(LinkAddr::Relative{ symbol, offset })
} }
} }
} }
@ -128,32 +175,75 @@ impl Linker {
&mut self, &mut self,
symbol: &str, symbol: &str,
data: Vec<VM_Word>, data: Vec<VM_Word>,
) { ) -> usize {
let link_addr = self.next_addr; let link_addr = self.next_addr;
self.next_addr += data.len() as i64; self.next_addr += data.len() as i64;
let section_id = self.sections.len();
self.sections.push(Section {
addr: link_addr,
data: data.into_iter().map(|w| AssemblyWord::Lit(w)).collect()
});
self.symbols.insert( self.symbols.insert(
symbol.into(), symbol.into(),
Section { ObjAddr {
addr: link_addr, section_id,
data: data.into_iter().map(|w| AssemblyWord::Lit(w)).collect() offset: 0
} }
); );
section_id
}
pub fn add_procedure_front(
&mut self,
symbol: &str,
bytecode: Vec< AssemblyWord >
) -> usize {
self.next_addr += bytecode.len() as i64;
for section in self.sections.iter_mut() {
section.addr += bytecode.len() as i64;
}
let section_id = self.sections.len();
self.sections.push(Section {
addr: 0,
data: bytecode
});
self.symbols.insert(symbol.into(), ObjAddr{
section_id,
offset: 0
});
section_id
} }
pub fn add_procedure( pub fn add_procedure(
&mut self, &mut self,
symbol: &str, symbol: &str,
bytecode: Vec< AssemblyWord > bytecode: Vec< AssemblyWord >
) { ) -> usize {
let link_addr = self.next_addr; let link_addr = self.next_addr;
self.next_addr += bytecode.len() as i64; self.next_addr += bytecode.len() as i64;
self.symbols.insert(
symbol.into(),
Section { let section_id = self.sections.len();
addr: link_addr,
data: bytecode self.sections.push(Section {
} addr: link_addr,
); data: bytecode
});
self.symbols.insert(symbol.into(), ObjAddr{
section_id,
offset: 0
});
section_id
} }
} }