Program loader loads ld.so now

This commit is contained in:
Tate, Hongliang Tian 2019-07-06 12:41:00 +00:00
parent 13974315ad
commit 33739cc00b
6 changed files with 173 additions and 91 deletions

@ -3,13 +3,16 @@ use super::*;
use std::ptr;
use xmas_elf::{header, program, sections, ElfFile};
pub const DEFAULT_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const DEFAULT_HEAP_SIZE: usize = 8 * 1024 * 1024;
pub const DEFAULT_MMAP_SIZE: usize = 8 * 1024 * 1024;
pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result<ProcessVM, Error> {
pub fn do_init(
elf_file: &ElfFile,
elf_buf: &[u8],
ldso_elf_file: &ElfFile,
ldso_elf_buf: &[u8]
) -> Result<ProcessVM, Error> {
let mut code_seg = get_code_segment(elf_file)?;
let mut data_seg = get_data_segment(elf_file)?;
let mut ldso_code_seg = get_code_segment(ldso_elf_file)?;
let mut ldso_data_seg = get_data_segment(ldso_elf_file)?;
// Alloc all virtual memory areas
let code_start = 0;
@ -18,24 +21,22 @@ pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result<ProcessVM, Error> {
let data_end = align_up(data_seg.get_mem_addr() + data_seg.get_mem_size(), 4096);
let code_size = code_end - code_start;
let data_size = data_end - data_start;
let stack_size = DEFAULT_STACK_SIZE;
let heap_size = DEFAULT_HEAP_SIZE;
let mmap_size = DEFAULT_MMAP_SIZE;
let mut process_vm = ProcessVM::new(code_size, data_size, heap_size, stack_size, mmap_size)?;
// Calculate the "real" addresses
let process_base_addr = process_vm.get_base_addr();
let code_start = code_start + process_base_addr;
let code_end = code_end + process_base_addr;
let data_start = data_start + process_base_addr;
let data_end = data_end + process_base_addr;
code_seg.set_runtime_info(process_base_addr, code_start, code_end);
data_seg.set_runtime_info(process_base_addr, data_start, data_end);
let mut process_vm = ProcessVMBuilder::new(code_size, data_size).build()?;
// Load code and data
let process_base_addr = process_vm.get_code_range().start();
code_seg.set_runtime_base(process_base_addr);
data_seg.set_runtime_base(process_base_addr);
code_seg.load_from_file(elf_buf);
data_seg.load_from_file(elf_buf);
// Load code and data of ld.so
let ldso_base_addr = process_vm.get_ldso_code_range().start();
ldso_code_seg.set_runtime_base(ldso_base_addr);
ldso_data_seg.set_runtime_base(ldso_base_addr);
ldso_code_seg.load_from_file(ldso_elf_buf);
ldso_data_seg.load_from_file(ldso_elf_buf);
// Relocate symbols
reloc_symbols(process_base_addr, elf_file)?;
//link_syscalls(process_base_addr, elf_file)?;

@ -6,7 +6,7 @@ use misc::ResourceLimitsRef;
use std::ffi::{CStr, CString};
use std::path::Path;
use std::sgxfs::SgxFile;
use vm::{ProcessVM};
use vm::{ProcessVM, ProcessVMBuilder};
use super::task::Task;
use super::*;
@ -58,9 +58,29 @@ pub fn do_spawn<P: AsRef<Path>>(
elf_file
};
let mut ldso_elf_buf = {
let ldso_path = "/ld.so";
let ldso_inode = ROOT_INODE.lookup(ldso_path)?;
ldso_inode.read_as_vec()?
};
let ldso_elf_file = {
let ldso_elf_file =
ElfFile::new(&ldso_elf_buf).map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?;
header::sanity_check(&ldso_elf_file)
.map_err(|e| (Errno::ENOEXEC, "Failed to parse the ELF file"))?;
/*
elf_helper::print_program_headers(&elf_file)?;
elf_helper::print_sections(&elf_file)?;
elf_helper::print_pltrel_section(&elf_file)?;
*/
ldso_elf_file
};
let (new_pid, new_process_ref) = {
let cwd = parent_ref.lock().unwrap().get_cwd().to_owned();
let vm = init_vm::do_init(&elf_file, &elf_buf[..])?;
let vm = init_vm::do_init(&elf_file, &elf_buf[..],
&ldso_elf_file, &ldso_elf_buf[..])?;
let base_addr = vm.get_base_addr();
let program_entry = {
let program_entry = base_addr + elf_helper::get_start_address(&elf_file)?;

@ -11,9 +11,7 @@ pub struct Segment {
file_offset: usize,
file_size: usize,
// Runtime info after loaded
process_base_addr: usize,
start_addr: usize,
end_addr: usize,
runtime_base_addr: Option<usize>,
}
pub const PERM_R: u32 = 0x1;
@ -42,8 +40,7 @@ impl Segment {
return Err((
Errno::EINVAL,
"Memory address and file offset is not equal, per modulo",
)
.into());
).into());
}
if ph64.mem_size < ph64.file_size {
return Err((Errno::EINVAL, "Memory size must be greater than file size").into());
@ -65,7 +62,7 @@ impl Segment {
pub fn load_from_file(&self, elf_buf: &[u8]) {
let mut target_buf = unsafe {
slice::from_raw_parts_mut(
(self.process_base_addr + self.mem_addr) as *mut u8,
(self.runtime_base_addr.unwrap() + self.mem_addr) as *mut u8,
self.mem_size,
)
};
@ -77,15 +74,8 @@ impl Segment {
}
}
pub fn set_runtime_info(
&mut self,
process_base_addr: usize,
start_addr: usize,
end_addr: usize,
) {
self.process_base_addr = process_base_addr;
self.start_addr = start_addr;
self.end_addr = end_addr;
pub fn set_runtime_base(&mut self, runtime_base_addr: usize) {
self.runtime_base_addr = Some(runtime_base_addr);
}
pub fn mprotect(&mut self, perm: u32) {

@ -7,7 +7,7 @@ mod vm_manager;
mod user_space_vm;
mod process_vm;
pub use self::process_vm::{ProcessVM, MMapFlags, VMPerms};
pub use self::process_vm::{ProcessVM, ProcessVMBuilder, MMapFlags, VMPerms};
pub use self::vm_manager::{VMRange};
pub fn do_mmap(

@ -3,12 +3,121 @@ use super::vm_manager::{VMRange, VMManager, VMMapOptionsBuilder, VMMapOptions, V
use super::user_space_vm::{UserSpaceVMManager, UserSpaceVMRange, USER_SPACE_VM_MANAGER};
use std::slice;
#[derive(Debug, Default)]
pub struct ProcessVMBuilder {
code_size: usize,
data_size: usize,
ldso_code_size: Option<usize>,
ldso_data_size: Option<usize>,
heap_size: Option<usize>,
stack_size: Option<usize>,
mmap_size: Option<usize>,
}
macro_rules! impl_setter_for_process_vm_builder {
($field: ident) => {
pub fn $field(mut self, size: usize) -> Self {
self.$field = Some(size);
self
}
}
}
impl ProcessVMBuilder {
pub const DEFAULT_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const DEFAULT_HEAP_SIZE: usize = 8 * 1024 * 1024;
pub const DEFAULT_MMAP_SIZE: usize = 8 * 1024 * 1024;
pub fn new(code_size: usize, data_size: usize) -> ProcessVMBuilder {
ProcessVMBuilder {
code_size,
data_size,
..ProcessVMBuilder::default()
}
}
impl_setter_for_process_vm_builder!(ldso_data_size);
impl_setter_for_process_vm_builder!(ldso_code_size);
impl_setter_for_process_vm_builder!(heap_size);
impl_setter_for_process_vm_builder!(stack_size);
impl_setter_for_process_vm_builder!(mmap_size);
pub fn build(self) -> Result<ProcessVM, Error> {
self.validate()?;
let code_size = self.code_size;
let data_size = self.data_size;
let ldso_code_size = self.ldso_code_size.unwrap_or(0);
let ldso_data_size = self.ldso_data_size.unwrap_or(0);
let heap_size = self.heap_size.unwrap_or(ProcessVMBuilder::DEFAULT_HEAP_SIZE);
let stack_size = self.stack_size.unwrap_or(ProcessVMBuilder::DEFAULT_STACK_SIZE);
let mmap_size = self.mmap_size.unwrap_or(ProcessVMBuilder::DEFAULT_MMAP_SIZE);
let range_sizes = vec![
code_size, data_size,
ldso_code_size, ldso_data_size,
heap_size, stack_size,
mmap_size
];
let process_range = {
let total_size = range_sizes.iter().sum();
USER_SPACE_VM_MANAGER.alloc(total_size)?
};
let vm_ranges = {
let mut curr_addr = process_range.range().start();
let mut vm_ranges = Vec::new();
for range_size in &range_sizes {
let range_start = curr_addr;
let range_end = curr_addr + range_size;
let range = VMRange::from(range_start, range_end)?;
vm_ranges.push(range);
curr_addr = range_end;
}
vm_ranges
};
let code_range = *&vm_ranges[0];
let data_range = *&vm_ranges[1];
let ldso_code_range = *&vm_ranges[2];
let ldso_data_range = *&vm_ranges[3];
let heap_range = *&vm_ranges[4];
let stack_range = *&vm_ranges[5];
let mmap_range = *&vm_ranges[6];
let brk = heap_range.start();
let mmap_manager = VMManager::from(mmap_range.start(), mmap_range.size())?;
Ok(ProcessVM {
process_range,
code_range,
data_range,
ldso_code_range,
ldso_data_range,
heap_range,
stack_range,
brk,
mmap_manager,
})
}
// TODO: implement this!
fn validate(&self) -> Result<(), Error> {
Ok(())
}
}
/// The per-process virtual memory
#[derive(Debug)]
pub struct ProcessVM {
process_range: UserSpaceVMRange,
code_range: VMRange,
data_range: VMRange,
ldso_code_range: VMRange,
ldso_data_range: VMRange,
heap_range: VMRange,
stack_range: VMRange,
brk: usize,
@ -19,66 +128,19 @@ impl Default for ProcessVM {
fn default() -> ProcessVM {
ProcessVM {
process_range: USER_SPACE_VM_MANAGER.alloc_dummy(),
code_range: VMRange::default(),
data_range: VMRange::default(),
heap_range: VMRange::default(),
stack_range: VMRange::default(),
brk: 0,
mmap_manager: VMManager::default(),
code_range: Default::default(),
data_range: Default::default(),
heap_range: Default::default(),
ldso_code_range: Default::default(),
ldso_data_range: Default::default(),
stack_range: Default::default(),
brk: Default::default(),
mmap_manager: Default::default(),
}
}
}
impl ProcessVM {
pub fn new(
code_size: usize,
data_size: usize,
heap_size: usize,
stack_size: usize,
mmap_size: usize,
) -> Result<ProcessVM, Error> {
let process_range = {
let vm_range_size = code_size + data_size + heap_size + stack_size + mmap_size;
USER_SPACE_VM_MANAGER.alloc(vm_range_size)?
};
let process_addr = process_range.range().start();
let range_sizes = vec![code_size, data_size, heap_size, stack_size];
let mut curr_addr = process_addr;
let mut ranges = Vec::new();
for range_size in &range_sizes {
let range_start = curr_addr;
let range_end = curr_addr + range_size;
let range = VMRange::from(range_start, range_end)?;
ranges.push(range);
curr_addr = range_end;
}
let code_range = *&ranges[0];
let data_range = *&ranges[1];
let heap_range = *&ranges[2];
let stack_range = *&ranges[3];
unsafe {
fill_zeros(code_range.start(), code_range.size());
fill_zeros(data_range.start(), data_range.size());
}
let brk = heap_range.start();
let mmap_addr = stack_range.end();
let mmap_manager = VMManager::from(mmap_addr, mmap_size)?;
Ok(ProcessVM {
process_range,
code_range,
data_range,
heap_range,
stack_range,
brk,
mmap_manager,
})
}
pub fn get_process_range(&self) -> &VMRange {
self.process_range.range()
}
@ -91,6 +153,14 @@ impl ProcessVM {
&self.data_range
}
pub fn get_ldso_code_range(&self) -> &VMRange {
&self.ldso_code_range
}
pub fn get_ldso_data_range(&self) -> &VMRange {
&self.ldso_data_range
}
pub fn get_heap_range(&self) -> &VMRange {
&self.heap_range
}

@ -45,6 +45,7 @@ $(BUILD_TARGETS): %:
sefs:
@$(RM) -rf $(SEFS_PATH)
@cp ~/Workspace/occlum/musl.old/lib/libc.so $(FS_PATH)/ld.so
@cd $(PROJECT_DIR)/deps/sefs/sefs-fuse/bin/ && \
./app \
$(CUR_DIR)/$(SEFS_PATH) \