diff --git a/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs b/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs index c8b39365f..5d1d5ff71 100644 --- a/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs +++ b/src/services/libs/jinux-std/src/process/program_loader/elf/init_stack.rs @@ -332,11 +332,11 @@ impl InitStack { } } -pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option) -> Result { +pub fn init_aux_vec(elf: &Elf, elf_map_addr: Vaddr) -> Result { let mut aux_vec = AuxVec::new(); aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?; let ph_addr = if elf.is_shared_object() { - elf.ph_addr()? + elf_map_addr.unwrap() + elf.ph_addr()? + elf_map_addr } else { elf.ph_addr()? }; @@ -345,7 +345,7 @@ pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option) -> Result { aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?; let elf_entry = if elf.is_shared_object() { 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 { elf.entry_point() }; diff --git a/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs b/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs index 432cbad6d..f2a93d788 100644 --- a/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs +++ b/src/services/libs/jinux-std/src/process/program_loader/elf/load_elf.rs @@ -4,8 +4,9 @@ use crate::fs::fs_resolver::{FsPath, FsResolver, AT_FDCWD}; use crate::fs::utils::Dentry; use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack}; +use crate::rights::Rights; use crate::vm::perms::VmPerms; -use crate::vm::vmo::VmoRightsOp; +use crate::vm::vmo::{VmoOptions, VmoRightsOp}; use crate::{ prelude::*, rights::Full, @@ -47,7 +48,7 @@ pub fn load_elf_to_root_vmar( } else { if elf.is_shared_object() { // ldso itself - elf.entry_point() + map_addr.unwrap() + elf.entry_point() + map_addr } else { // statically linked executable elf.entry_point() @@ -65,18 +66,23 @@ fn load_ldso_for_shared_object( file_header: &[u8], fs_resolver: &FsResolver, ) -> Result { - if let Ok(ldso_path) = elf.ldso_path(file_header) && elf.is_shared_object(){ - trace!("ldso_path = {:?}", ldso_path); - let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?; - let ldso_file = fs_resolver.lookup(&fs_path)?; - let vnode = ldso_file.vnode(); - let mut buf = Box::new([0u8; PAGE_SIZE]); - let ldso_header = vnode.read_at(0, &mut *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)?.unwrap(); - return Ok(LdsoLoadInfo::new(ldso_elf.entry_point() + map_addr, map_addr)); + if elf.is_shared_object() { + if let Ok(ldso_path) = elf.ldso_path(file_header) { + trace!("ldso_path = {:?}", ldso_path); + let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?; + let ldso_file = fs_resolver.lookup(&fs_path)?; + let vnode = ldso_file.vnode(); + let mut buf = Box::new([0u8; PAGE_SIZE]); + let ldso_header = vnode.read_at(0, &mut *buf)?; + let ldso_elf = Elf::parse_elf(&*buf)?; + let map_addr = map_segment_vmos(&ldso_elf, root_vmar, &ldso_file)?; + return Ok(LdsoLoadInfo::new( + ldso_elf.entry_point() + map_addr, + map_addr, + )); + } } + // There are three reasons that an executable may lack ldso_path, // 1. this is a statically linked executable, // 2. the shared object is invalid, @@ -130,17 +136,13 @@ impl ElfLoadInfo { } /// init vmo for each segment and then map segment to root vmar -pub fn map_segment_vmos( - elf: &Elf, - root_vmar: &Vmar, - elf_file: &Dentry, -) -> Result> { +pub fn map_segment_vmos(elf: &Elf, root_vmar: &Vmar, elf_file: &Dentry) -> Result { // all segments of the shared object must be mapped to a continuous vm range // to ensure the relative offset of each segment not changed. - let file_map_addr = if elf.is_shared_object() { - Some(hint_elf_map_addr(elf, root_vmar)?) + let base_addr = if elf.is_shared_object() { + base_map_addr(elf, root_vmar)? } else { - None + 0 }; for program_header in &elf.program_headers { 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"))?; if type_ == program::Type::Load { let vmo = init_segment_vmo(program_header, elf_file)?; - map_segment_vmo( - program_header, - vmo, - root_vmar, - // elf_file.clone(), - &file_map_addr, - )?; + map_segment_vmo(program_header, vmo, root_vmar, base_addr)?; } } - Ok(file_map_addr) + Ok(base_addr) } -fn hint_elf_map_addr(elf: &Elf, root_vmar: &Vmar) -> Result { - let mut size = 0; - for program_header in &elf.program_headers { - let ph_size = program_header.virtual_addr + program_header.mem_size; - if ph_size > size { - size = ph_size; +fn base_map_addr(elf: &Elf, root_vmar: &Vmar) -> Result { + let elf_size = elf.program_headers.iter().fold(0, |prev, program_header| { + let ph_max_addr = program_header.virtual_addr as usize + program_header.mem_size as usize; + if ph_max_addr > prev { + ph_max_addr + } else { + prev } - } - root_vmar.hint_map_addr(size as usize) + }); + let map_size = elf_size.align_up(PAGE_SIZE); + let vmo = VmoOptions::::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 @@ -176,11 +176,9 @@ fn map_segment_vmo( program_header: &ProgramHeader64, vmo: Vmo, root_vmar: &Vmar, - // elf_file: Arc, - file_map_addr: &Option, + base_addr: Vaddr, ) -> Result<()> { - let perms = VmPerms::from(parse_segment_perm(program_header.flags)?); - // let perms = VmPerms::READ | VmPerms::WRITE | VmPerms::EXEC; + let perms = VmPerms::from(parse_segment_perm(program_header.flags)); let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE); trace!( "map segment vmo: virtual addr = 0x{:x}, size = 0x{:x}, perms = {:?}", @@ -188,13 +186,9 @@ fn map_segment_vmo( program_header.mem_size, perms ); - let mut vm_map_options = root_vmar.new_map(vmo, perms)?; - if let Some(file_map_addr) = *file_map_addr { - let offset = file_map_addr + offset; - vm_map_options = vm_map_options.offset(offset); - } else { - vm_map_options = vm_map_options.offset(offset); - } + let mut vm_map_options = root_vmar.new_map(vmo, perms)?.can_overwrite(true); + let offset = base_addr + offset; + vm_map_options = vm_map_options.offset(offset); let map_addr = vm_map_options.build()?; Ok(()) } @@ -254,16 +248,16 @@ fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Resu Ok(segment_vmo.to_dyn()) } -fn parse_segment_perm(flags: xmas_elf::program::Flags) -> Result { - if !flags.is_read() { - return_errno_with_message!(Errno::ENOEXEC, "unreadable segment"); +fn parse_segment_perm(flags: xmas_elf::program::Flags) -> VmPerm { + let mut vm_perm = VmPerm::empty(); + if flags.is_read() { + vm_perm |= VmPerm::R; } - let mut vm_perm = VmPerm::R; if flags.is_write() { vm_perm |= VmPerm::W; } if flags.is_execute() { vm_perm |= VmPerm::X; } - Ok(vm_perm) + vm_perm } diff --git a/src/services/libs/jinux-std/src/syscall/mmap.rs b/src/services/libs/jinux-std/src/syscall/mmap.rs index edf86f33c..ef1775496 100644 --- a/src/services/libs/jinux-std/src/syscall/mmap.rs +++ b/src/services/libs/jinux-std/src/syscall/mmap.rs @@ -50,11 +50,8 @@ pub fn do_sys_mmap( let len = len.align_up(PAGE_SIZE); - if len % PAGE_SIZE != 0 { - panic!("Mmap only support page-aligned len"); - } 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);