Relocations are working
This commit is contained in:
@@ -15,7 +15,6 @@
|
||||
ptr_metadata
|
||||
)]
|
||||
|
||||
use alloc::string::String;
|
||||
use embedded_alloc::LlffHeap as Heap;
|
||||
use log::info;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use core::time::Duration;
|
||||
|
||||
use alloc::{boxed::Box, format, string::String, vec::Vec};
|
||||
use bffs::{io::Read, path::Path};
|
||||
use goblin::elf::reloc::R_RISCV_RELATIVE;
|
||||
use shared::syscall::exit;
|
||||
|
||||
use crate::{
|
||||
@@ -134,6 +135,78 @@ pub fn create_process_from_file<'a, T: Into<Path<'a>>>(path: T) -> i64 {
|
||||
|
||||
println!("Loading binary at address: {:x?}", content.as_ptr());
|
||||
|
||||
// If ELF, use goblin to load PT_LOAD segments and apply relocations
|
||||
if let Ok(gelf) = goblin::elf::Elf::parse(&content) {
|
||||
// Determine memory bounds from program headers
|
||||
let mut min_vaddr = u64::MAX;
|
||||
let mut max_vaddr = 0u64;
|
||||
for ph in gelf.program_headers.iter() {
|
||||
if ph.p_type == goblin::elf::program_header::PT_LOAD && ph.p_memsz > 0 {
|
||||
min_vaddr = core::cmp::min(min_vaddr, ph.p_vaddr);
|
||||
max_vaddr = core::cmp::max(max_vaddr, ph.p_vaddr + ph.p_memsz);
|
||||
}
|
||||
}
|
||||
|
||||
if min_vaddr != u64::MAX {
|
||||
let size = (max_vaddr - min_vaddr) as usize;
|
||||
use alloc::alloc::{alloc_zeroed, Layout};
|
||||
let layout = Layout::from_size_align(size, 0x1000).unwrap();
|
||||
let base = unsafe { alloc_zeroed(layout) };
|
||||
|
||||
// Copy segments
|
||||
for ph in gelf.program_headers.iter() {
|
||||
if ph.p_type == goblin::elf::program_header::PT_LOAD {
|
||||
let dst = unsafe { base.add((ph.p_vaddr - min_vaddr) as usize) };
|
||||
let src_off = ph.p_offset as usize;
|
||||
let copy_len = ph.p_filesz as usize;
|
||||
if copy_len > 0 {
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
content.as_ptr().add(src_off),
|
||||
dst,
|
||||
copy_len,
|
||||
)
|
||||
}
|
||||
}
|
||||
if ph.p_memsz as usize > copy_len {
|
||||
unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
dst.add(copy_len),
|
||||
ph.p_memsz as usize - copy_len,
|
||||
)
|
||||
.fill(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply relocations using our parser (handles RELA entries)
|
||||
for rela in gelf.dynrelas.iter() {
|
||||
let r_type = rela.r_type;
|
||||
match r_type {
|
||||
x if x == R_RISCV_RELATIVE => {
|
||||
let where_off = (rela.r_offset - min_vaddr) as usize;
|
||||
let where_ptr = unsafe { base.add(where_off) } as *mut u64;
|
||||
let val = (base as u64).wrapping_add(rela.r_addend.unwrap() as u64);
|
||||
unsafe { core::ptr::write_unaligned(where_ptr, val) };
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Entry point
|
||||
let entry_va = gelf.entry;
|
||||
let entry_addr = unsafe { base.add((entry_va - min_vaddr) as usize) } as *const u8;
|
||||
let entry_fn =
|
||||
unsafe { core::mem::transmute::<*const u8, extern "C" fn()>(entry_addr) };
|
||||
let wrapper = Box::leak(Box::new(move || {
|
||||
entry_fn();
|
||||
}));
|
||||
println!("Program loaded at : {:x?}", entry_addr);
|
||||
return create_process(wrapper, name);
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: treat the file as a raw binary blob and execute in-place
|
||||
let entry_point =
|
||||
unsafe { core::mem::transmute::<*const u8, extern "C" fn()>(Vec::leak(content).as_ptr()) };
|
||||
|
||||
Reference in New Issue
Block a user