mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
support loading shared object
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
5a2f3c94b0
commit
66d72b0104
3
.gitattributes
vendored
3
.gitattributes
vendored
@ -6,4 +6,5 @@ src/apps/execve/hello filter=lfs diff=lfs merge=lfs -text
|
||||
src/apps/fork_c/fork filter=lfs diff=lfs merge=lfs -text
|
||||
src/apps/signal_c/signal_test filter=lfs diff=lfs merge=lfs -text
|
||||
src/apps/busybox/busybox filter=lfs diff=lfs merge=lfs -text
|
||||
src/apps/pthread/pthread_test filter=lfs diff=lfs merge=lfs -text
|
||||
src/apps/pthread/pthread_test filter=lfs diff=lfs merge=lfs -text
|
||||
src/apps/hello_pie/hello filter=lfs diff=lfs merge=lfs -text
|
||||
|
@ -1,9 +1,12 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello.c execve.c
|
||||
@gcc -static hello.c -o hello
|
||||
@gcc -static execve.c -o execve
|
||||
|
||||
clean:
|
||||
@rm hello
|
||||
@rm execve
|
||||
|
||||
run: build
|
||||
@./execve
|
@ -1,7 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: fork.s
|
||||
@gcc -static -nostdlib fork.s -o fork
|
||||
|
||||
clean:
|
||||
@rm fork
|
||||
|
||||
run: build
|
||||
@./fork
|
@ -1,7 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: fork.c
|
||||
@gcc -static fork.c -o fork
|
||||
|
||||
clean:
|
||||
@rm fork
|
||||
|
||||
run: build
|
||||
@./fork
|
@ -1,7 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello.c
|
||||
@gcc -static -mno-sse hello.c -o hello
|
||||
|
||||
clean:
|
||||
@rm hello
|
||||
|
||||
run: build
|
||||
@./hello
|
10
src/apps/hello_pie/Makefile
Normal file
10
src/apps/hello_pie/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello.c
|
||||
@gcc hello.c -o hello
|
||||
|
||||
clean:
|
||||
@rm hello
|
||||
|
||||
run: build
|
||||
@./hello
|
3
src/apps/hello_pie/hello
Executable file
3
src/apps/hello_pie/hello
Executable file
@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:da31082cbaabc14fb9f6b62933844d61a73942dd23a28ac920d86c163126b530
|
||||
size 16696
|
6
src/apps/hello_pie/hello.c
Normal file
6
src/apps/hello_pie/hello.c
Normal file
@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("hello world from hello_c!\n");
|
||||
return 0;
|
||||
}
|
@ -1,7 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: hello_world.s
|
||||
@gcc -static -nostdlib hello_world.s -o hello_world
|
||||
|
||||
clean:
|
||||
@rm hello_world
|
||||
|
||||
run: build
|
||||
@./hello_world
|
@ -1,7 +1,10 @@
|
||||
.PHONY: build clean run
|
||||
|
||||
build: pthread_test.c
|
||||
@gcc -static pthread_test.c -lpthread -o pthread_test
|
||||
|
||||
clean:
|
||||
@rm pthread_test
|
||||
|
||||
run: build
|
||||
@./pthread_test
|
@ -16,7 +16,7 @@ ifneq (, $(wildcard $(INITRAMFS)/. ))
|
||||
endif
|
||||
|
||||
|
||||
.PHONY: all clean
|
||||
.PHONY: all clean prepare_libs
|
||||
|
||||
all: $(RAMDISK)
|
||||
|
||||
@ -25,7 +25,13 @@ $(INITRAMFS): $(APPS) $(APPS_DIRS) $(APPS_FILES)
|
||||
@cp -a $(APPS)/* $@
|
||||
@cd $@ && find . \( -name "*.s" -o -name "*.c" -o -name "Makefile" -o -name "README.md" \) -delete
|
||||
|
||||
$(RAMDISK): $(INITRAMFS) $(INITRAMFS_DIRS) $(INITRAMFS_FILES)
|
||||
prepare_libs: $(INITRAMFS)
|
||||
@mkdir -p $(INITRAMFS)/lib64
|
||||
@cp -L /lib64/ld-linux-x86-64.so.2 $(INITRAMFS)/lib64
|
||||
@mkdir -p $(INITRAMFS)/lib/x86_64-linux-gnu
|
||||
@cp -L /lib/x86_64-linux-gnu/libc.so.6 $(INITRAMFS)/lib/x86_64-linux-gnu
|
||||
|
||||
$(RAMDISK): $(INITRAMFS) $(INITRAMFS_DIRS) $(INITRAMFS_FILES) prepare_libs
|
||||
@echo "Generating the ramdisk image..."
|
||||
@rm -rf $(BUILD_DIR) && mkdir -p $(BUILD_DIR)
|
||||
@./mkinitramfs $(INITRAMFS) $@
|
||||
|
@ -16,8 +16,8 @@ impl Elf {
|
||||
// The elf header is usually 64 bytes. pt1 is 16bytes and pt2 is 48 bytes.
|
||||
// We require 128 bytes here is to keep consistency with linux implementations.
|
||||
debug_assert!(input.len() >= 128);
|
||||
let header =
|
||||
xmas_elf::header::parse_header(input).map_err(|_| Error::new(Errno::ENOEXEC))?;
|
||||
let header = xmas_elf::header::parse_header(input)
|
||||
.map_err(|_| Error::with_message(Errno::ENOEXEC, "parse elf header fails"))?;
|
||||
let elf_header = ElfHeader::parse_elf_header(header)?;
|
||||
check_elf_header(&elf_header)?;
|
||||
// than parse the program headers table
|
||||
@ -31,7 +31,7 @@ impl Elf {
|
||||
let mut program_headers = Vec::with_capacity(ph_count as usize);
|
||||
for index in 0..ph_count {
|
||||
let program_header = xmas_elf::program::parse_program_header(input, header, index)
|
||||
.map_err(|_| Error::new(Errno::ENOEXEC))?;
|
||||
.map_err(|_| Error::with_message(Errno::ENOEXEC, "parse program header fails"))?;
|
||||
let ph64 = match program_header {
|
||||
xmas_elf::program::ProgramHeader::Ph64(ph64) => ph64.clone(),
|
||||
xmas_elf::program::ProgramHeader::Ph32(_) => {
|
||||
@ -81,6 +81,11 @@ impl Elf {
|
||||
"can not find program header table address in elf"
|
||||
);
|
||||
}
|
||||
|
||||
/// whether the elf is a shared object
|
||||
pub fn is_shared_object(&self) -> bool {
|
||||
self.elf_header.pt2.type_.as_type() == header::Type::SharedObject
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ElfHeader {
|
||||
@ -167,9 +172,10 @@ fn check_elf_header(elf_header: &ElfHeader) -> Result<()> {
|
||||
if elf_header.pt2.machine.as_machine() != header::Machine::X86_64 {
|
||||
return_errno_with_message!(Errno::ENOEXEC, "Not x86_64 executable");
|
||||
}
|
||||
// Executable file
|
||||
debug_assert_eq!(elf_header.pt2.type_.as_type(), header::Type::Executable);
|
||||
if elf_header.pt2.type_.as_type() != header::Type::Executable {
|
||||
// Executable file or shared object
|
||||
let elf_type = elf_header.pt2.type_.as_type();
|
||||
debug_assert!(elf_type == header::Type::Executable || elf_type == header::Type::SharedObject);
|
||||
if elf_type != header::Type::Executable && elf_type != header::Type::SharedObject {
|
||||
return_errno_with_message!(Errno::ENOEXEC, "Not executable file");
|
||||
}
|
||||
|
||||
|
@ -70,8 +70,6 @@ pub struct InitStack {
|
||||
argv: Vec<CString>,
|
||||
/// Environmental variables
|
||||
envp: Vec<CString>,
|
||||
/// Auxiliary Vector
|
||||
aux_vec: AuxVec,
|
||||
}
|
||||
|
||||
impl InitStack {
|
||||
@ -88,7 +86,6 @@ impl InitStack {
|
||||
pos: init_stack_top,
|
||||
argv,
|
||||
envp,
|
||||
aux_vec: AuxVec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -112,9 +109,9 @@ impl InitStack {
|
||||
self.init_stack_top - self.init_stack_size
|
||||
}
|
||||
|
||||
pub fn init(&mut self, root_vmar: &Vmar<Full>, elf: &Elf) -> Result<()> {
|
||||
pub fn init(&mut self, root_vmar: &Vmar<Full>, elf: &Elf, aux_vec: &mut AuxVec) -> Result<()> {
|
||||
self.map_and_zeroed(root_vmar)?;
|
||||
self.write_stack_content(root_vmar, elf)?;
|
||||
self.write_stack_content(root_vmar, elf, aux_vec)?;
|
||||
self.debug_print_stack_content(root_vmar);
|
||||
Ok(())
|
||||
}
|
||||
@ -139,10 +136,11 @@ impl InitStack {
|
||||
root_vmar: &Vmar<Full>,
|
||||
envp_pointers: &Vec<u64>,
|
||||
argv_pointers: &Vec<u64>,
|
||||
aux_vec: &AuxVec,
|
||||
) -> Result<()> {
|
||||
// ensure 8-byte alignment
|
||||
self.write_u64(0, root_vmar)?;
|
||||
let auxvec_size = (self.aux_vec.table().len() + 1) * (mem::size_of::<u64>() * 2);
|
||||
let auxvec_size = (aux_vec.table().len() + 1) * (mem::size_of::<u64>() * 2);
|
||||
let envp_pointers_size = (envp_pointers.len() + 1) * mem::size_of::<u64>();
|
||||
let argv_pointers_size = (argv_pointers.len() + 1) * mem::size_of::<u64>();
|
||||
let argc_size = mem::size_of::<u64>();
|
||||
@ -153,7 +151,12 @@ impl InitStack {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_stack_content(&mut self, root_vmar: &Vmar<Full>, elf: &Elf) -> Result<()> {
|
||||
fn write_stack_content(
|
||||
&mut self,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf: &Elf,
|
||||
aux_vec: &mut AuxVec,
|
||||
) -> Result<()> {
|
||||
// write a zero page. When a user program tries to read a cstring(like argv) from init stack,
|
||||
// it will typically read 4096 bytes and then find the first '\0' in the buffer
|
||||
// (we now read 128 bytes, which is set by MAX_FILENAME_LEN).
|
||||
@ -169,13 +172,9 @@ impl InitStack {
|
||||
// write random value
|
||||
let random_value = generate_random_for_aux_vec();
|
||||
let random_value_pointer = self.write_bytes(&random_value, root_vmar)?;
|
||||
self.aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?;
|
||||
self.aux_vec.set(AuxKey::AT_PAGESZ, PAGE_SIZE as _)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHDR, elf.ph_addr()? as u64)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
|
||||
self.aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
|
||||
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers)?;
|
||||
self.write_aux_vec(root_vmar)?;
|
||||
aux_vec.set(AuxKey::AT_RANDOM, random_value_pointer)?;
|
||||
self.adjust_stack_alignment(root_vmar, &envp_pointers, &argv_pointers, &aux_vec)?;
|
||||
self.write_aux_vec(root_vmar, aux_vec)?;
|
||||
self.write_envp_pointers(root_vmar, envp_pointers)?;
|
||||
self.write_argv_pointers(root_vmar, argv_pointers)?;
|
||||
// write argc
|
||||
@ -214,13 +213,12 @@ impl InitStack {
|
||||
Ok(argv_pointers)
|
||||
}
|
||||
|
||||
fn write_aux_vec(&mut self, root_vmar: &Vmar<Full>) -> Result<()> {
|
||||
fn write_aux_vec(&mut self, root_vmar: &Vmar<Full>, aux_vec: &mut AuxVec) -> Result<()> {
|
||||
// Write NULL auxilary
|
||||
self.write_u64(0, root_vmar)?;
|
||||
self.write_u64(AuxKey::AT_NULL as u64, root_vmar)?;
|
||||
// Write Auxiliary vectors
|
||||
let aux_vec: Vec<_> = self
|
||||
.aux_vec
|
||||
let aux_vec: Vec<_> = aux_vec
|
||||
.table()
|
||||
.iter()
|
||||
.map(|(aux_key, aux_value)| (*aux_key, *aux_value))
|
||||
@ -322,6 +320,20 @@ impl InitStack {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init_aux_vec(elf: &Elf, elf_map_addr: Option<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()
|
||||
} else {
|
||||
elf.ph_addr()?
|
||||
};
|
||||
aux_vec.set(AuxKey::AT_PHDR, ph_addr as u64)?;
|
||||
aux_vec.set(AuxKey::AT_PHNUM, elf.ph_count() as u64)?;
|
||||
aux_vec.set(AuxKey::AT_PHENT, elf.ph_ent() as u64)?;
|
||||
Ok(aux_vec)
|
||||
}
|
||||
|
||||
/// generate random [u8; 16].
|
||||
/// FIXME: generate really random value. Now only return array with fixed values.
|
||||
fn generate_random_for_aux_vec() -> [u8; 16] {
|
||||
|
@ -2,7 +2,7 @@
|
||||
//! When create a process from elf file, we will use the elf_load_info to construct the VmSpace
|
||||
|
||||
use crate::fs::file_handle::FileHandle;
|
||||
use crate::process::program_loader::elf::init_stack::InitStack;
|
||||
use crate::process::program_loader::elf::init_stack::{init_aux_vec, InitStack};
|
||||
use crate::vm::perms::VmPerms;
|
||||
use crate::vm::vmo::VmoRightsOp;
|
||||
use crate::{
|
||||
@ -32,10 +32,16 @@ pub fn load_elf_to_root_vmar(
|
||||
envp: Vec<CString>,
|
||||
) -> Result<ElfLoadInfo> {
|
||||
let elf = Elf::parse_elf(file_header)?;
|
||||
map_segment_vmos(&elf, root_vmar, elf_file)?;
|
||||
let map_addr = map_segment_vmos(&elf, root_vmar, elf_file)?;
|
||||
let mut aux_vec = init_aux_vec(&elf, map_addr)?;
|
||||
let mut init_stack = InitStack::new_default_config(argv, envp);
|
||||
init_stack.init(root_vmar, &elf)?;
|
||||
let elf_load_info = ElfLoadInfo::new(elf.entry_point(), init_stack.user_stack_top());
|
||||
init_stack.init(root_vmar, &elf, &mut aux_vec)?;
|
||||
let entry_point = if elf.is_shared_object() {
|
||||
elf.entry_point() + map_addr.unwrap()
|
||||
} else {
|
||||
elf.entry_point()
|
||||
};
|
||||
let elf_load_info = ElfLoadInfo::new(entry_point, init_stack.user_stack_top());
|
||||
debug!("load elf succeeds.");
|
||||
Ok(elf_load_info)
|
||||
}
|
||||
@ -67,17 +73,26 @@ pub fn map_segment_vmos(
|
||||
elf: &Elf,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_file: Arc<FileHandle>,
|
||||
) -> Result<()> {
|
||||
) -> Result<Option<Vaddr>> {
|
||||
let is_shared_object = elf.is_shared_object();
|
||||
let mut file_map_addr = None;
|
||||
for program_header in &elf.program_headers {
|
||||
let type_ = program_header
|
||||
.get_type()
|
||||
.map_err(|_| Error::new(Errno::ENOEXEC))?;
|
||||
.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.clone())?;
|
||||
map_segment_vmo(program_header, vmo, root_vmar, elf_file.clone())?;
|
||||
map_segment_vmo(
|
||||
program_header,
|
||||
vmo,
|
||||
root_vmar,
|
||||
elf_file.clone(),
|
||||
&mut file_map_addr,
|
||||
is_shared_object,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
Ok(file_map_addr)
|
||||
}
|
||||
|
||||
/// map the segment vmo to root_vmar
|
||||
@ -86,11 +101,29 @@ fn map_segment_vmo(
|
||||
vmo: Vmo,
|
||||
root_vmar: &Vmar<Full>,
|
||||
elf_file: Arc<FileHandle>,
|
||||
file_map_addr: &mut Option<Vaddr>,
|
||||
is_shared_object: bool,
|
||||
) -> Result<()> {
|
||||
let perms = VmPerms::from(parse_segment_perm(program_header.flags)?);
|
||||
let offset = (program_header.virtual_addr as Vaddr).align_down(PAGE_SIZE);
|
||||
let vm_map_options = root_vmar.new_map(vmo, perms)?.offset(offset);
|
||||
debug!(
|
||||
"map segment vmo: offset = 0x{:x}, virtual_addr = 0x{:x}",
|
||||
offset, program_header.virtual_addr
|
||||
);
|
||||
let mut vm_map_options = root_vmar.new_map(vmo, perms)?;
|
||||
// offset = 0 means the vmo can be put at any address
|
||||
if is_shared_object {
|
||||
if let Some(file_init_addr) = *file_map_addr {
|
||||
let offset = file_init_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()?;
|
||||
if is_shared_object && *file_map_addr == None {
|
||||
*file_map_addr = Some(map_addr);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -59,6 +59,6 @@ pub fn load_program_to_root_vmar(
|
||||
}
|
||||
|
||||
let elf_file = Arc::new(FileHandle::new_inode_handle(file));
|
||||
let elf_load_info = load_elf_to_root_vmar(root_vmar, &file_header, elf_file, argv, envp)?;
|
||||
Ok((abs_path, elf_load_info))
|
||||
debug!("load executable, path = {}", executable_path);
|
||||
load_elf_to_root_vmar(root_vmar, &file_header, elf_file, argv, envp)
|
||||
}
|
||||
|
Reference in New Issue
Block a user