From 0b3225c92cd119ad8688dca8274551a296888a70 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 21 Oct 2023 21:11:33 +0200 Subject: [PATCH] basic symbol resolution --- elven-parser/src/consts.rs | 8 +++ elven-wald/src/lib.rs | 114 ++++++++++++++++++++++++++----------- elven-wald/src/storage.rs | 2 - 3 files changed, 88 insertions(+), 36 deletions(-) diff --git a/elven-parser/src/consts.rs b/elven-parser/src/consts.rs index 1429033..cec7da6 100644 --- a/elven-parser/src/consts.rs +++ b/elven-parser/src/consts.rs @@ -57,6 +57,14 @@ macro_rules! const_group_with_fmt { } } + impl PartialEq<$struct_name> for $struct_name { + fn eq(&self, other: &$struct_name) -> bool { + self.0 == other.0 + } + } + + impl Eq for $struct_name {} + impl PartialOrd<$ty> for $struct_name { fn partial_cmp(&self, other: &$ty) -> Option { self.0.partial_cmp(other) diff --git a/elven-wald/src/lib.rs b/elven-wald/src/lib.rs index 78cc912..b616524 100644 --- a/elven-wald/src/lib.rs +++ b/elven-wald/src/lib.rs @@ -15,13 +15,20 @@ use elven_parser::{ }; use memmap2::Mmap; use std::{ + cell::RefCell, collections::{hash_map::Entry, HashMap}, + fmt::Debug, fs::{self, File}, io::{BufWriter, Write}, iter, num::NonZeroU64, - path::PathBuf, + path::{Path, PathBuf}, }; +use storage::StorageAllocation; + +thread_local! { + static ELF_PATHS: RefCell> = RefCell::new(Vec::new()); +} #[derive(Debug, Clone, Parser)] pub struct Opts { @@ -30,28 +37,52 @@ pub struct Opts { pub objs: Vec, } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] struct FileId(usize); +impl Debug for FileId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ELF_PATHS.with(|p| { + let paths = p.borrow(); + let name = &paths[self.0]; + write!(f, "{}#{{{}}}", self.0, name.display(),) + }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +struct SectionId { + file: FileId, + section: SectionIdx, +} + struct ElfFile<'a> { id: FileId, elf: ElfReader<'a>, } #[derive(Debug)] -struct SymDef<'a> { - _name: &'a BStr, - defined_in: u32, - /// `shndx` from ELF - _refers_to_section: SectionIdx, +struct Symbol<'a> { + name: &'a BStr, + definition: Option, +} + +#[derive(Debug)] +struct SymbolDefinition { + location: SectionId, + value: Addr, + size: u64, } struct LinkCtxt<'a> { elves: Vec>, - sym_defs: HashMap<&'a BStr, SymDef<'a>>, + sym_defs: HashMap<&'a BStr, Symbol<'a>>, + storage: StorageAllocation, } pub fn run(opts: Opts) -> Result<()> { + ELF_PATHS.set(opts.objs.clone()); + let mmaps = opts .objs .iter() @@ -83,19 +114,22 @@ pub fn run(opts: Opts) -> Result<()> { }) .collect::, anyhow::Error>>()?; + let storage = + storage::allocate_storage(BASE_EXEC_ADDR, &elves).context("while allocating storage")?; + let mut cx = LinkCtxt { elves, sym_defs: HashMap::new(), + storage, }; - let storage = - storage::allocate_storage(BASE_EXEC_ADDR, &cx.elves).context("while allocating storage")?; + dbg!(&cx.storage); - dbg!(&storage); + cx.sym_first_pass()?; let mut writer = create_elf(); - for section in &storage.sections { + for section in &cx.storage.sections { let exec = if section.name == b"text".as_slice() { ShFlags::SHF_EXECINSTR } else { @@ -128,7 +162,7 @@ pub fn run(opts: Opts) -> Result<()> { })?; } - cx.resolve()?; + write_elf_to_file(writer, &opts.output)?; dbg!(cx.sym_defs); @@ -146,33 +180,41 @@ pub const BASE_EXEC_ADDR: Addr = Addr(0x400000); // whatever ld does pub const DEFAULT_PAGE_ALIGN: u64 = 0x1000; impl<'a> LinkCtxt<'a> { - fn resolve(&mut self) -> Result<()> { + fn sym_first_pass(&mut self) -> Result<()> { for (elf_idx, elf) in self.elves.iter().enumerate() { for e_sym in elf.elf.symbols()? { let ty = e_sym.info.r#type(); - // Undefined symbols are not a definition. - if e_sym.shndx == SHN_UNDEF { + if ty.0 == c::STT_SECTION { continue; } - let name = match ty.0 { - c::STT_SECTION => elf - .elf - .sh_string(elf.elf.section_header(e_sym.shndx)?.name)?, - _ => elf.elf.string(e_sym.name)?, + let name = elf.elf.string(e_sym.name)?; + + let definition = if e_sym.shndx == SHN_UNDEF { + None + } else { + Some(SymbolDefinition { + location: SectionId { + file: FileId(elf_idx), + section: e_sym.shndx, + }, + value: e_sym.value, + size: e_sym.size, + }) }; match self.sym_defs.entry(name) { - Entry::Occupied(entry) => { - bail!("duplicate symbol {name}. Already defined in {}, duplicate definition in {}", entry.get().defined_in, elf_idx); + Entry::Occupied(mut entry) => { + match (&mut entry.get_mut().definition, definition) { + (Some(_), Some(_)) => bail!("duplicate definition for symbol {name}"), + (new @ None, def @ Some(_)) => *new = def, + (Some(_), None) => {} + (None, None) => {} + } } Entry::Vacant(entry) => { - entry.insert(SymDef { - _name: name, - defined_in: elf_idx as u32, - _refers_to_section: e_sym.shndx, - }); + entry.insert(Symbol { name, definition }); } } } @@ -252,16 +294,20 @@ fn write_output(opts: &Opts, text: &[u8], entry_offset_from_text: Addr) -> Resul write.set_entry(entry_addr); - let output = write.write().context("writing output file")?; - - let mut output_file = fs::File::create(&opts.output).context("creating ./a.out")?; - BufWriter::new(&mut output_file).write_all(&output)?; - - make_file_executable(&output_file)?; + write_elf_to_file(write, &opts.output)?; Ok(()) } +fn write_elf_to_file(elf: ElfWriter, path: &Path) -> Result<()> { + let output = elf.write().context("writing output file")?; + + let mut output_file = fs::File::create(path).context("creating ./a.out")?; + BufWriter::new(&mut output_file).write_all(&output)?; + + make_file_executable(&output_file) +} + fn make_file_executable(file: &File) -> Result<()> { #[allow(unused_mut)] let mut permissions = file.metadata()?.permissions(); diff --git a/elven-wald/src/storage.rs b/elven-wald/src/storage.rs index fb1b3bf..13f492d 100644 --- a/elven-wald/src/storage.rs +++ b/elven-wald/src/storage.rs @@ -1,5 +1,3 @@ -use std::ops::Add; - use anyhow::Result; use bstr::{BStr, BString}; use elven_parser::{read::ElfReadError, Addr};