mirror of
https://github.com/Noratrieb/elven-forest.git
synced 2026-01-14 18:55:01 +01:00
basic storage allocation
This commit is contained in:
parent
b76d57ee9d
commit
b04e3b8a55
7 changed files with 171 additions and 21 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
|
@ -197,12 +197,19 @@ dependencies = [
|
||||||
"bstr",
|
"bstr",
|
||||||
"clap",
|
"clap",
|
||||||
"elven-parser",
|
"elven-parser",
|
||||||
|
"indexmap",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "equivalent"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
|
|
@ -225,12 +232,28 @@ version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.14.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "2.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
|
||||||
|
dependencies = [
|
||||||
|
"equivalent",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
consts::{self as c, DynamicTag, ShType},
|
consts::{self as c, DynamicTag, ShType},
|
||||||
idx::{define_idx, ElfIndexExt, ToIdxUsize},
|
idx::{define_idx, ElfIndexExt, ToIdxUsize},
|
||||||
Addr, Offset,
|
Addr, Offset, write::Section,
|
||||||
};
|
};
|
||||||
use bstr::BStr;
|
use bstr::BStr;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ anyhow = "1.0.69"
|
||||||
bstr = "1.3.0"
|
bstr = "1.3.0"
|
||||||
clap = { version = "4.1.4", features = ["derive"] }
|
clap = { version = "4.1.4", features = ["derive"] }
|
||||||
elven-parser = { path = "../elven-parser" }
|
elven-parser = { path = "../elven-parser" }
|
||||||
|
indexmap = "2.0.2"
|
||||||
memmap2 = "0.5.8"
|
memmap2 = "0.5.8"
|
||||||
tracing = "0.1.37"
|
tracing = "0.1.37"
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
mod storage;
|
||||||
|
mod utils;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate tracing;
|
extern crate tracing;
|
||||||
|
|
||||||
|
|
@ -26,6 +29,14 @@ pub struct Opts {
|
||||||
pub objs: Vec<PathBuf>,
|
pub objs: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
struct FileId(usize);
|
||||||
|
|
||||||
|
struct ElfFile<'a> {
|
||||||
|
id: FileId,
|
||||||
|
elf: ElfReader<'a>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct SymDef<'a> {
|
struct SymDef<'a> {
|
||||||
_name: &'a BStr,
|
_name: &'a BStr,
|
||||||
|
|
@ -35,7 +46,7 @@ struct SymDef<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct LinkCtxt<'a> {
|
struct LinkCtxt<'a> {
|
||||||
elves: Vec<ElfReader<'a>>,
|
elves: Vec<ElfFile<'a>>,
|
||||||
sym_defs: HashMap<&'a BStr, SymDef<'a>>,
|
sym_defs: HashMap<&'a BStr, SymDef<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,17 +67,18 @@ pub fn run(opts: Opts) -> Result<()> {
|
||||||
bail!("you gotta supply at least one object file");
|
bail!("you gotta supply at least one object file");
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.objs.len() > 1 {
|
|
||||||
bail!("hey hey hey one stop back please. you want to link MULTIPLE files TOGETHER? im sorry i cant do that");
|
|
||||||
}
|
|
||||||
|
|
||||||
info!(objs=?opts.objs, "Linking files");
|
info!(objs=?opts.objs, "Linking files");
|
||||||
|
|
||||||
let elves = mmaps
|
let elves = mmaps
|
||||||
.iter()
|
.iter()
|
||||||
.zip(&opts.objs)
|
.zip(&opts.objs)
|
||||||
.map(|(mmap, path)| {
|
.enumerate()
|
||||||
ElfReader::new(mmap).with_context(|| format!("parsing ELF file {}", path.display()))
|
.map(|(idx, (mmap, path))| {
|
||||||
|
Ok(ElfFile {
|
||||||
|
id: FileId(idx),
|
||||||
|
elf: ElfReader::new(mmap)
|
||||||
|
.with_context(|| format!("parsing ELF file {}", path.display()))?,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
.collect::<Result<Vec<_>, anyhow::Error>>()?;
|
||||||
|
|
||||||
|
|
@ -75,14 +87,19 @@ pub fn run(opts: Opts) -> Result<()> {
|
||||||
sym_defs: HashMap::new(),
|
sym_defs: HashMap::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let storage =
|
||||||
|
storage::allocate_storage(BASE_EXEC_ADDR, &cx.elves).context("while allocating storage")?;
|
||||||
|
|
||||||
|
dbg!(storage);
|
||||||
|
|
||||||
cx.resolve()?;
|
cx.resolve()?;
|
||||||
|
|
||||||
dbg!(cx.sym_defs);
|
dbg!(cx.sym_defs);
|
||||||
|
|
||||||
let text_sh = cx.elves[0].section_header_by_name(b".text")?;
|
let text_sh = cx.elves[0].elf.section_header_by_name(b".text")?;
|
||||||
let text_content = cx.elves[0].section_content(text_sh)?;
|
let text_content = cx.elves[0].elf.section_content(text_sh)?;
|
||||||
|
|
||||||
let _start_sym = cx.elves[0].symbol_by_name(b"_start")?;
|
let _start_sym = cx.elves[0].elf.symbol_by_name(b"_start")?;
|
||||||
|
|
||||||
write_output(&opts, text_content, _start_sym.value)?;
|
write_output(&opts, text_content, _start_sym.value)?;
|
||||||
|
|
||||||
|
|
@ -90,12 +107,12 @@ pub fn run(opts: Opts) -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const BASE_EXEC_ADDR: Addr = Addr(0x400000); // whatever ld does
|
pub const BASE_EXEC_ADDR: Addr = Addr(0x400000); // whatever ld does
|
||||||
pub const DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE: u64 = 0x1000;
|
pub const DEFAULT_PAGE_ALIGN: u64 = 0x1000;
|
||||||
|
|
||||||
impl<'a> LinkCtxt<'a> {
|
impl<'a> LinkCtxt<'a> {
|
||||||
fn resolve(&mut self) -> Result<()> {
|
fn resolve(&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.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.
|
// Undefined symbols are not a definition.
|
||||||
|
|
@ -104,8 +121,10 @@ impl<'a> LinkCtxt<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = match ty.0 {
|
let name = match ty.0 {
|
||||||
c::STT_SECTION => elf.sh_string(elf.section_header(e_sym.shndx)?.name)?,
|
c::STT_SECTION => elf
|
||||||
_ => elf.string(e_sym.name)?,
|
.elf
|
||||||
|
.sh_string(elf.elf.section_header(e_sym.shndx)?.name)?,
|
||||||
|
_ => elf.elf.string(e_sym.name)?,
|
||||||
};
|
};
|
||||||
|
|
||||||
match self.sym_defs.entry(name) {
|
match self.sym_defs.entry(name) {
|
||||||
|
|
@ -154,7 +173,7 @@ fn write_output(opts: &Opts, text: &[u8], entry_offset_from_text: Addr) -> Resul
|
||||||
fixed_entsize: None,
|
fixed_entsize: None,
|
||||||
content: text.to_vec(),
|
content: text.to_vec(),
|
||||||
// align nicely
|
// align nicely
|
||||||
addr_align: Some(NonZeroU64::new(DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE).unwrap()),
|
addr_align: Some(NonZeroU64::new(DEFAULT_PAGE_ALIGN).unwrap()),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let elf_header_and_program_headers = ProgramHeader {
|
let elf_header_and_program_headers = ProgramHeader {
|
||||||
|
|
@ -168,13 +187,12 @@ fn write_output(opts: &Opts, text: &[u8], entry_offset_from_text: Addr) -> Resul
|
||||||
paddr: BASE_EXEC_ADDR,
|
paddr: BASE_EXEC_ADDR,
|
||||||
filesz: 176, // FIXME: Do not hardocde this lol
|
filesz: 176, // FIXME: Do not hardocde this lol
|
||||||
memsz: 176,
|
memsz: 176,
|
||||||
align: DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE,
|
align: DEFAULT_PAGE_ALIGN,
|
||||||
};
|
};
|
||||||
|
|
||||||
write.add_program_header(elf_header_and_program_headers);
|
write.add_program_header(elf_header_and_program_headers);
|
||||||
|
|
||||||
let entry_addr =
|
let entry_addr = BASE_EXEC_ADDR + DEFAULT_PAGE_ALIGN + entry_offset_from_text;
|
||||||
BASE_EXEC_ADDR + DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE + entry_offset_from_text;
|
|
||||||
|
|
||||||
let text_program_header = ProgramHeader {
|
let text_program_header = ProgramHeader {
|
||||||
r#type: PT_LOAD.into(),
|
r#type: PT_LOAD.into(),
|
||||||
|
|
@ -187,7 +205,7 @@ fn write_output(opts: &Opts, text: &[u8], entry_offset_from_text: Addr) -> Resul
|
||||||
paddr: entry_addr,
|
paddr: entry_addr,
|
||||||
filesz: text.len() as u64,
|
filesz: text.len() as u64,
|
||||||
memsz: text.len() as u64,
|
memsz: text.len() as u64,
|
||||||
align: DEFAULT_PROGRAM_HEADER_ALIGN_THAT_LD_USES_HERE,
|
align: DEFAULT_PAGE_ALIGN,
|
||||||
};
|
};
|
||||||
|
|
||||||
write.add_program_header(text_program_header);
|
write.add_program_header(text_program_header);
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::fmt()
|
tracing_subscriber::fmt()
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
EnvFilter::builder()
|
EnvFilter::builder()
|
||||||
.with_default_directive(LevelFilter::INFO.into())
|
.with_default_directive(LevelFilter::DEBUG.into())
|
||||||
.from_env_lossy(),
|
.from_env_lossy(),
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
|
|
||||||
76
elven-wald/src/storage.rs
Normal file
76
elven-wald/src/storage.rs
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
use std::ops::Add;
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use bstr::{BStr, BString};
|
||||||
|
use elven_parser::{read::ElfReadError, Addr};
|
||||||
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
|
use crate::{utils::AlignExt, ElfFile, FileId, DEFAULT_PAGE_ALIGN};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Allocation {
|
||||||
|
file: FileId,
|
||||||
|
section: BString,
|
||||||
|
size: u64,
|
||||||
|
align: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SegmentPart {
|
||||||
|
base: Addr,
|
||||||
|
file: FileId,
|
||||||
|
section: BString,
|
||||||
|
size: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StorageAllocation {
|
||||||
|
segment_parts: Vec<SegmentPart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn allocate_storage<'a>(base_addr: Addr, files: &[ElfFile<'a>]) -> Result<StorageAllocation> {
|
||||||
|
let mut allocs = IndexMap::<_, Vec<Allocation>>::new();
|
||||||
|
|
||||||
|
for file in files {
|
||||||
|
let elf = file.elf;
|
||||||
|
|
||||||
|
for name in [b".text".as_slice(), b".data", b".bss"] {
|
||||||
|
let section = elf.section_header_by_name(name);
|
||||||
|
match section {
|
||||||
|
Ok(section) => {
|
||||||
|
allocs.entry(BStr::new(name)).or_default().push(Allocation {
|
||||||
|
file: file.id,
|
||||||
|
section: name.into(),
|
||||||
|
size: section.size,
|
||||||
|
align: section.addralign,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
Err(ElfReadError::NotFoundByName(_, _)) => {}
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!(?allocs, "Allocation pass one completed");
|
||||||
|
|
||||||
|
let mut current_addr = base_addr;
|
||||||
|
let mut segment_parts = Vec::new();
|
||||||
|
for section in allocs {
|
||||||
|
current_addr = current_addr.align_up(DEFAULT_PAGE_ALIGN);
|
||||||
|
for alloc in section.1 {
|
||||||
|
let align = alloc.align;
|
||||||
|
let addr = current_addr.align_up(align);
|
||||||
|
|
||||||
|
current_addr = addr + alloc.size;
|
||||||
|
|
||||||
|
segment_parts.push(SegmentPart {
|
||||||
|
base: addr,
|
||||||
|
file: alloc.file,
|
||||||
|
size: alloc.size,
|
||||||
|
section: section.0.to_owned(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(StorageAllocation { segment_parts })
|
||||||
|
}
|
||||||
32
elven-wald/src/utils.rs
Normal file
32
elven-wald/src/utils.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
use elven_parser::Addr;
|
||||||
|
|
||||||
|
pub trait AlignExt<T>: Copy {
|
||||||
|
fn align_down(self, align: T) -> Self;
|
||||||
|
fn align_up(self, align: T) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlignExt<u64> for u64 {
|
||||||
|
fn align_down(self, align: Self) -> Self {
|
||||||
|
assert!(align.is_power_of_two() && align > 0);
|
||||||
|
// We want to set all the aligment bits to zero.
|
||||||
|
// 0b0101 aligned to 0b0100 => 0b0100
|
||||||
|
// mask is !0b0011 = 0b1100
|
||||||
|
let mask = !(align - 1);
|
||||||
|
self & mask
|
||||||
|
}
|
||||||
|
fn align_up(self, align: Self) -> Self {
|
||||||
|
assert!(align.is_power_of_two() && align > 0);
|
||||||
|
// 0b0101 aligned to 0b0100 => 0b1000
|
||||||
|
(self + align - 1) & !(align - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AlignExt<u64> for Addr {
|
||||||
|
fn align_down(self, align: u64) -> Self {
|
||||||
|
Addr(self.u64().align_down(align))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn align_up(self, align: u64) -> Self {
|
||||||
|
Addr(self.u64().align_up(align))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue