Fix ELF not running when load address not start from zero

This commit is contained in:
Hui, Chunyang 2021-04-02 09:28:32 +00:00 committed by Zongmin.Gu
parent 09bac3d4b5
commit a9574ca22e
3 changed files with 33 additions and 20 deletions

@ -309,7 +309,12 @@ fn init_auxvec(process_vm: &ProcessVM, exec_elf_file: &ElfFile) -> Result<AuxVec
auxvec.set(AuxKey::AT_PHENT, exec_elf_header.e_phentsize as u64)?;
auxvec.set(AuxKey::AT_PHNUM, exec_elf_header.e_phnum as u64)?;
auxvec.set(AuxKey::AT_PHDR, exec_elf_base + exec_elf_header.e_phoff)?;
auxvec.set(AuxKey::AT_ENTRY, exec_elf_base + exec_elf_header.e_entry)?;
let base_load_address_offset = exec_elf_file.base_load_address_offset();
auxvec.set(
AuxKey::AT_ENTRY,
exec_elf_base + exec_elf_header.e_entry - base_load_address_offset,
)?;
let ldso_elf_base = process_vm.get_elf_ranges()[1].start() as u64;
auxvec.set(AuxKey::AT_BASE, ldso_elf_base)?;

@ -136,6 +136,12 @@ impl<'a> ElfFile<'a> {
)?;
Ok(elf_hdr)
}
// An offset to be subtracted from ELF vaddr for PIE
pub fn base_load_address_offset(&self) -> u64 {
let phdr = self.program_headers().nth(0).unwrap();
phdr.p_vaddr - phdr.p_offset
}
}
pub trait ProgramHeaderExt<'a> {

@ -212,14 +212,17 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> {
fn init_elf_memory(elf_range: &VMRange, elf_file: &ElfFile) -> Result<()> {
// Destination buffer: ELF appeared in the process
let elf_proc_buf = unsafe { elf_range.as_slice_mut() };
let mut empty_offset_vec: Vec<(usize, usize)> = Vec::with_capacity(3); // usally two loadable segments
// Source buffer: ELF stored in the ELF file
let elf_file_buf = elf_file.as_slice();
let base_load_address_offset = elf_file.base_load_address_offset() as usize;
// Offsets to track zerolized range
let mut empty_start_offset = 0;
let mut empty_end_offset = 0;
// Source buffer: ELF stored in the ELF file
let elf_file_buf = elf_file.as_slice();
// Init all loadable segements
let loadable_segments = elf_file
elf_file
.program_headers()
.filter(|segment| segment.loadable())
.for_each(|segment| {
@ -227,27 +230,26 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> {
let file_offset = segment.p_offset as usize;
let mem_addr = segment.p_vaddr as usize;
let mem_size = segment.p_memsz as usize;
let alignment = segment.p_align as usize;
debug_assert!(file_size <= mem_size);
// The first file_size bytes are loaded from the ELF file,
// the remaining (mem_size - file_size) bytes are zeros.
let mem_start_offset = mem_addr - base_load_address_offset;
// Initialize empty part to zero based on alignment
empty_start_offset = align_down(mem_start_offset, alignment);
for b in &mut elf_proc_buf[empty_start_offset..mem_start_offset] {
*b = 0;
}
// Bytes of file_size length are loaded from the ELF file
elf_file.file_inode().read_at(
file_offset,
&mut elf_proc_buf[mem_addr..mem_addr + file_size],
&mut elf_proc_buf[mem_start_offset..mem_start_offset + file_size],
);
empty_end_offset = mem_addr;
empty_offset_vec.push((empty_start_offset, empty_end_offset));
empty_start_offset = empty_end_offset + file_size;
});
empty_offset_vec.push((empty_start_offset, elf_proc_buf.len()));
// Set zero for the remain part of the buffer
empty_offset_vec
.iter()
.for_each(|(start_offset, end_offset)| {
for b in &mut elf_proc_buf[*start_offset..*end_offset] {
// Set the remaining part to zero based on alignment
empty_end_offset = align_up(mem_start_offset + file_size, alignment);
for b in &mut elf_proc_buf[mem_start_offset + file_size..empty_end_offset] {
*b = 0;
}
});