basic symbol resolution

This commit is contained in:
nora 2023-10-21 21:11:33 +02:00
parent 898e84363a
commit 0b3225c92c
3 changed files with 88 additions and 36 deletions

View file

@ -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 { impl PartialOrd<$ty> for $struct_name {
fn partial_cmp(&self, other: &$ty) -> Option<std::cmp::Ordering> { fn partial_cmp(&self, other: &$ty) -> Option<std::cmp::Ordering> {
self.0.partial_cmp(other) self.0.partial_cmp(other)

View file

@ -15,13 +15,20 @@ use elven_parser::{
}; };
use memmap2::Mmap; use memmap2::Mmap;
use std::{ use std::{
cell::RefCell,
collections::{hash_map::Entry, HashMap}, collections::{hash_map::Entry, HashMap},
fmt::Debug,
fs::{self, File}, fs::{self, File},
io::{BufWriter, Write}, io::{BufWriter, Write},
iter, iter,
num::NonZeroU64, num::NonZeroU64,
path::PathBuf, path::{Path, PathBuf},
}; };
use storage::StorageAllocation;
thread_local! {
static ELF_PATHS: RefCell<Vec<PathBuf>> = RefCell::new(Vec::new());
}
#[derive(Debug, Clone, Parser)] #[derive(Debug, Clone, Parser)]
pub struct Opts { pub struct Opts {
@ -30,28 +37,52 @@ pub struct Opts {
pub objs: Vec<PathBuf>, pub objs: Vec<PathBuf>,
} }
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
struct FileId(usize); 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> { struct ElfFile<'a> {
id: FileId, id: FileId,
elf: ElfReader<'a>, elf: ElfReader<'a>,
} }
#[derive(Debug)] #[derive(Debug)]
struct SymDef<'a> { struct Symbol<'a> {
_name: &'a BStr, name: &'a BStr,
defined_in: u32, definition: Option<SymbolDefinition>,
/// `shndx` from ELF }
_refers_to_section: SectionIdx,
#[derive(Debug)]
struct SymbolDefinition {
location: SectionId,
value: Addr,
size: u64,
} }
struct LinkCtxt<'a> { struct LinkCtxt<'a> {
elves: Vec<ElfFile<'a>>, elves: Vec<ElfFile<'a>>,
sym_defs: HashMap<&'a BStr, SymDef<'a>>, sym_defs: HashMap<&'a BStr, Symbol<'a>>,
storage: StorageAllocation,
} }
pub fn run(opts: Opts) -> Result<()> { pub fn run(opts: Opts) -> Result<()> {
ELF_PATHS.set(opts.objs.clone());
let mmaps = opts let mmaps = opts
.objs .objs
.iter() .iter()
@ -83,19 +114,22 @@ pub fn run(opts: Opts) -> Result<()> {
}) })
.collect::<Result<Vec<_>, anyhow::Error>>()?; .collect::<Result<Vec<_>, anyhow::Error>>()?;
let storage =
storage::allocate_storage(BASE_EXEC_ADDR, &elves).context("while allocating storage")?;
let mut cx = LinkCtxt { let mut cx = LinkCtxt {
elves, elves,
sym_defs: HashMap::new(), sym_defs: HashMap::new(),
storage,
}; };
let storage = dbg!(&cx.storage);
storage::allocate_storage(BASE_EXEC_ADDR, &cx.elves).context("while allocating storage")?;
dbg!(&storage); cx.sym_first_pass()?;
let mut writer = create_elf(); 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() { let exec = if section.name == b"text".as_slice() {
ShFlags::SHF_EXECINSTR ShFlags::SHF_EXECINSTR
} else { } else {
@ -128,7 +162,7 @@ pub fn run(opts: Opts) -> Result<()> {
})?; })?;
} }
cx.resolve()?; write_elf_to_file(writer, &opts.output)?;
dbg!(cx.sym_defs); 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; pub const DEFAULT_PAGE_ALIGN: u64 = 0x1000;
impl<'a> LinkCtxt<'a> { 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 (elf_idx, elf) in self.elves.iter().enumerate() {
for e_sym in elf.elf.symbols()? { for e_sym in elf.elf.symbols()? {
let ty = e_sym.info.r#type(); let ty = e_sym.info.r#type();
// Undefined symbols are not a definition. if ty.0 == c::STT_SECTION {
if e_sym.shndx == SHN_UNDEF {
continue; continue;
} }
let name = match ty.0 { let name = elf.elf.string(e_sym.name)?;
c::STT_SECTION => elf
.elf let definition = if e_sym.shndx == SHN_UNDEF {
.sh_string(elf.elf.section_header(e_sym.shndx)?.name)?, None
_ => elf.elf.string(e_sym.name)?, } 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) { match self.sym_defs.entry(name) {
Entry::Occupied(entry) => { Entry::Occupied(mut entry) => {
bail!("duplicate symbol {name}. Already defined in {}, duplicate definition in {}", entry.get().defined_in, elf_idx); 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::Vacant(entry) => {
entry.insert(SymDef { entry.insert(Symbol { name, definition });
_name: name,
defined_in: elf_idx as u32,
_refers_to_section: e_sym.shndx,
});
} }
} }
} }
@ -252,16 +294,20 @@ fn write_output(opts: &Opts, text: &[u8], entry_offset_from_text: Addr) -> Resul
write.set_entry(entry_addr); write.set_entry(entry_addr);
let output = write.write().context("writing output file")?; write_elf_to_file(write, &opts.output)?;
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)?;
Ok(()) 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<()> { fn make_file_executable(file: &File) -> Result<()> {
#[allow(unused_mut)] #[allow(unused_mut)]
let mut permissions = file.metadata()?.permissions(); let mut permissions = file.metadata()?.permissions();

View file

@ -1,5 +1,3 @@
use std::ops::Add;
use anyhow::Result; use anyhow::Result;
use bstr::{BStr, BString}; use bstr::{BStr, BString};
use elven_parser::{read::ElfReadError, Addr}; use elven_parser::{read::ElfReadError, Addr};