mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-26 19:03:27 +00:00
Refactor the elf loading logics
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
950fbc131b
commit
2ca7b28bbc
@ -7,7 +7,7 @@
|
|||||||
//! When create a process from elf file, we will use the elf_load_info to construct the VmSpace
|
//! When create a process from elf file, we will use the elf_load_info to construct the VmSpace
|
||||||
|
|
||||||
use align_ext::AlignExt;
|
use align_ext::AlignExt;
|
||||||
use aster_rights::{Full, Rights};
|
use aster_rights::Full;
|
||||||
use ostd::mm::VmIo;
|
use ostd::mm::VmIo;
|
||||||
use xmas_elf::program::{self, ProgramHeader64};
|
use xmas_elf::program::{self, ProgramHeader64};
|
||||||
|
|
||||||
@ -23,12 +23,8 @@ use crate::{
|
|||||||
process_vm::{AuxKey, AuxVec, ProcessVm},
|
process_vm::{AuxKey, AuxVec, ProcessVm},
|
||||||
TermStatus,
|
TermStatus,
|
||||||
},
|
},
|
||||||
vdso::vdso_vmo,
|
vdso::{vdso_vmo, VDSO_VMO_SIZE},
|
||||||
vm::{
|
vm::{perms::VmPerms, util::duplicate_frame, vmar::Vmar, vmo::VmoRightsOp},
|
||||||
perms::VmPerms,
|
|
||||||
vmar::Vmar,
|
|
||||||
vmo::{Vmo, VmoOptions, VmoRightsOp},
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Loads elf to the process vm.
|
/// Loads elf to the process vm.
|
||||||
@ -197,7 +193,7 @@ impl ElfLoadInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// init vmo for each segment and then map segment to root vmar
|
/// Inits 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<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
|
// 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.
|
||||||
@ -212,14 +208,7 @@ pub fn map_segment_vmos(elf: &Elf, root_vmar: &Vmar<Full>, elf_file: &Dentry) ->
|
|||||||
.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 {
|
||||||
check_segment_align(program_header)?;
|
check_segment_align(program_header)?;
|
||||||
let (vmo, anonymous_map_size) = init_segment_vmo(program_header, elf_file)?;
|
map_segment_vmo(program_header, elf_file, root_vmar, base_addr)?;
|
||||||
map_segment_vmo(
|
|
||||||
program_header,
|
|
||||||
vmo,
|
|
||||||
anonymous_map_size,
|
|
||||||
root_vmar,
|
|
||||||
base_addr,
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(base_addr)
|
Ok(base_addr)
|
||||||
@ -245,49 +234,18 @@ fn base_map_addr(elf: &Elf, root_vmar: &Vmar<Full>) -> Result<Vaddr> {
|
|||||||
"executable file does not has loadable sections",
|
"executable file does not has loadable sections",
|
||||||
))?;
|
))?;
|
||||||
let map_size = elf_size.align_up(PAGE_SIZE);
|
let map_size = elf_size.align_up(PAGE_SIZE);
|
||||||
let vmo = VmoOptions::<Rights>::new(0).alloc()?;
|
let vmar_map_options = root_vmar.new_map(map_size, VmPerms::empty())?;
|
||||||
let vmar_map_options = root_vmar.new_map(vmo, VmPerms::empty())?.size(map_size);
|
|
||||||
vmar_map_options.build()
|
vmar_map_options.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// map the segment vmo to root_vmar
|
/// Creates and map the corresponding segment VMO to `root_vmar`.
|
||||||
|
/// If needed, create additional anonymous mapping to represents .bss segment.
|
||||||
fn map_segment_vmo(
|
fn map_segment_vmo(
|
||||||
program_header: &ProgramHeader64,
|
program_header: &ProgramHeader64,
|
||||||
vmo: Vmo,
|
elf_file: &Dentry,
|
||||||
anonymous_map_size: usize,
|
|
||||||
root_vmar: &Vmar<Full>,
|
root_vmar: &Vmar<Full>,
|
||||||
base_addr: Vaddr,
|
base_addr: Vaddr,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let perms = 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 = {:?}",
|
|
||||||
offset,
|
|
||||||
program_header.mem_size,
|
|
||||||
perms
|
|
||||||
);
|
|
||||||
let vmo_size = vmo.size();
|
|
||||||
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()?;
|
|
||||||
|
|
||||||
if anonymous_map_size > 0 {
|
|
||||||
let anonymous_vmo = {
|
|
||||||
let options: VmoOptions<Rights> = VmoOptions::new(anonymous_map_size);
|
|
||||||
options.alloc()?
|
|
||||||
};
|
|
||||||
let mut anonymous_map_options =
|
|
||||||
root_vmar.new_map(anonymous_vmo, perms)?.can_overwrite(true);
|
|
||||||
anonymous_map_options = anonymous_map_options.offset(offset + vmo_size);
|
|
||||||
let anonymous_map_addr = anonymous_map_options.build()?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create VMO for each segment. Return the segment VMO and the size of
|
|
||||||
/// additional anonymous mapping it needs.
|
|
||||||
fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Result<(Vmo, usize)> {
|
|
||||||
trace!(
|
trace!(
|
||||||
"mem range = 0x{:x} - 0x{:x}, mem_size = 0x{:x}",
|
"mem range = 0x{:x} - 0x{:x}, mem_size = 0x{:x}",
|
||||||
program_header.virtual_addr,
|
program_header.virtual_addr,
|
||||||
@ -304,33 +262,29 @@ fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Resu
|
|||||||
let file_offset = program_header.offset as usize;
|
let file_offset = program_header.offset as usize;
|
||||||
let virtual_addr = program_header.virtual_addr as usize;
|
let virtual_addr = program_header.virtual_addr as usize;
|
||||||
debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE);
|
debug_assert!(file_offset % PAGE_SIZE == virtual_addr % PAGE_SIZE);
|
||||||
let page_cache_vmo = {
|
let segment_vmo = {
|
||||||
let inode = elf_file.inode();
|
let inode = elf_file.inode();
|
||||||
inode.page_cache().ok_or(Error::with_message(
|
inode
|
||||||
Errno::ENOENT,
|
.page_cache()
|
||||||
"executable has no page cache",
|
.ok_or(Error::with_message(
|
||||||
))?
|
Errno::ENOENT,
|
||||||
|
"executable has no page cache",
|
||||||
|
))?
|
||||||
|
.to_dyn()
|
||||||
|
.dup_independent()?
|
||||||
};
|
};
|
||||||
let vmo_size = {
|
|
||||||
|
let total_map_size = {
|
||||||
let vmap_start = virtual_addr.align_down(PAGE_SIZE);
|
let vmap_start = virtual_addr.align_down(PAGE_SIZE);
|
||||||
let vmap_end = (virtual_addr + program_header.mem_size as usize).align_up(PAGE_SIZE);
|
let vmap_end = (virtual_addr + program_header.mem_size as usize).align_up(PAGE_SIZE);
|
||||||
vmap_end - vmap_start
|
vmap_end - vmap_start
|
||||||
};
|
};
|
||||||
|
|
||||||
let segment_vmo = {
|
let (segment_offset, segment_size) = {
|
||||||
let parent_range = {
|
let start = file_offset.align_down(PAGE_SIZE);
|
||||||
let start = file_offset.align_down(PAGE_SIZE);
|
let end = (file_offset + program_header.file_size as usize).align_up(PAGE_SIZE);
|
||||||
let end = (file_offset + program_header.file_size as usize).align_up(PAGE_SIZE);
|
debug_assert!(total_map_size >= (program_header.file_size as usize).align_up(PAGE_SIZE));
|
||||||
start..end
|
(start, end - start)
|
||||||
};
|
|
||||||
debug_assert!(vmo_size >= (program_header.file_size as usize).align_up(PAGE_SIZE));
|
|
||||||
page_cache_vmo.new_cow_child(parent_range).alloc()?
|
|
||||||
};
|
|
||||||
|
|
||||||
let anonymous_map_size: usize = if vmo_size > segment_vmo.size() {
|
|
||||||
vmo_size - segment_vmo.size()
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write zero as paddings. There are head padding and tail padding.
|
// Write zero as paddings. There are head padding and tail padding.
|
||||||
@ -342,17 +296,61 @@ fn init_segment_vmo(program_header: &ProgramHeader64, elf_file: &Dentry) -> Resu
|
|||||||
// Head padding.
|
// Head padding.
|
||||||
let page_offset = file_offset % PAGE_SIZE;
|
let page_offset = file_offset % PAGE_SIZE;
|
||||||
if page_offset != 0 {
|
if page_offset != 0 {
|
||||||
let buffer = vec![0u8; page_offset];
|
let new_frame = {
|
||||||
segment_vmo.write_bytes(0, &buffer)?;
|
let head_frame = segment_vmo.commit_page(segment_offset)?;
|
||||||
|
let new_frame = duplicate_frame(&head_frame)?;
|
||||||
|
|
||||||
|
let buffer = vec![0u8; page_offset];
|
||||||
|
new_frame.write_bytes(0, &buffer).unwrap();
|
||||||
|
new_frame
|
||||||
|
};
|
||||||
|
let head_idx = segment_offset / PAGE_SIZE;
|
||||||
|
segment_vmo.replace(new_frame, head_idx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tail padding.
|
// Tail padding.
|
||||||
let segment_vmo_size = segment_vmo.size();
|
|
||||||
let tail_padding_offset = program_header.file_size as usize + page_offset;
|
let tail_padding_offset = program_header.file_size as usize + page_offset;
|
||||||
if segment_vmo_size > tail_padding_offset {
|
if segment_size > tail_padding_offset {
|
||||||
let buffer = vec![0u8; (segment_vmo_size - tail_padding_offset) % PAGE_SIZE];
|
let new_frame = {
|
||||||
segment_vmo.write_bytes(tail_padding_offset, &buffer)?;
|
let tail_frame = segment_vmo.commit_page(segment_offset + tail_padding_offset)?;
|
||||||
|
let new_frame = duplicate_frame(&tail_frame)?;
|
||||||
|
|
||||||
|
let buffer = vec![0u8; (segment_size - tail_padding_offset) % PAGE_SIZE];
|
||||||
|
new_frame
|
||||||
|
.write_bytes(tail_padding_offset % PAGE_SIZE, &buffer)
|
||||||
|
.unwrap();
|
||||||
|
new_frame
|
||||||
|
};
|
||||||
|
|
||||||
|
let tail_idx = (segment_offset + tail_padding_offset) / PAGE_SIZE;
|
||||||
|
segment_vmo.replace(new_frame, tail_idx).unwrap();
|
||||||
}
|
}
|
||||||
Ok((segment_vmo.to_dyn(), anonymous_map_size))
|
|
||||||
|
let perms = parse_segment_perm(program_header.flags);
|
||||||
|
let mut vm_map_options = root_vmar
|
||||||
|
.new_map(segment_size, perms)?
|
||||||
|
.vmo(segment_vmo)
|
||||||
|
.vmo_offset(segment_offset)
|
||||||
|
.vmo_limit(segment_offset + segment_size)
|
||||||
|
.can_overwrite(true);
|
||||||
|
let offset = base_addr + (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE);
|
||||||
|
vm_map_options = vm_map_options.offset(offset);
|
||||||
|
let map_addr = vm_map_options.build()?;
|
||||||
|
|
||||||
|
let anonymous_map_size: usize = if total_map_size > segment_size {
|
||||||
|
total_map_size - segment_size
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
if anonymous_map_size > 0 {
|
||||||
|
let mut anonymous_map_options = root_vmar
|
||||||
|
.new_map(anonymous_map_size, perms)?
|
||||||
|
.can_overwrite(true);
|
||||||
|
anonymous_map_options = anonymous_map_options.offset(offset + segment_size);
|
||||||
|
anonymous_map_options.build()?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_segment_perm(flags: xmas_elf::program::Flags) -> VmPerms {
|
fn parse_segment_perm(flags: xmas_elf::program::Flags) -> VmPerms {
|
||||||
@ -411,15 +409,16 @@ pub fn init_aux_vec(elf: &Elf, elf_map_addr: Vaddr, ldso_base: Option<Vaddr>) ->
|
|||||||
Ok(aux_vec)
|
Ok(aux_vec)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map the vdso vmo to the corresponding virtual memory address.
|
/// Maps the VDSO VMO to the corresponding virtual memory address.
|
||||||
fn map_vdso_to_vm(process_vm: &ProcessVm) -> Option<Vaddr> {
|
fn map_vdso_to_vm(process_vm: &ProcessVm) -> Option<Vaddr> {
|
||||||
let root_vmar = process_vm.root_vmar();
|
let root_vmar = process_vm.root_vmar();
|
||||||
let vdso_vmo = vdso_vmo()?;
|
let vdso_vmo = vdso_vmo()?;
|
||||||
|
|
||||||
let options = root_vmar
|
let options = root_vmar
|
||||||
.new_map(vdso_vmo.dup().unwrap(), VmPerms::empty())
|
.new_map(VDSO_VMO_SIZE, VmPerms::empty())
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.size(5 * PAGE_SIZE);
|
.vmo(vdso_vmo.dup().unwrap());
|
||||||
|
|
||||||
let vdso_data_base = options.build().unwrap();
|
let vdso_data_base = options.build().unwrap();
|
||||||
let vdso_text_base = vdso_data_base + 0x4000;
|
let vdso_text_base = vdso_data_base + 0x4000;
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user