mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-28 03:43:23 +00:00
map all the segments of the ELF in a range
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
9ae2ca4c02
commit
1a525454ef
@ -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();
|
||||
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<Vaddr>) -> Result<AuxVec> {
|
||||
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()
|
||||
};
|
||||
|
@ -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,7 +66,8 @@ fn load_ldso_for_shared_object(
|
||||
file_header: &[u8],
|
||||
fs_resolver: &FsResolver,
|
||||
) -> 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);
|
||||
let fs_path = FsPath::new(AT_FDCWD, &ldso_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 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));
|
||||
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<Full>,
|
||||
elf_file: &Dentry,
|
||||
) -> Result<Option<Vaddr>> {
|
||||
pub fn map_segment_vmos(elf: &Elf, root_vmar: &Vmar<Full>, elf_file: &Dentry) -> Result<Vaddr> {
|
||||
// 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<Full>) -> Result<Vaddr> {
|
||||
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<Full>) -> Result<Vaddr> {
|
||||
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::<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
|
||||
@ -176,11 +176,9 @@ fn map_segment_vmo(
|
||||
program_header: &ProgramHeader64,
|
||||
vmo: Vmo,
|
||||
root_vmar: &Vmar<Full>,
|
||||
// elf_file: Arc<FileHandle>,
|
||||
file_map_addr: &Option<Vaddr>,
|
||||
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;
|
||||
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);
|
||||
} else {
|
||||
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<VmPerm> {
|
||||
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
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user