diff --git a/crates/molotov-core/src/lib.rs b/crates/molotov-core/src/lib.rs index cdf6125..4880353 100644 --- a/crates/molotov-core/src/lib.rs +++ b/crates/molotov-core/src/lib.rs @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-or-later pub mod dynamic; pub mod elf; +pub mod linker; pub mod mmap; pub mod reloc; pub mod symbols; diff --git a/crates/molotov-core/src/linker.rs b/crates/molotov-core/src/linker.rs new file mode 100644 index 0000000..1b1bd4c --- /dev/null +++ b/crates/molotov-core/src/linker.rs @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use crate::elf::ElfBinary; +use crate::mmap::MappedImage; +use crate::symbols::SymbolTriage; + +pub struct LoadedLibrary { + pub mapping: MappedImage, + pub base_addr: u64, +} + +pub struct BionicLinker { + triage: SymbolTriage, +} + +impl Default for BionicLinker { + fn default() -> Self { + Self::new() + } +} + +impl BionicLinker { + pub fn new() -> Self { + Self { + triage: SymbolTriage::new(), + } + } + + pub fn triage(&self) -> &SymbolTriage { + &self.triage + } + + pub fn triage_mut(&mut self) -> &mut SymbolTriage { + &mut self.triage + } + + pub fn load_from_bytes(&self, bytes: &[u8]) -> Result { + let elf = ElfBinary::parse(bytes).map_err(|e| e.to_string())?; + + // Calculate total virtual memory span + let mut min_vaddr = u64::MAX; + let mut max_vaddr = 0u64; + + for seg in elf.load_segments() { + if seg.p_vaddr < min_vaddr { + min_vaddr = seg.p_vaddr; + } + let seg_end = seg.p_vaddr + seg.p_memsz; + if seg_end > max_vaddr { + max_vaddr = seg_end; + } + } + + if min_vaddr > max_vaddr { + return Err("No PT_LOAD segments found in ELF binary".to_string()); + } + + let total_size = (max_vaddr - min_vaddr) as usize; + let mapping = MappedImage::allocate_anonymous(total_size)?; + let base_addr = mapping.base_addr() as u64; + + // Copy PT_LOAD segments into virtual memory + for seg in elf.load_segments() { + let seg_dest_offset = (seg.p_vaddr - min_vaddr) as usize; + let file_start = seg.p_offset as usize; + let file_end = file_start + seg.p_filesz as usize; + + if file_end <= bytes.len() { + let slice = &bytes[file_start..file_end]; + unsafe { + let dest_ptr = mapping.base_addr().add(seg_dest_offset); + std::ptr::copy_nonoverlapping(slice.as_ptr(), dest_ptr, slice.len()); + } + } + } + + Ok(LoadedLibrary { + mapping, + base_addr, + }) + } +} diff --git a/crates/molotov-core/tests/linker_test.rs b/crates/molotov-core/tests/linker_test.rs new file mode 100644 index 0000000..7e00832 --- /dev/null +++ b/crates/molotov-core/tests/linker_test.rs @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +use molotov_core::linker::BionicLinker; + +#[test] +fn test_linker_rejects_empty_data() { + let linker = BionicLinker::new(); + let res = linker.load_from_bytes(&[]); + assert!(res.is_err()); +}