Skip to content

Commit

Permalink
reduce the use of mmap when loading ELF
Browse files Browse the repository at this point in the history
  • Loading branch information
thesayol committed Apr 8, 2024
1 parent 575a1ff commit e84621b
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 92 deletions.
126 changes: 37 additions & 89 deletions api/ruxos_posix_api/src/imp/execve/load_elf.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::*;
use alloc::vec::Vec;
use crate::{ctypes::kstat, utils::char_ptr_to_str, *};
use alloc::{vec, vec::Vec};
use core::{
ffi::c_char,
mem::size_of,
ptr::{null, null_mut},
};

Expand All @@ -25,32 +24,27 @@ impl ElfProg {
///
/// and load interp, if needed.
pub fn new(filepath: *const c_char) -> Self {
let name = ptr2vec(filepath);
let path = ptr2vec(filepath);
debug!("sys_execve: new elf prog: {}", vec_u8_to_str(&path));
let name = char_ptr_to_str(filepath).unwrap().as_bytes().to_vec();
let path = name.clone();
debug!("sys_execve: new elf prog: {:?}", char_ptr_to_str(filepath));

// open file
let fd = sys_open(filepath, ctypes::O_RDWR as i32, 0);

// get file size
let buf = sys_mmap(null_mut(), size_of::<ctypes::kstat>(), 0, 0, 0, 0);
let bufsize = unsafe {
sys_fstat(fd, buf);
(*(buf as *const ctypes::kstat)).st_size as usize
let mut buf = ctypes::kstat {
..Default::default()
};
sys_munmap(buf, size_of::<ctypes::kstat>());
sys_fstat(fd, &mut buf as *const kstat as *mut _);
let filesize = buf.st_size as usize;

// read file
let buf = sys_mmap(null_mut(), bufsize, 0, 0, fd, 0);
debug!(
"sys_execve: mmap to read file at {:p} size {:x}",
buf, bufsize
);
sys_read(fd, buf, bufsize);
let mut file = vec![0u8; filesize];
sys_read(fd, file.as_mut_ptr() as *mut _, filesize);
debug!("sys_execve: read file size 0x{filesize:x}");

// parse elf
let slice = unsafe { core::slice::from_raw_parts_mut(buf as *mut u8, bufsize) };
let file = elf::ElfBytes::<elf::endian::AnyEndian>::minimal_parse(slice)
let file = elf::ElfBytes::<elf::endian::AnyEndian>::minimal_parse(&file)
.expect("parse ELF failed");

// get program's LOAD mem size
Expand All @@ -62,22 +56,13 @@ impl ElfProg {
}
}

// mmap memory to copy LOAD segmeants
let a = crate::sys_mmap(null_mut(), msize as usize, 0, 0, 0, 0);
debug!("sys_execve: mmap to copy LOAD at {:p} size {:x}", a, msize);
let base = a as usize;

// copy LOAD segs into base
// copy LOAD segments
let base = crate::sys_mmap(null_mut(), msize as usize, 0, 0, 0, 0) as usize;
for seg in segs {
if seg.p_type == elf::abi::PT_LOAD {
let data = file.segment_data(&seg).unwrap();
let vaddr = seg.p_vaddr as usize + base;
unsafe {
let c = vaddr as *mut u8;
for (i, d) in data.iter().enumerate() {
*(c.add(i)) = *d;
}
}
let dst = (seg.p_vaddr as usize + base) as *mut u8;
unsafe { dst.copy_from_nonoverlapping(data.as_ptr(), data.len()) };
}
}

Expand All @@ -93,24 +78,31 @@ impl ElfProg {
if seg.p_type == elf::abi::PT_INTERP {
let data = file.segment_data(&seg).unwrap();
interp_path = data.as_ptr() as *const c_char;
break;
}
}

let sec = file.section_header_by_name(".got").unwrap().unwrap();
let addr = sec.sh_addr as usize + base;
debug!("sys_execve: got vaddr = {:#X}", addr);

// return Self
let mut platform = Vec::new();
// platform
let platform = b"unknown".to_vec();
#[cfg(target_arch = "aarch64")]
for c in b"aarch64" {
platform.push(*c);
}
let platform = b"aarch64".to_vec();
#[cfg(target_arch = "x86_64")]
for c in b"x86_64" {
platform.push(*c);
}
let ret = Self {
let platform = b"x86_64".to_vec();

// get address of .text for debugging
let text_section_addr = base
+ file
.section_header_by_name(".text")
.unwrap()
.unwrap()
.sh_offset as usize;
debug!(
"sys_execve: loaded ELF in 0x{:x}, .text is 0x{:x}",
base, text_section_addr
);

// create retval
Self {
base,
entry,
name,
Expand All @@ -121,50 +113,6 @@ impl ElfProg {
phent: file.ehdr.e_phentsize as usize,
phnum: file.ehdr.e_phnum as usize,
phdr,
};

let text_off = file
.section_header_by_name(".text")
.unwrap()
.unwrap()
.sh_offset;
debug!(
"sys_execve: loaded ELF in 0x{:x}, .text is 0x{:x}",
ret.base,
ret.base + text_off as usize
);

// unmap file
sys_munmap(buf, bufsize);
debug!(
"sys_execve: unmap ELF file in memory at {:p} len {:x}",
buf, bufsize
);

ret
}
}

pub fn ptr2vec(s: *const c_char) -> Vec<u8> {
if s as usize == 0 {
return alloc::vec![];
}
let mut v = Vec::new();
unsafe {
let mut i = 0;
while *s.add(i) != 0 {
v.push(*s.add(i) as u8);
i += 1;
}
}
v
}

pub fn vec_u8_to_str(v: &Vec<u8>) -> &str {
if v.is_empty() {
return "";
}
let a = v.as_slice();
let s = core::str::from_utf8(a).unwrap();
s
}
4 changes: 2 additions & 2 deletions api/ruxos_posix_api/src/imp/execve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ use crate::{
pub fn sys_execve(pathname: *const c_char, argv: usize, envp: usize) -> ! {
use auxv::*;

let prog = load_elf::ElfProg::new(pathname as *const c_char);
let prog = load_elf::ElfProg::new(pathname);

// get entry
let mut entry = prog.entry;

// if interp is needed
let mut at_base = 0;
if prog.interp_path as usize != 0 {
if !prog.interp_path.is_null() {
let interp_prog = load_elf::ElfProg::new(prog.interp_path);
entry = interp_prog.entry;
at_base = interp_prog.base;
Expand Down
2 changes: 1 addition & 1 deletion api/ruxos_posix_api/src/imp/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ pub unsafe fn sys_stat(path: *const c_char, buf: *mut core::ffi::c_void) -> c_in
}

/// retrieve information about the file pointed by `fd`
pub unsafe fn sys_fstat(fd: c_int, kst: *mut core::ffi::c_void) -> c_int {
pub fn sys_fstat(fd: c_int, kst: *mut core::ffi::c_void) -> c_int {
debug!("sys_fstat <= {} {:#x}", fd, kst as usize);
syscall_body!(sys_fstat, {
if kst.is_null() {
Expand Down

0 comments on commit e84621b

Please sign in to comment.