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();
|
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()
|
||||||
};
|
};
|
||||||
|
@ -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,18 +66,23 @@ 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() {
|
||||||
trace!("ldso_path = {:?}", ldso_path);
|
if let Ok(ldso_path) = elf.ldso_path(file_header) {
|
||||||
let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?;
|
trace!("ldso_path = {:?}", ldso_path);
|
||||||
let ldso_file = fs_resolver.lookup(&fs_path)?;
|
let fs_path = FsPath::new(AT_FDCWD, &ldso_path)?;
|
||||||
let vnode = ldso_file.vnode();
|
let ldso_file = fs_resolver.lookup(&fs_path)?;
|
||||||
let mut buf = Box::new([0u8; PAGE_SIZE]);
|
let vnode = ldso_file.vnode();
|
||||||
let ldso_header = vnode.read_at(0, &mut *buf)?;
|
let mut buf = Box::new([0u8; PAGE_SIZE]);
|
||||||
let ldso_elf = Elf::parse_elf(&*buf)?;
|
let ldso_header = vnode.read_at(0, &mut *buf)?;
|
||||||
// let ldso_file = Arc::new(FileHandle::new_inode_handle(ldso_file));
|
let ldso_elf = Elf::parse_elf(&*buf)?;
|
||||||
let map_addr = map_segment_vmos(&ldso_elf, root_vmar, &ldso_file)?.unwrap();
|
let map_addr = map_segment_vmos(&ldso_elf, root_vmar, &ldso_file)?;
|
||||||
return Ok(LdsoLoadInfo::new(ldso_elf.entry_point() + map_addr, map_addr));
|
return Ok(LdsoLoadInfo::new(
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user