From a6eb022b91a6836b57460f1a7fd74ece8f5988bb Mon Sep 17 00:00:00 2001 From: Ales Katona Date: Sat, 30 Jan 2021 13:06:59 -0800 Subject: [PATCH] WIP --- src/common/loadable.rs | 28 ++++++++----- src/common/relocatable.rs | 4 ++ src/common/symbol.rs | 87 ++++++++++++++++++++++++++++++++++++++- src/error.rs | 20 +++++---- src/formats/elf/object.rs | 33 +++++++++++++++ src/linker.rs | 20 +++++---- 6 files changed, 165 insertions(+), 27 deletions(-) diff --git a/src/common/loadable.rs b/src/common/loadable.rs index 9bbf4b4..bbdc3d6 100644 --- a/src/common/loadable.rs +++ b/src/common/loadable.rs @@ -3,7 +3,7 @@ use std::iter::once; use crate::error::Error; use crate::{ - common::{Relocatable, Section, SectionInfo, SymbolIndex}, + common::{Relocatable, Section, SectionInfo, SymbolIndex, Symbols}, error::LinkError, }; @@ -42,7 +42,7 @@ pub struct Loadable { rodata: SegmentSections, data: SegmentSections, bss: SegmentSections, - symbol_map: HashMap>, + symbol_map: HashMap, } impl Loadable { @@ -57,29 +57,35 @@ impl Loadable { Ok(()) } - pub fn process_symbol(&mut self, index: usize, object: &R) -> Result<(), Error> + pub fn process_symbol(&mut self, si: SymbolIndex, objects: &[R]) -> Result<(), Error> where R: Relocatable, { - if !object.symbol_needs_resolving(index) { + let object = objects + .get(si.object_index) + .ok_or(Error::InvalidSectionIndex)?; + + if !object.symbol_needs_resolving(si.symbol_index) { return Ok(()); // local symbols are not stored } - let name = object.symbol_name(index)?; - eprintln!("NAME: {}", name); + let name = object.symbol_name(si.symbol_index)?; + eprintln!("NAME: {}/{:?}", name, object.symbol_value(si.symbol_index)?); let si = SymbolIndex { object_index: object.object_index(), - symbol_index: index, + symbol_index: si.symbol_index, }; if let Some(existing) = self.symbol_map.get_mut(name) { - existing.push(si); + existing.push(si, objects) } else { - self.symbol_map.insert(name.to_owned(), vec![si]); - } + let mut symbols = Symbols::default(); + symbols.push(si, objects)?; + self.symbol_map.insert(name.to_owned(), symbols); - Ok(()) + Ok(()) + } } pub fn segment_sections(&self) -> impl Iterator { diff --git a/src/common/relocatable.rs b/src/common/relocatable.rs index d84425b..53e7879 100644 --- a/src/common/relocatable.rs +++ b/src/common/relocatable.rs @@ -23,6 +23,10 @@ pub trait Relocatable: Display + Sized { fn symbol_name(&self, index: usize) -> Result<&str, Error>; + fn symbol_value(&self, index: usize) -> Result<&[u8], Error>; + + fn symbol_file_offset(&self, index: usize) -> Result; + fn symbol_needs_resolving(&self, index: usize) -> bool; fn bytes(&self, offset: u64, size: u64) -> Result<&[u8], Error>; diff --git a/src/common/symbol.rs b/src/common/symbol.rs index 7ec0a9e..e7e3d34 100644 --- a/src/common/symbol.rs +++ b/src/common/symbol.rs @@ -1,7 +1,92 @@ use std::fmt::Debug; -#[derive(Default, Debug)] +use crate::error::{Error, LinkError, Trace, LE_GLOBAL_SYMBOL_DUPLICATE}; + +use super::Relocatable; + +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)] pub struct SymbolIndex { pub object_index: usize, pub symbol_index: usize, } + +#[derive(Default)] +pub struct Symbols { + indexes: Vec, + value_index: Option, +} + +impl Symbols { + pub fn push(&mut self, si: SymbolIndex, objects: &[R]) -> Result<(), Error> + where + R: Relocatable, + { + let object = objects + .get(si.object_index) + .ok_or(Error::InvalidSymbolIndex)?; + let value = object.symbol_value(si.symbol_index)?; + + self.indexes.push(si); + + if value.len() > 0 { + if let Some(existing) = self.value_index { + let osi = self + .indexes + .get(existing) + .ok_or(Error::InvalidSymbolIndex)?; + Self::duplicate_symbol_error(si, *osi, objects) + } else { + self.value_index = Some(self.indexes.len() - 1); + + Ok(()) + } + } else { + Ok(()) + } + } + + pub fn value<'o, R>(&self, object: &'o R) -> Result<&'o [u8], Error> + where + R: Relocatable, + { + self.value_index.map_or(Ok(&[]), |v| { + object.symbol_value(self.indexes[v].symbol_index) + }) + } + + fn duplicate_symbol_error( + si: SymbolIndex, + osi: SymbolIndex, + objects: &[R], + ) -> Result<(), Error> + where + R: Relocatable, + { + let object = objects + .get(si.object_index) + .ok_or(Error::InvalidSymbolIndex)?; + let other = objects + .get(osi.object_index) + .ok_or(Error::InvalidObjectIndex)?; + let mut traces = Vec::new(); + + traces.push(Trace { + origin: object.origin().into(), + offset: object.symbol_file_offset(si.symbol_index)?, + source_info: None, + }); + traces.push(Trace { + origin: other.origin().into(), + offset: other.symbol_file_offset(osi.symbol_index)?, + source_info: None, + }); + + let link_error = LinkError { + code: LE_GLOBAL_SYMBOL_DUPLICATE, + message: "duplicate global symbol found".into(), + traces, + }; + + Err(Error::LinkingError(link_error)) + } +} diff --git a/src/error.rs b/src/error.rs index 63e269b..60646e4 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,7 +9,9 @@ pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 10001; pub enum Error { IOError(Box), DataError(PathBuf), // generic "something wrong with data" error, not specific to parsing + InvalidObjectIndex, InvalidObjectType(u32), + InvalidSectionIndex, InvalidSectionName, InvalidSymbolIndex, InvalidSymbolName, @@ -23,7 +25,7 @@ pub enum Error { #[derive(Debug, Default)] pub struct Trace { pub origin: PathBuf, - pub offset: u64, // 0 indicates unknown/invalid + pub offset: usize, // 0 indicates unknown/invalid pub source_info: Option>, } @@ -41,11 +43,13 @@ impl Error { match self { Error::IOError(_) => 100, Error::DataError(_) => 800, - Error::InvalidObjectType(_) => 200, - Error::InvalidSectionName => 300, - Error::InvalidSymbolIndex => 325, - Error::InvalidSymbolName => 350, - Error::InvalidSectionData => 400, + Error::InvalidObjectIndex => 200, + Error::InvalidObjectType(_) => 201, + Error::InvalidSectionIndex => 300, + Error::InvalidSectionName => 301, + Error::InvalidSectionData => 302, + Error::InvalidSymbolIndex => 400, + Error::InvalidSymbolName => 401, Error::ParseError(_) => 500, Error::TryFromIntError => 600, Error::InvalidInput => 700, @@ -79,11 +83,13 @@ impl Display for Error { match self { Error::IOError(err) => write!(f, "IO error: {}", err), Error::DataError(origin) => write!(f, "Data error in {:?}", origin), + Error::InvalidObjectIndex => write!(f, "Invalid section index"), Error::InvalidObjectType(ot) => write!(f, "Invalid object type: {}", ot), + Error::InvalidSectionIndex => write!(f, "Invalid section index"), Error::InvalidSectionName => write!(f, "Invalid section name"), + Error::InvalidSectionData => write!(f, "Invalid section data"), Error::InvalidSymbolIndex => write!(f, "Invalid symbol index"), Error::InvalidSymbolName => write!(f, "Invalid symbol name"), - Error::InvalidSectionData => write!(f, "Invalid section data"), Error::ParseError(err) => write!(f, "Parse error: {}", err), Error::TryFromIntError => write!(f, "Integer conversion error"), Error::InvalidInput => write!(f, "Input object invalid"), diff --git a/src/formats/elf/object.rs b/src/formats/elf/object.rs index fa72a67..7839b89 100644 --- a/src/formats/elf/object.rs +++ b/src/formats/elf/object.rs @@ -48,6 +48,23 @@ impl ElfObject { Ok(result) } + fn resolve_symbol_value(&self, symbol_index: usize) -> Result<&[u8], Error> { + if let Some((_, s64)) = self.symbols.get(symbol_index) { + if s64.st_size == 0 { + Ok(&[]) + } else if let Some(shdr) = self.shdrs.get(s64.st_shndx as usize) { + let start: usize = (shdr.sh_offset + s64.st_value) as usize; + let end: usize = start + s64.st_size as usize; + + Ok(&self.data[start..end]) + } else { + Err(Error::InvalidSectionIndex) + } + } else { + Err(Error::InvalidSymbolIndex) + } + } + fn resolve_name(&self, name_idx: usize, sh_index: usize) -> Result<&str, Error> { if name_idx == 0 { let error = if sh_index == self.ehdr.e_shstrndx.into() { @@ -194,6 +211,22 @@ impl Relocatable for ElfObject { } } + fn symbol_value(&self, index: usize) -> Result<&[u8], Error> { + self.resolve_symbol_value(index) + } + + fn symbol_file_offset(&self, index: usize) -> Result { + let (sh_index, s64) = self.symbols.get(index).ok_or(Error::InvalidSymbolIndex)?; + + let shdr = self + .shdrs + .get(*sh_index) + .ok_or(Error::InvalidSectionIndex)?; + let sh_offset: usize = shdr.sh_offset as usize; + + Ok(sh_offset) + } + fn symbol_needs_resolving(&self, index: usize) -> bool { match self.symbols[index].1.get_bind() { Bind::Global | Bind::Weak => true, diff --git a/src/linker.rs b/src/linker.rs index 625602b..4f99957 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -10,7 +10,7 @@ where R: Relocatable, O: Output, { - relocatables: Vec, + objects: Vec, loadable: Loadable, output: O, } @@ -22,21 +22,21 @@ where { pub fn new(output: O) -> Self { Self { - relocatables: Vec::new(), + objects: Vec::new(), loadable: Loadable::default(), output, } } pub fn add_relocatable(&mut self, origin: PathBuf) -> Result<(), Error> { - let r = R::new(origin, self.relocatables.len())?; + let r = R::new(origin, self.objects.len())?; // TODO: parallelize? for section in r.sections() { self.loadable.process_section(section?)?; } - self.relocatables.push(r); + self.objects.push(r); Ok(()) } @@ -45,15 +45,19 @@ where self.process_symbols()?; self.loadable.set_start_offset(4096); // TODO: get from .start symbol location - self.output.finalize(&self.relocatables, &self.loadable) + self.output.finalize(&self.objects, &self.loadable) } fn process_symbols(&mut self) -> Result<(), Error> { - for r in &self.relocatables { + for r in &self.objects { let symbol_count = r.symbol_count(); for i in 0..symbol_count { - self.loadable.process_symbol(i, r)?; + let si = SymbolIndex { + object_index: r.object_index(), + symbol_index: i, + }; + self.loadable.process_symbol(si, &self.objects)?; } } @@ -69,7 +73,7 @@ where fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { writeln!(f, "===Relocatables===")?; - for r in self.relocatables.iter() { + for r in self.objects.iter() { write!(f, "{}", r)?; }