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"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
152
src/linker.rs
152
src/linker.rs
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue