add (de-)serializable ObjectFile
linker: add add_procedure_front()
This commit is contained in:
parent
90bca05e2c
commit
3a55cd32dd
3 changed files with 126 additions and 33 deletions
|
@ -4,3 +4,5 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
|
152
src/linker.rs
152
src/linker.rs
|
@ -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 ))
|
||||
} else {
|
||||
Err(LinkError::RelativeAddrOutOfBounds(symbol, offset))
|
||||
}
|
||||
},
|
||||
None => Ok(LinkAddr::Relative{ symbol, offset })
|
||||
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))
|
||||
}
|
||||
} 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;
|
||||
|
||||
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(),
|
||||
Section {
|
||||
addr: link_addr,
|
||||
data: data.into_iter().map(|w| AssemblyWord::Lit(w)).collect()
|
||||
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 {
|
||||
addr: link_addr,
|
||||
data: bytecode
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue