mirror of
https://github.com/Noratrieb/elven-forest.git
synced 2026-01-16 19:35:02 +01:00
basic symbol resolution
This commit is contained in:
parent
898e84363a
commit
0b3225c92c
3 changed files with 88 additions and 36 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue