diff --git a/src/common/loadable.rs b/src/common/loadable.rs index 57c4202..cf00768 100644 --- a/src/common/loadable.rs +++ b/src/common/loadable.rs @@ -1,8 +1,12 @@ -use std::iter::once; +use std::{collections::HashMap, iter::once, rc::Rc}; -use crate::common::SectionInfo; -use crate::common::{Relocatable, Section}; use crate::error::Error; +use crate::{ + common::{Relocatable, Section, SectionInfo, Symbol}, + error::{LinkError, Trace, LE_GLOBAL_SYMBOL_DUPLICATE}, +}; + +use super::Binding; pub enum SegmentType { Text, @@ -40,6 +44,8 @@ pub struct Loadable { rodata: SegmentSections, data: SegmentSections, bss: SegmentSections, + + symbol_map: HashMap, Symbol>, } impl Loadable { @@ -54,6 +60,38 @@ impl Loadable { Ok(()) } + pub fn process_symbol(&mut self, symbol: Symbol, objects: &[R]) -> Result<(), Error> + where + R: Relocatable, + { + Ok(()) + // if symbol.binding == Binding::Local { + // return Ok(()); // local symbols are not stored + // } + + // let key = Rc::from(symbol.name.as_str()); + // let object_index = symbol.object_index; + + // if let Some(prev) = self.symbol_map.insert(key, symbol) { + // let prev_trace = Trace { + // origin: objects[prev.object_index].origin().into(), + // ..Default::default() + // }; + // let symbol_trace = Trace { + // origin: objects[object_index].origin().into(), + // ..Default::default() + // }; + // let link_error = LinkError { + // message: format!("Duplicate global symbol found: {}", prev.name), + // code: LE_GLOBAL_SYMBOL_DUPLICATE, + // traces: vec![prev_trace, symbol_trace], + // }; + // Err(Error::LinkingError(link_error)) + // } else { + // Ok(()) + // } + } + pub const fn section_names() -> &'static [&'static str] { &[".text", ".rodata", ".data", ".bss"] } diff --git a/src/common/symbol.rs b/src/common/symbol.rs index b52329d..1051100 100644 --- a/src/common/symbol.rs +++ b/src/common/symbol.rs @@ -1,4 +1,4 @@ -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq)] pub enum Binding { Local, Global, @@ -6,6 +6,7 @@ pub enum Binding { } pub struct Symbol { + pub object_index: usize, pub name: String, pub binding: Binding, pub address: u64, diff --git a/src/error.rs b/src/error.rs index f3c678f..024191b 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,6 +3,8 @@ use std::{ path::PathBuf, }; +pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 701; + #[derive(Debug)] pub enum Error { IOError(Box), @@ -11,19 +13,24 @@ pub enum Error { InvalidSectionData, ParseError(Box), TryFromIntError, - LinkingError(Trace), + LinkingError(LinkError), } -// "backtrace" for error origin #[derive(Debug, Default)] pub struct Trace { - pub code: u32, // specific trace code, should be >= 700 - pub message: &'static str, pub origin: PathBuf, pub offset: u64, // 0 indicates unknown/invalid pub source_info: Option>, } +// "backtrace" for error origin +#[derive(Debug, Default)] +pub struct LinkError { + pub code: u32, // specific trace code, should be >= 700 + pub message: String, + pub traces: Vec, +} + impl Error { // used for programmatic input/output handling, IDE's etc. pub fn code(&self) -> u32 { @@ -34,7 +41,7 @@ impl Error { Error::InvalidSectionData => 400, Error::ParseError(_) => 500, Error::TryFromIntError => 600, - Error::LinkingError(trace) => trace.code, + Error::LinkingError(le) => le.code, } } } @@ -73,23 +80,25 @@ impl Display for Error { } } -impl Display for Trace { +impl Display for LinkError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { let mut new_line = ""; // new line in case of previous info only - if let Some(origin) = self.origin.to_str() { - new_line = "\n"; - write!(f, "\n\t{}", origin)?; - } + for trace in &self.traces { + if let Some(origin) = trace.origin.to_str() { + new_line = "\n"; + write!(f, "\n\t{}", origin)?; + } - if self.offset > 0 { - new_line = "\n"; - write!(f, "\n@offset: {}", self.offset)?; - } + if trace.offset > 0 { + new_line = "\n"; + write!(f, "\n@offset: {}", trace.offset)?; + } - if let Some(si) = &self.source_info { - new_line = "\n"; - write!(f, "\n{}", si)?; + if let Some(si) = &trace.source_info { + new_line = "\n"; + write!(f, "\n{}", si)?; + } } write!(f, "{}{}", new_line, self.message) diff --git a/src/formats/elf/object.rs b/src/formats/elf/object.rs index a8698cd..1753edb 100644 --- a/src/formats/elf/object.rs +++ b/src/formats/elf/object.rs @@ -39,6 +39,23 @@ impl ElfObject { Ok(result) } + + fn make_symbol(&self, s64: &Symbol64, strtab: &[u8]) -> Symbol { + let binding = match s64.get_bind() { + Bind::Global => Binding::Global, + Bind::Local => Binding::Local, + Bind::Weak => Binding::Weak, + _ => panic!("Unexpected binding type encountered on symbol"), // this is screened! + }; + + Symbol { + object_index: self.object_index, + name: parse_strtab_name(&strtab, s64.st_name), + binding, + address: s64.st_value, + size: s64.st_size, + } + } } impl Relocatable for ElfObject { @@ -124,7 +141,7 @@ impl Relocatable for ElfObject { Contents64::Symbols(symbols) => { Some(symbols.iter().filter_map(move |sym| match sym.get_bind() { Bind::Global | Bind::Local | Bind::Weak => { - Some(make_symbol(sym, strtab)) + Some(self.make_symbol(sym, strtab)) } _ => None, })) @@ -158,23 +175,7 @@ impl Display for ElfObject { } } -fn make_symbol(s64: &Symbol64, strtab: &Vec) -> Symbol { - let binding = match s64.get_bind() { - Bind::Global => Binding::Global, - Bind::Local => Binding::Local, - Bind::Weak => Binding::Weak, - _ => panic!("Unexpected binding type encountered on symbol"), // this is screened! - }; - - Symbol { - name: parse_strtab_name(&strtab, s64.st_name), - binding, - address: s64.st_value, - size: s64.st_size, - } -} - -fn parse_strtab_name(strtab: &Vec, idx: u32) -> String { +fn parse_strtab_name(strtab: &[u8], idx: u32) -> String { let bytes: Vec = strtab .iter() .skip(idx as usize) diff --git a/src/formats/elf/output.rs b/src/formats/elf/output.rs index 480b693..d0d9ef7 100644 --- a/src/formats/elf/output.rs +++ b/src/formats/elf/output.rs @@ -216,15 +216,15 @@ fn make_strtab() -> (Vec, Vec) { } fn get_start_offset(loadable: &Loadable) -> Result { - use crate::error::Trace; + use crate::error::LinkError; loadable.start_offset.ok_or_else(|| { - let trace = Trace { - message: "Program entrypoint not found", + let link_error = LinkError { + message: "Program entrypoint not found".into(), ..Default::default() }; - Error::LinkingError(trace) + Error::LinkingError(link_error) }) } diff --git a/src/linker.rs b/src/linker.rs index 7d1e609..0c09b7f 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -32,8 +32,8 @@ where let r = R::new(origin, DataIndex::for_object(self.relocatables.len()))?; // TODO: parallelize? - for s in r.sections() { - self.loadable.process_section(s?)?; + for section in r.sections() { + self.loadable.process_section(section?)?; } self.relocatables.push(r); @@ -42,10 +42,22 @@ where } pub fn link(mut self) -> Result { + self.process_symbols()?; + self.loadable.start_offset = Some(4096); // TODO: get from .start symbol location self.output.finalize(&self.relocatables, &self.loadable) } + fn process_symbols(&mut self) -> Result<(), Error> { + for r in &self.relocatables { + for symbol in r.symbols() { + self.loadable.process_symbol(symbol, &self.relocatables)?; + } + } + + Ok(()) + } + // pub fn object_path(origin: &Path) -> Result { // let mut dest = std::fs::canonicalize(origin)?; // if !dest.pop() {