|
| 1 | +use crate::{ctypes::kstat, *}; |
| 2 | +use alloc::{vec, vec::Vec}; |
| 3 | +use core::ptr::null_mut; |
| 4 | + |
| 5 | +#[derive(Debug)] |
| 6 | +pub struct ElfProg { |
| 7 | + pub base: usize, |
| 8 | + pub entry: usize, |
| 9 | + pub interp_path: Vec<u8>, |
| 10 | + pub phent: usize, |
| 11 | + pub phnum: usize, |
| 12 | + pub phdr: usize, |
| 13 | +} |
| 14 | + |
| 15 | +impl ElfProg { |
| 16 | + /// read elf from `path`, and copy LOAD segments to a alloacated memory |
| 17 | + /// |
| 18 | + /// and load interp, if needed. |
| 19 | + pub fn new(filepath: &str) -> Self { |
| 20 | + debug!("sys_execve: new elf prog: {filepath}"); |
| 21 | + |
| 22 | + // open file |
| 23 | + let fd = sys_open(filepath.as_ptr() as _, ctypes::O_RDWR as _, 0); |
| 24 | + |
| 25 | + // get file size |
| 26 | + let mut buf = ctypes::kstat { |
| 27 | + ..Default::default() |
| 28 | + }; |
| 29 | + sys_fstat(fd, &mut buf as *const kstat as *mut _); |
| 30 | + let filesize = buf.st_size as usize; |
| 31 | + |
| 32 | + // read file |
| 33 | + let mut file = vec![0u8; filesize]; |
| 34 | + sys_read(fd, file.as_mut_ptr() as *mut _, filesize); |
| 35 | + debug!("sys_execve: read file size 0x{filesize:x}"); |
| 36 | + sys_close(fd); |
| 37 | + |
| 38 | + // parse elf |
| 39 | + let file = elf::ElfBytes::<elf::endian::AnyEndian>::minimal_parse(&file) |
| 40 | + .expect("parse ELF failed"); |
| 41 | + |
| 42 | + // get program's LOAD mem size |
| 43 | + let mut min_addr = 0; |
| 44 | + let mut max_addr = 0; |
| 45 | + let segs = file.segments().unwrap(); |
| 46 | + for seg in segs { |
| 47 | + if seg.p_type == elf::abi::PT_LOAD { |
| 48 | + min_addr = min_addr.min(seg.p_vaddr); |
| 49 | + max_addr = max_addr.max(seg.p_vaddr + seg.p_memsz); |
| 50 | + } |
| 51 | + } |
| 52 | + let msize = (max_addr - min_addr) as usize; |
| 53 | + |
| 54 | + // alloc memory for LOAD |
| 55 | + let prot = ctypes::PROT_WRITE | ctypes::PROT_READ | ctypes::PROT_EXEC; |
| 56 | + let flags = ctypes::MAP_ANONYMOUS | ctypes::MAP_PRIVATE; |
| 57 | + let base = crate::sys_mmap(null_mut(), msize, prot as _, flags as _, -1, 0) as usize; |
| 58 | + |
| 59 | + // copy LOAD segments |
| 60 | + for seg in segs { |
| 61 | + if seg.p_type == elf::abi::PT_LOAD { |
| 62 | + let data = file.segment_data(&seg).unwrap(); |
| 63 | + let dst = (seg.p_vaddr as usize + base) as *mut u8; |
| 64 | + unsafe { dst.copy_from_nonoverlapping(data.as_ptr(), data.len()) }; |
| 65 | + } |
| 66 | + } |
| 67 | + |
| 68 | + // phdr |
| 69 | + let phdr = base + file.ehdr.e_phoff as usize; |
| 70 | + |
| 71 | + // get entry |
| 72 | + let entry = file.ehdr.e_entry as usize + base; |
| 73 | + |
| 74 | + // parse interpreter |
| 75 | + let mut interp_path = vec![]; |
| 76 | + for seg in file.segments().unwrap() { |
| 77 | + if seg.p_type == elf::abi::PT_INTERP { |
| 78 | + let data = file.segment_data(&seg).unwrap().to_vec(); |
| 79 | + interp_path = data; |
| 80 | + break; |
| 81 | + } |
| 82 | + } |
| 83 | + |
| 84 | + // get address of .text for debugging |
| 85 | + let text_section_addr = base |
| 86 | + + file |
| 87 | + .section_header_by_name(".text") |
| 88 | + .unwrap() |
| 89 | + .unwrap() |
| 90 | + .sh_offset as usize; |
| 91 | + debug!( |
| 92 | + "sys_execve: loaded ELF in 0x{:x}, .text is 0x{:x}", |
| 93 | + base, text_section_addr |
| 94 | + ); |
| 95 | + |
| 96 | + // create retval |
| 97 | + Self { |
| 98 | + base, |
| 99 | + entry, |
| 100 | + interp_path, |
| 101 | + phent: file.ehdr.e_phentsize as usize, |
| 102 | + phnum: file.ehdr.e_phnum as usize, |
| 103 | + phdr, |
| 104 | + } |
| 105 | + } |
| 106 | +} |
0 commit comments