diff --git a/src/common/loadable.rs b/src/common/loadable.rs index 0cbaebc..bde3643 100644 --- a/src/common/loadable.rs +++ b/src/common/loadable.rs @@ -1,7 +1,13 @@ +use std::collections::HashMap; use std::iter::once; -use crate::common::{Relocatable, Section, SectionInfo, Symbol}; 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, @@ -38,7 +44,7 @@ pub struct Loadable { rodata: SegmentSections, data: SegmentSections, bss: SegmentSections, - // symbol_map: HashMap, Symbol>, + symbol_map: HashMap>, } impl Loadable { @@ -53,36 +59,18 @@ impl Loadable { Ok(()) } - pub fn process_symbol(&mut self, _symbol: Symbol, _objects: &[R]) -> Result<(), Error> - where - R: Relocatable, - { + pub fn process_symbol(&mut self, name: &str, symbol: Symbol) -> Result<(), Error> { + if symbol.binding == Binding::Local { + return Ok(()); // local symbols are not stored + } + + if let Some(existing) = self.symbol_map.get_mut(name) { + existing.push(symbol); + } else { + self.symbol_map.insert(name.to_owned(), Vec::new()); + } + 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 fn segment_sections(&self) -> impl Iterator { diff --git a/src/common/relocatable.rs b/src/common/relocatable.rs index 54ba98b..9a9870c 100644 --- a/src/common/relocatable.rs +++ b/src/common/relocatable.rs @@ -7,7 +7,7 @@ use super::{Section, Symbol}; pub type SectionIterBox<'iter> = Box> + 'iter>; -pub type SymbolIterBox<'iter> = Box + 'iter>; +pub type SymbolIterBox<'iter> = Box + 'iter>; /// Contains all the needed getters to construct a final /// mushed and relocated executable from an object file diff --git a/src/common/symbol.rs b/src/common/symbol.rs index 1051100..8e0ab35 100644 --- a/src/common/symbol.rs +++ b/src/common/symbol.rs @@ -1,3 +1,9 @@ +use elf_utilities::relocation; + +use crate::error::Error; + +use super::Relocatable; + #[derive(Clone, Copy, PartialEq, Eq)] pub enum Binding { Local, @@ -7,7 +13,6 @@ pub enum Binding { pub struct Symbol { pub object_index: usize, - pub name: String, pub binding: Binding, pub address: u64, pub size: u64, diff --git a/src/error.rs b/src/error.rs index 3ae39bd..057280a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,7 +3,7 @@ use std::{ path::PathBuf, }; -// pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 10001; +pub const LE_GLOBAL_SYMBOL_DUPLICATE: u32 = 10001; #[derive(Debug)] pub enum Error { diff --git a/src/formats/elf/object.rs b/src/formats/elf/object.rs index f90e6b0..4fdd3ea 100644 --- a/src/formats/elf/object.rs +++ b/src/formats/elf/object.rs @@ -8,7 +8,7 @@ use crate::common::{Binding, Relocatable, Section, SectionInfo, Symbol, SymbolIt use crate::{common::SectionIterBox, error::Error}; use elf_utilities::{ header::Ehdr64, - section::Shdr64, + section::{Contents64, Shdr64, Type}, symbol::{Bind, Symbol64}, }; use memmap::Mmap; @@ -18,7 +18,8 @@ pub struct ElfObject { origin: PathBuf, data: Mmap, ehdr: Ehdr64, - sh_name_offset: usize, + shdrs: Vec, + symbols: Vec, } impl ElfObject { @@ -31,22 +32,26 @@ impl ElfObject { let file = File::open(str_origin)?; let data = unsafe { Mmap::map(&file)? }; let ehdr = parse_elf_header(&data)?; - let shstrtab = parse_shstrtab(&data, &ehdr)?; - let result = ElfObject { + let mut result = ElfObject { object_index, origin, data, ehdr, - sh_name_offset: shstrtab.sh_offset as usize, + shdrs: Vec::new(), + symbols: Vec::new(), }; + // TODO: make paralellization from outside possible? + result.populate()?; + Ok(result) } - fn section_name(&self, shdr: &Shdr64) -> Result<&str, Error> { - let idx: usize = shdr.sh_name as usize; - let start = self.sh_name_offset + idx; + fn resolve_name(&self, name_idx: usize, sh_index: usize) -> Result<&str, Error> { + let strtab = self.parse_strtab(sh_index)?; + let strtab_offset: usize = strtab.sh_offset as usize; + let start = strtab_offset + name_idx; let mut i = start; while self.data[i] != 0 { @@ -61,17 +66,57 @@ impl ElfObject { std::str::from_utf8(&self.data[start..i]).map_err(|err| Error::ParseError(err.into())) } - fn make_section(&self, offset: usize, sh: &Shdr64) -> Option> { - let name = match self.section_name(sh) { + // TODO: consider caching these + fn parse_strtab(&self, sh_index: usize) -> Result { + let sh_start: usize = self.ehdr.e_shoff as usize; + let sh_size: usize = self.ehdr.e_shentsize.into(); + let offset: usize = sh_start + sh_size * sh_index; + + bincode::deserialize(&self.data[offset..offset + sh_size]) + .map_err(|err| Error::ParseError(err)) + } + + fn populate(&mut self) -> Result<(), Error> { + for i in 0..self.ehdr.e_shnum { + let i_usize: usize = i.into(); + let sh_start = self.ehdr.e_shoff as usize; + let sh_size = usize::from(self.ehdr.e_shentsize); + + let offset: usize = sh_start + i_usize * sh_size; + let shdr: Shdr64 = bincode::deserialize(&self.data[offset..offset + sh_size]) + .map_err(|err| Error::ParseError(err))?; + + if shdr.get_type() == Type::SymTab { + let ent_size = shdr.sh_entsize as usize; + let offset = shdr.sh_offset as usize; + let count = shdr.sh_size as usize / ent_size; + + for s_i in 0..count { + let start = offset + s_i * ent_size; + let s64 = Symbol64::deserialize(&self.data, start) + .map_err(|err| Error::ParseError(err))?; + self.symbols.push(s64); + } + } + // self.symbols.push(); + self.shdrs.push(shdr); + } + + Ok(()) + } + + fn make_section(&self, shdr: &Shdr64) -> Option> { + let sh_index: usize = self.ehdr.e_shstrndx.into(); + let name = match self.resolve_name(shdr.sh_name as usize, sh_index) { Ok(n) => n, Err(err) => return Some(Err(err)), }; let mut si = SectionInfo { object_index: self.object_index, - file_size: sh.sh_size, - data_size: sh.sh_size, - offset: offset as u64, + file_size: shdr.sh_size, + data_size: shdr.sh_size, + offset: shdr.sh_offset, }; if name.starts_with(".bss") { @@ -88,7 +133,7 @@ impl ElfObject { } } - fn make_symbol(&self, s64: &Symbol64, strtab: &[u8]) -> Symbol { + fn make_symbol(&self, s64: &Symbol64) -> Symbol { let binding = match s64.get_bind() { Bind::Global => Binding::Global, Bind::Local => Binding::Local, @@ -98,7 +143,6 @@ impl ElfObject { Symbol { object_index: self.object_index, - name: parse_strtab_name(&strtab, s64.st_name), binding, address: s64.st_value, size: s64.st_size, @@ -116,21 +160,13 @@ impl Relocatable for ElfObject { } fn sections(&self) -> SectionIterBox { - let iter = (0..self.ehdr.e_shnum).into_iter().filter_map(move |i| { - let i_usize = usize::from(i); - let sh_start = self.ehdr.e_shoff as usize; - let sh_size = usize::from(self.ehdr.e_shentsize); - - let offset: usize = sh_start + i_usize * sh_size; - let shr: Result = - bincode::deserialize(&self.data[offset..offset + sh_size]) - .map_err(|err| Error::ParseError(err)); - - match shr { - Err(err) => Some(Err(err)), - Ok(sh) => self.make_section(offset, &sh), - } - }); + let iter = self + .shdrs + .iter() + .filter_map(move |shdr| match shdr.get_type() { + Type::ProgBits | Type::NoBits => self.make_section(shdr), + _ => None, + }); Box::new(iter) } @@ -142,36 +178,13 @@ impl Relocatable for ElfObject { } fn symbols(&self) -> SymbolIterBox { - // if let Some(strtab_section) = self - // .elf - // .first_section_by(|s64| s64.header.get_type() == Type::StrTab && s64.name == ".strtab") - // { - // let strtab = match &strtab_section.contents { - // Contents64::Raw(bytes) => bytes, - // _ => panic!("Unexpected strtab content type"), - // }; - - // let iter = self - // .elf - // .sections - // .iter() - // .filter_map(move |s| match &s.contents { - // Contents64::Symbols(symbols) => { - // Some(symbols.iter().filter_map(move |sym| match sym.get_bind() { - // Bind::Global | Bind::Local | Bind::Weak => { - // Some(self.make_symbol(sym, strtab)) - // } - // _ => None, - // })) - // } - // _ => None, - // }) - // .flatten(); - - // Box::new(iter) - // } else { - Box::new(std::iter::empty()) - //} + Box::new(self.symbols.iter().map(move |s| { + // TODO: change SymbolIterBox to allow errors! + let name = self + .resolve_name(s.st_name as usize, s.st_other as usize) + .expect("Symbol name resolution"); + (name, self.make_symbol(s)) + })) } } @@ -221,12 +234,3 @@ fn parse_elf_header(data: &Mmap) -> Result { Ok(ehdr) } - -fn parse_shstrtab(data: &Mmap, ehdr: &Ehdr64) -> Result { - let idx: usize = ehdr.e_shstrndx.into(); - let sh_start: usize = ehdr.e_shoff as usize; - let sh_size: usize = ehdr.e_shentsize.into(); - let offset: usize = sh_start + sh_size * idx; - - bincode::deserialize(&data[offset..offset + sh_size]).map_err(|err| Error::ParseError(err)) -} diff --git a/src/linker.rs b/src/linker.rs index fcac3d5..0e7b84d 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -50,8 +50,8 @@ where fn process_symbols(&mut self) -> Result<(), Error> { for r in &self.relocatables { - for symbol in r.symbols() { - self.loadable.process_symbol(symbol, &self.relocatables)?; + for (name, symbol) in r.symbols() { + self.loadable.process_symbol(name, symbol)?; } }