map all the segments of the ELF in a range

This commit is contained in:
Jianfeng Jiang
2023-04-03 06:54:28 -04:00
committed by Tate, Hongliang Tian
parent 9ae2ca4c02
commit 1a525454ef
3 changed files with 51 additions and 60 deletions

View File

@ -332,11 +332,11 @@ impl InitStack {
} }
} }
pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option<Vaddr>) -> Result<AuxVec> { pub fn init_aux_vec(elf: &Elf, elf_map_addr: Vaddr) -> Result<AuxVec> {
let mut aux_vec = AuxVec::new(); let mut aux_vec = AuxVec::new();
aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?; aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?;
let ph_addr = if elf.is_shared_object() { let ph_addr = if elf.is_shared_object() {
elf.ph_addr()? + elf_map_addr.unwrap() elf.ph_addr()? + elf_map_addr
} else { } else {
elf.ph_addr()? elf.ph_addr()?
}; };
@ -345,7 +345,7 @@ pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option<Vaddr>) -> Result<AuxVec> {
aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?; aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
let elf_entry = if elf.is_shared_object() { let elf_entry = if elf.is_shared_object() {
let base_load_offset = elf.base_load_address_offset(); let base_load_offset = elf.base_load_address_offset();
elf.entry_point() + elf_map_addr.unwrap() - base_load_offset as usize elf.entry_point() + elf_map_addr - base_load_offset as usize
} else { } else {
elf.entry_point() elf.entry_point()
}; };

View File

@ -4,8 +4,9 @@
use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD}; use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD};
use crate::fs::utils::Dentry; use crate::fs::utils::Dentry;
use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack}; use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack};
use crate::rights::Rights;
use crate::vm::perms::VmPerms; use crate::vm::perms::VmPerms;
use crate::vm::vmo::VmoRightsOp; use crate::vm::vmo::{VmoOptions, VmoRightsOp};
use crate::{ use crate::{
prelude::*, prelude::*,
rights::Full, rights::Full,
@ -47,7 +48,7 @@ pub fn load_elf_to_root_vmar(
} else { } else {
if elf.is_shared_object() { if elf.is_shared_object() {
// ldso itself // ldso itself
elf.entry_point() + map_addr.unwrap() elf.entry_point() + map_addr
} else { } else {
// statically linked executable // statically linked executable
elf.entry_point() elf.entry_point()
@ -65,7 +66,8 @@ fn load_ldso_for_shared_object(
file_header: &[u8], file_header: &[u8],
fs_resolver: &FsResolver, fs_resolver: &FsResolver,
) -> Result<LdsoLoadInfo> { ) -> Result<LdsoLoadInfo> {
if let Ok(ldso_path) = elf.ldso_path(file_header) && elf.is_shared_object(){ if elf.is_shared_object() {
if let Ok(ldso_path) = elf.ldso_path(file_header) {
trace!("ldso_path = {:?}", ldso_path); trace!("ldso_path = {:?}", ldso_path);
let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?; let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?;
let ldso_file = fs_resolver.lookup(&fs_path)?; let ldso_file = fs_resolver.lookup(&fs_path)?;
@ -73,10 +75,14 @@ fn load_ldso_for_shared_object(
let mut buf = Box::new([0u8; PAGE_SIZE]); let mut buf = Box::new([0u8; PAGE_SIZE]);
let ldso_header = vnode.read_at(0, &mut *buf)?; let ldso_header = vnode.read_at(0, &mut *buf)?;
let ldso_elf = Elf::parse_elf(&*buf)?; let ldso_elf = Elf::parse_elf(&*buf)?;
// let ldso_file = Arc::new(FileHandle::new_inode_handle(ldso_file)); let map_addr = map_segment_vmos(&ldso_elf, root_vmar, &ldso_file)?;
let map_addr = map_segment_vmos(&ldso_elf, root_vmar, &ldso_file)?.unwrap(); return Ok(LdsoLoadInfo::new(
return Ok(LdsoLoadInfo::new(ldso_elf.entry_point() + map_addr, map_addr)); ldso_elf.entry_point() + map_addr,
map_addr,
));
} }
}
// There are three reasons that an executable may lack ldso_path, // There are three reasons that an executable may lack ldso_path,
// 1. this is a statically linked executable, // 1. this is a statically linked executable,
// 2. the shared object is invalid, // 2. the shared object is invalid,
@ -130,17 +136,13 @@ impl ElfLoadInfo {
} }
/// init vmo for each segment and then map segment to root vmar /// init vmo for each segment and then map segment to root vmar
pub fn map_segment_vmos( pub fn map_segment_vmos(elf: &Elf, root_vmar: &Vmar<Full>, elf_file: &Dentry) -> Result<Vaddr> {
elf: &Elf,
root_vmar: &Vmar<Full>,
elf_file: &Dentry,
) -> Result<Option<Vaddr>> {
// all segments of the shared object must be mapped to a continuous vm range // all segments of the shared object must be mapped to a continuous vm range
// to ensure the relative offset of each segment not changed. // to ensure the relative offset of each segment not changed.
let file_map_addr = if elf.is_shared_object() { let base_addr = if elf.is_shared_object() {
Some(hint_elf_map_addr(elf, root_vmar)?) base_map_addr(elf, root_vmar)?
} else { } else {
None 0
}; };
for program_header in &elf.program_headers { for program_header in &elf.program_headers {
let type_ = program_header let type_ = program_header
@ -148,27 +150,25 @@ pub fn map_segment_vmos(
.map_err(|_| Error::with_message(Errno::ENOEXEC, "parse program header type fails"))?; .map_err(|_| Error::with_message(Errno::ENOEXEC, "parse program header type fails"))?;
if type_ == program::Type::Load { if type_ == program::Type::Load {
let vmo = init_segment_vmo(program_header, elf_file)?; let vmo = init_segment_vmo(program_header, elf_file)?;
map_segment_vmo( map_segment_vmo(program_header, vmo, root_vmar, base_addr)?;
program_header,
vmo,
root_vmar,
// elf_file.clone(),
&file_map_addr,
)?;
} }
} }
Ok(file_map_addr) Ok(base_addr)
} }
fn hint_elf_map_addr(elf: &Elf, root_vmar: &Vmar<Full>) -> Result<Vaddr> { fn base_map_addr(elf: &Elf, root_vmar: &Vmar<Full>) -> Result<Vaddr> {
let mut size = 0; let elf_size = elf.program_headers.iter().fold(0, |prev, program_header| {
for program_header in &elf.program_headers { let ph_max_addr = program_header.virtual_addr as usize + program_header.mem_size as usize;
let ph_size = program_header.virtual_addr + program_header.mem_size; if ph_max_addr > prev {
if ph_size > size { ph_max_addr
size = ph_size; } else {
prev
} }
} });
root_vmar.hint_map_addr(size as usize) let map_size = elf_size.align_up(PAGE_SIZE);
let vmo = VmoOptions::<Rights>::new(0).alloc()?;
let vmar_map_options = root_vmar.new_map(vmo, VmPerms::empty())?.size(map_size);
vmar_map_options.build()
} }
/// map the segment vmo to root_vmar /// map the segment vmo to root_vmar
@ -176,11 +176,9 @@ fn map_segment_vmo(
program_header: &ProgramHeader64, program_header: &ProgramHeader64,
vmo: Vmo, vmo: Vmo,
root_vmar: &Vmar<Full>, root_vmar: &Vmar<Full>,
// elf_file: Arc<FileHandle>, base_addr: Vaddr,
file_map_addr: &Option<Vaddr>,
) -> Result<()> { ) -> Result<()> {
let perms = VmPerms::from(parse_segment_perm(program_header.flags)?); let perms = VmPerms::from(parse_segment_perm(program_header.flags));
// let perms = VmPerms::READ | VmPerms::WRITE | VmPerms::EXEC;
let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE); let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE);
trace!( trace!(
"map segment vmo: virtual addr = 0x{:x}, size = 0x{:x}, perms = {:?}", "map segment vmo: virtual addr = 0x{:x}, size = 0x{:x}, perms = {:?}",
@ -188,13 +186,9 @@ fn map_segment_vmo(
program_header.mem_size, program_header.mem_size,
perms perms
); );
let mut vm_map_options = root_vmar.new_map(vmo, perms)?; let mut vm_map_options = root_vmar.new_map(vmo, perms)?.can_overwrite(true);
if let Some(file_map_addr) = *file_map_addr { let offset = base_addr + offset;
let offset = file_map_addr + offset;
vm_map_options = vm_map_options.offset(offset); vm_map_options = vm_map_options.offset(offset);
} else {
vm_map_options = vm_map_options.offset(offset);
}
let map_addr = vm_map_options.build()?; let map_addr = vm_map_options.build()?;
Ok(()) Ok(())
} }
@ -254,16 +248,16 @@ fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Resu
Ok(segment_vmo.to_dyn()) Ok(segment_vmo.to_dyn())
} }
fn parse_segment_perm(flags: xmas_elf::program::Flags) -> Result<VmPerm> { fn parse_segment_perm(flags: xmas_elf::program::Flags) -> VmPerm {
if !flags.is_read() { let mut vm_perm = VmPerm::empty();
return_errno_with_message!(Errno::ENOEXEC, "unreadable segment"); if flags.is_read() {
vm_perm |= VmPerm::R;
} }
let mut vm_perm = VmPerm::R;
if flags.is_write() { if flags.is_write() {
vm_perm |= VmPerm::W; vm_perm |= VmPerm::W;
} }
if flags.is_execute() { if flags.is_execute() {
vm_perm |= VmPerm::X; vm_perm |= VmPerm::X;
} }
Ok(vm_perm) vm_perm
} }

View File

@ -50,11 +50,8 @@ pub fn do_sys_mmap(
let len = len.align_up(PAGE_SIZE); let len = len.align_up(PAGE_SIZE);
if len % PAGE_SIZE != 0 {
panic!("Mmap only support page-aligned len");
}
if offset % PAGE_SIZE != 0 { if offset % PAGE_SIZE != 0 {
panic!("Mmap only support page-aligned offset"); return_errno_with_message!(Errno::EINVAL, "mmap only support page-aligned offset");
} }
let perms = VmPerms::from(vm_perm); let perms = VmPerms::from(vm_perm);