mirror of
https://github.com/Noratrieb/elven-forest.git
synced 2026-01-14 10:45:03 +01:00
brain
This commit is contained in:
parent
177c869133
commit
dc4cf750aa
4 changed files with 100 additions and 34 deletions
|
|
@ -7,6 +7,7 @@ edition = "2021"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1.0.69"
|
||||
bstr = "1.3.0"
|
||||
clap = { version = "4.1.4", features = ["derive"] }
|
||||
elven-parser = { path = "../elven-parser" }
|
||||
memmap2 = "0.5.8"
|
||||
|
|
|
|||
|
|
@ -2,17 +2,20 @@
|
|||
extern crate tracing;
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
use bstr::BStr;
|
||||
use clap::Parser;
|
||||
use elven_parser::{
|
||||
consts::{self as c, PhFlags, SectionIdx, ShFlags, ShType, PT_LOAD, SHT_PROGBITS},
|
||||
consts::{self as c, PhFlags, SectionIdx, ShFlags, ShType, PT_LOAD, SHN_UNDEF, SHT_PROGBITS},
|
||||
read::{ElfIdent, ElfReader},
|
||||
write::{self, ElfWriter, ProgramHeader, Section, SectionRelativeAbsoluteAddr},
|
||||
Addr, Offset,
|
||||
};
|
||||
use memmap2::Mmap;
|
||||
use std::{
|
||||
fs,
|
||||
collections::{hash_map::Entry, HashMap},
|
||||
fs::{self, File},
|
||||
io::{BufWriter, Write},
|
||||
num::NonZeroU64,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
|
|
@ -21,6 +24,19 @@ pub struct Opts {
|
|||
pub objs: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct SymDef<'a> {
|
||||
name: &'a BStr,
|
||||
defined_in: u32,
|
||||
/// `shndx` from ELF
|
||||
refers_to_section: SectionIdx,
|
||||
}
|
||||
|
||||
struct LinkCtxt<'a> {
|
||||
elves: Vec<ElfReader<'a>>,
|
||||
sym_defs: HashMap<&'a BStr, SymDef<'a>>,
|
||||
}
|
||||
|
||||
pub fn run(opts: Opts) -> Result<()> {
|
||||
let mmaps = opts
|
||||
.objs
|
||||
|
|
@ -44,7 +60,7 @@ pub fn run(opts: Opts) -> Result<()> {
|
|||
|
||||
info!(objs=?opts.objs, "Linking files");
|
||||
|
||||
let elfs = mmaps
|
||||
let elves = mmaps
|
||||
.iter()
|
||||
.zip(&opts.objs)
|
||||
.map(|(mmap, path)| {
|
||||
|
|
@ -52,12 +68,19 @@ pub fn run(opts: Opts) -> Result<()> {
|
|||
})
|
||||
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
||||
|
||||
let elf = elfs[0];
|
||||
let mut cx = LinkCtxt {
|
||||
elves,
|
||||
sym_defs: HashMap::new(),
|
||||
};
|
||||
|
||||
let text_sh = elf.section_header_by_name(b".text")?;
|
||||
let text_content = elf.section_content(text_sh)?;
|
||||
cx.resolve()?;
|
||||
|
||||
let _start_sym = elf.symbol_by_name(b"_start")?;
|
||||
dbg!(cx.sym_defs);
|
||||
|
||||
let text_sh = cx.elves[0].section_header_by_name(b".text")?;
|
||||
let text_content = cx.elves[0].section_content(text_sh)?;
|
||||
|
||||
let _start_sym = cx.elves[0].symbol_by_name(b"_start")?;
|
||||
|
||||
write_output(text_content, _start_sym.value)?;
|
||||
|
||||
|
|
@ -67,6 +90,41 @@ pub fn run(opts: Opts) -> Result<()> {
|
|||
pub const BASE_EXEC_ADDR: Addr = Addr(0x400000); // whatever ld does
|
||||
pub const DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE: u64 = 0x1000;
|
||||
|
||||
impl<'a> LinkCtxt<'a> {
|
||||
fn resolve(&mut self) -> Result<()> {
|
||||
for (elf_idx, elf) in self.elves.iter().enumerate() {
|
||||
for e_sym in elf.symbols()? {
|
||||
let ty = e_sym.info.r#type();
|
||||
|
||||
// Undefined symbols are not a definition.
|
||||
if e_sym.shndx == SHN_UNDEF {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = match ty.0 {
|
||||
c::STT_SECTION => elf.sh_string(elf.section_header(e_sym.shndx)?.name)?,
|
||||
_ => elf.string(e_sym.name)?,
|
||||
};
|
||||
|
||||
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::Vacant(entry) => {
|
||||
entry.insert(SymDef {
|
||||
name,
|
||||
defined_in: elf_idx as u32,
|
||||
refers_to_section: e_sym.shndx,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn write_output(text: &[u8], entry_offset_from_text: Addr) -> Result<()> {
|
||||
let ident = ElfIdent {
|
||||
magic: *c::ELFMAG,
|
||||
|
|
@ -93,7 +151,8 @@ fn write_output(text: &[u8], entry_offset_from_text: Addr) -> Result<()> {
|
|||
flags: ShFlags::SHF_ALLOC | ShFlags::SHF_EXECINSTR,
|
||||
fixed_entsize: None,
|
||||
content: text.to_vec(),
|
||||
addr_align: None,
|
||||
// align nicely
|
||||
addr_align: Some(NonZeroU64::new(DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE).unwrap()),
|
||||
})?;
|
||||
|
||||
let elf_header_and_program_headers = ProgramHeader {
|
||||
|
|
@ -138,15 +197,20 @@ fn write_output(text: &[u8], entry_offset_from_text: Addr) -> Result<()> {
|
|||
let mut output_file = fs::File::create("a.out").context("creating ./a.out")?;
|
||||
BufWriter::new(&mut output_file).write_all(&output)?;
|
||||
|
||||
make_file_executable(&output_file)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn make_file_executable(file: &File) -> Result<()> {
|
||||
#[allow(unused_mut)]
|
||||
let mut permissions = output_file.metadata()?.permissions();
|
||||
let mut permissions = file.metadata()?.permissions();
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
let mode = permissions.mode();
|
||||
permissions.set_mode(mode | 0o111);
|
||||
};
|
||||
output_file.set_permissions(permissions)?;
|
||||
|
||||
file.set_permissions(permissions)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue