diff --git a/src/common.rs b/src/common.rs index 7ff3fc0..6f2b81c 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,11 +1,9 @@ -mod lazy; mod loadable; mod output; mod relocatable; mod section; mod symbol; -pub use lazy::*; pub use loadable::*; pub use output::*; pub use relocatable::*; diff --git a/src/common/lazy.rs b/src/common/lazy.rs deleted file mode 100644 index 44732e0..0000000 --- a/src/common/lazy.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::error::Error; -pub trait Lazy { - /// Resolve VALUE, blocking load from the SOURCE - fn value(&self, src: &SOURCE) -> Result; - - /// Check if already resolved - fn resolved(&self) -> bool; -} diff --git a/src/common/loadable.rs b/src/common/loadable.rs index 9d4dcfc..57c4202 100644 --- a/src/common/loadable.rs +++ b/src/common/loadable.rs @@ -34,11 +34,12 @@ impl SegmentSections { // TODO: use attributes for field section names, indexes etc. #[derive(Default)] pub struct Loadable { + pub start_offset: Option, + text: SegmentSections, rodata: SegmentSections, data: SegmentSections, bss: SegmentSections, - pub start_offset: Option, } impl Loadable { diff --git a/src/common/relocatable.rs b/src/common/relocatable.rs index 9c26d19..0bd6b69 100644 --- a/src/common/relocatable.rs +++ b/src/common/relocatable.rs @@ -3,7 +3,7 @@ use std::{fmt::Display, path::PathBuf}; use crate::error::Error; -use super::Section; +use super::{Section, Symbol}; #[derive(Clone, Copy)] // index into section of given object stored in the linker @@ -28,7 +28,10 @@ impl DataIndex { } } -pub type BSI<'iter> = Box> + 'iter>; +pub type SectionIterBox<'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 pub trait Relocatable: Display + Sized { @@ -37,7 +40,9 @@ pub trait Relocatable: Display + Sized { fn origin(&self) -> &Path; // not same as section's path since this one's supposed to be cannonical - fn sections(&self) -> BSI; + fn sections(&self) -> SectionIterBox; fn section_data(&self, section_index: DataIndex) -> Result<&[u8], Error>; + + fn symbols(&self) -> SymbolIterBox; } diff --git a/src/common/symbol.rs b/src/common/symbol.rs index 3572ac0..b52329d 100644 --- a/src/common/symbol.rs +++ b/src/common/symbol.rs @@ -1,14 +1,13 @@ -#[derive(Debug, Default)] -pub struct Symbol<'a> { - pub index: u32, - pub str_ref: Option<&'a str>, +#[derive(Clone, Copy)] +pub enum Binding { + Local, + Global, + Weak, } -impl Symbol<'_> { - pub fn new(index: u32) -> Self { - Self { - index, - str_ref: None, - } - } +pub struct Symbol { + pub name: String, + pub binding: Binding, + pub address: u64, + pub size: u64, } diff --git a/src/formats/elf.rs b/src/formats/elf.rs index 2f5e1c5..e8f33c6 100644 --- a/src/formats/elf.rs +++ b/src/formats/elf.rs @@ -1,13 +1,11 @@ use std::path::PathBuf; -use crate::common::{Lazy, Symbol}; use crate::error::Error; use crate::linker::Linker; mod object; mod output; -use elf_utilities::file::ELF64; pub use object::*; pub use output::*; @@ -17,13 +15,3 @@ impl Linker { Ok(Self::new(ElfOutput::new(destination)?)) } } - -impl<'data> Lazy<&'data str, ELF64> for Symbol<'data> { - fn value(&self, _src: &ELF64) -> Result<&'data str, Error> { - Err(Error::InvalidSectionData) // TODO - } - - fn resolved(&self) -> bool { - self.str_ref.is_some() - } -} diff --git a/src/formats/elf/object.rs b/src/formats/elf/object.rs index 32d06d8..a8698cd 100644 --- a/src/formats/elf/object.rs +++ b/src/formats/elf/object.rs @@ -4,9 +4,14 @@ use std::{ path::{Path, PathBuf}, }; -use crate::common::{DataIndex, Relocatable, Section, SectionInfo}; -use crate::{common::BSI, error::Error}; -use elf_utilities::{file::ELF64, parser::read_elf64}; +use crate::common::{Binding, DataIndex, Relocatable, Section, SectionInfo, Symbol, SymbolIterBox}; +use crate::{common::SectionIterBox, error::Error}; +use elf_utilities::{ + file::ELF64, + parser::read_elf64, + section::{Contents64, Type}, + symbol::{Bind, Symbol64}, +}; pub struct ElfObject { object_index: usize, @@ -45,9 +50,7 @@ impl Relocatable for ElfObject { &self.origin } - fn sections(&self) -> BSI { - use elf_utilities::section::{Contents64, Type}; - + fn sections(&self) -> SectionIterBox { let iter = self .elf .sections @@ -95,7 +98,6 @@ impl Relocatable for ElfObject { } fn section_data(&self, index: DataIndex) -> Result<&[u8], Error> { - use elf_utilities::section::Contents64; let section = &self.elf.sections[index.section_index]; match §ion.contents { @@ -103,6 +105,39 @@ impl Relocatable for ElfObject { _ => Err(Error::InvalidSectionData), } } + + 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(make_symbol(sym, strtab)) + } + _ => None, + })) + } + _ => None, + }) + .flatten(); + + Box::new(iter) + } else { + Box::new(std::iter::empty()) + } + } } impl Display for ElfObject { @@ -123,13 +158,34 @@ impl Display for ElfObject { } } -// impl TryFrom for ElfObject { -// type Error = Error; +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 try_from(path: PathBuf) -> Result { -// Self::new(path) -// } -// } +fn parse_strtab_name(strtab: &Vec, idx: u32) -> String { + let bytes: Vec = strtab + .iter() + .skip(idx as usize) + .take_while(|byte| **byte != 0x00) + .copied() + .collect(); + + std::str::from_utf8(&bytes) + .expect("Symbol name parse") + .to_string() +} fn is_relocatable(elf: &ELF64) -> Result<(), Error> { use elf_utilities::header::Type; diff --git a/src/linker.rs b/src/linker.rs index 288c9d8..7d1e609 100644 --- a/src/linker.rs +++ b/src/linker.rs @@ -1,8 +1,4 @@ -use std::{ - fmt::Display, - io::ErrorKind, - path::{Path, PathBuf}, -}; +use std::{fmt::Display, path::PathBuf}; use crate::{ common::{DataIndex, Loadable, Output, Relocatable}, @@ -33,35 +29,33 @@ where } pub fn add_relocatable(&mut self, origin: PathBuf) -> Result<(), Error> { - self.relocatables.push(R::new( - origin, - DataIndex::for_object(self.relocatables.len()), - )?); + let r = R::new(origin, DataIndex::for_object(self.relocatables.len()))?; + + // TODO: parallelize? + for s in r.sections() { + self.loadable.process_section(s?)?; + } + + self.relocatables.push(r); Ok(()) } pub fn link(mut self) -> Result { - for r in self.relocatables.iter() { - for s in r.sections() { - self.loadable.process_section(s?)?; - } - } - self.loadable.start_offset = Some(4096); // TODO: get from .start symbol location self.output.finalize(&self.relocatables, &self.loadable) } - pub fn object_path(origin: &Path) -> Result { - let mut dest = std::fs::canonicalize(origin)?; - if !dest.pop() { - let err = std::io::Error::new(ErrorKind::Other, "Destination path invalid"); - Err(Error::IOError(Box::new(err))) - } else { - dest.push("rld.out"); - Ok(dest) - } - } + // pub fn object_path(origin: &Path) -> Result { + // let mut dest = std::fs::canonicalize(origin)?; + // if !dest.pop() { + // let err = std::io::Error::new(ErrorKind::Other, "Destination path invalid"); + // Err(Error::IOError(Box::new(err))) + // } else { + // dest.push("rld.out"); + // Ok(dest) + // } + // } } impl Display for Linker