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"
[dependencies]
serde = { version = "1.0", features = ["derive"] }

View file

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

View file

@ -1,12 +1,13 @@
use {
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 {
Absolute(VM_Word),
Relative{
Relative {
symbol: String,
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> {
match self {
LinkAddr::Absolute(addr) =>
write!(f, "{:x}", addr),
write!(f, "{:#08x}", addr),
LinkAddr::Relative{ symbol, offset } =>
if *offset == 0 {
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 {
addr: VM_Word,
data: Vec< AssemblyWord >
pub addr: VM_Word,
pub data: Vec< AssemblyWord >
}
pub struct Linker {
symbols: HashMap<String, Section>,
next_addr: VM_Word
pub sections: Vec<Section>,
pub symbols: HashMap<String, ObjAddr>,
// internal linker state
pub next_addr: VM_Word
}
#[derive(Clone, Debug)]
@ -43,17 +54,38 @@ pub enum LinkError {
RelativeAddrOutOfBounds( String, VM_Word )
}
#[derive(Serialize, Deserialize, Debug)]
pub struct ObjectFile {
pub symbols: Vec< (String, VM_Word) >,
pub code: Vec< AssemblyWord >,
}
impl Linker {
pub fn new() -> Self {
Linker {
sections: Vec::new(),
symbols: HashMap::new(),
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> {
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 {
bytecode[ addr as usize ] = self.resolve_link(w.clone())?;
addr += 1;
@ -93,7 +125,10 @@ impl Linker {
pub fn get_link_addr(&self, name: &String) -> Option<VM_Word> {
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
}
}
@ -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> {
match addr {
LinkAddr::Absolute(w) => Ok(LinkAddr::Absolute(w)),
LinkAddr::Relative{ symbol, offset } => {
match self.symbols.get(&symbol){
Some(Section{ addr, data }) => {
if offset < data.len() as i64 && offset >= 0 {
Ok(LinkAddr::Absolute( *addr as i64 + offset as i64 ))
if let Some((symbol_addr, len)) = self.get_symbol_range(&symbol) {
if offset < len as i64 && offset >= 0 {
Ok(LinkAddr::Absolute( symbol_addr + offset as i64 ))
} else {
eprintln!("symbol {} @ {}+{}", symbol, symbol_addr, len);
Err(LinkError::RelativeAddrOutOfBounds(symbol, offset))
}
},
None => Ok(LinkAddr::Relative{ symbol, offset })
} else {
Ok(LinkAddr::Relative{ symbol, offset })
}
}
}
@ -128,32 +175,75 @@ impl Linker {
&mut self,
symbol: &str,
data: Vec<VM_Word>,
) {
) -> usize {
let link_addr = self.next_addr;
self.next_addr += data.len() as i64;
self.symbols.insert(
symbol.into(),
Section {
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(
symbol.into(),
ObjAddr {
section_id,
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(
&mut self,
symbol: &str,
bytecode: Vec< AssemblyWord >
) {
) -> usize {
let link_addr = self.next_addr;
self.next_addr += bytecode.len() as i64;
self.symbols.insert(
symbol.into(),
Section {
let section_id = self.sections.len();
self.sections.push(Section {
addr: link_addr,
data: bytecode
}
);
});
self.symbols.insert(symbol.into(), ObjAddr{
section_id,
offset: 0
});
section_id
}
}