Enable new system call mechanism via Auxiliary Vector
The old system call mechanism works by relocating the symbol __occlum_syscall provided by libocclum_stub.so to the real entry point of the LibOS. This symbol relocation is done by the program loader. Now, the new system call mechanism is based on passing the entry point via the auxiliary vector. This new mechanism is simpler and is more compatible with the upcoming support for ld.so. Changes: 1. Fix a bug in serializing auxiliary vector in the stack of a user program; 2. Passing syscall entry via auxiliary vector; 3. Remove relocating for the __occlum_syscall symbol; 4. Remove the dependency on libocclum_stub.so in tests.
This commit is contained in:
parent
9c226c9a9f
commit
a579f84e90
@ -79,7 +79,10 @@ fn do_boot(path_str: &str, argv: &Vec<CString>) -> Result<(), Error> {
|
||||
// info!("boot: path: {:?}, argv: {:?}", path_str, argv);
|
||||
util::mpx_util::mpx_enable()?;
|
||||
|
||||
let envp = std::vec::Vec::new();
|
||||
// The default environment variables
|
||||
let envp = vec![
|
||||
CString::new("OCCLUM=yes").unwrap()
|
||||
];
|
||||
let file_actions = Vec::new();
|
||||
let parent = &process::IDLE_PROCESS;
|
||||
process::do_spawn(&path_str, argv, &envp, &file_actions, parent)?;
|
||||
|
@ -67,10 +67,12 @@ macro_rules! try_libc {
|
||||
}
|
||||
|
||||
pub fn align_up(addr: usize, align: usize) -> usize {
|
||||
(addr + (align - 1)) / align * align
|
||||
debug_assert!(align != 0 && align.is_power_of_two());
|
||||
align_down(addr + (align - 1), align)
|
||||
}
|
||||
|
||||
pub fn align_down(addr: usize, align: usize) -> usize {
|
||||
debug_assert!(align != 0 && align.is_power_of_two());
|
||||
addr & !(align - 1)
|
||||
}
|
||||
|
||||
|
@ -86,17 +86,13 @@ impl StackBuf {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn put<T>(&self, val: T) -> Result<*const T, Error>
|
||||
where
|
||||
T: Copy,
|
||||
pub fn put(&self, val: u64) -> Result<*const u64, Error>
|
||||
{
|
||||
let val_size = mem::size_of::<T>();
|
||||
let val_align = mem::align_of::<T>();
|
||||
let val_ptr = self.alloc(val_size, val_align)? as *mut T;
|
||||
let val_ptr = self.alloc(8, 8)? as *mut u64;
|
||||
unsafe {
|
||||
ptr::write(val_ptr, val);
|
||||
}
|
||||
Ok(val_ptr as *const T)
|
||||
Ok(val_ptr as *const u64)
|
||||
}
|
||||
|
||||
pub fn put_slice<T>(&self, vals: &[T]) -> Result<*const T, Error>
|
||||
@ -164,12 +160,12 @@ fn clone_cstrings_on_stack<'a, 'b>(
|
||||
}
|
||||
|
||||
fn dump_auxtbl_on_stack<'a, 'b>(stack: &'a StackBuf, auxtbl: &'b AuxTable) -> Result<(), Error> {
|
||||
// For every key-value pari, dump the value first, then the key
|
||||
// For every key-value pair, dump the value first, then the key
|
||||
stack.put(0 as u64);
|
||||
stack.put(AuxKey::AT_NULL as u64);
|
||||
stack.put(AuxKey::AT_NULL as u64);
|
||||
for (aux_key, aux_val) in auxtbl {
|
||||
stack.put(aux_val);
|
||||
stack.put(aux_key as u64);
|
||||
for (aux_key, aux_val) in auxtbl.table() {
|
||||
stack.put(*aux_val as u64);
|
||||
stack.put(*aux_key as u64);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -188,7 +184,7 @@ fn dump_cstrptrs_on_stack<'a, 'b>(
|
||||
/* Symbolic values for the entries in the auxiliary table
|
||||
put on the initial stack */
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum AuxKey {
|
||||
AT_NULL = 0, /* end of vector */
|
||||
AT_IGNORE = 1, /* entry should be ignored */
|
||||
@ -210,122 +206,53 @@ pub enum AuxKey {
|
||||
AT_CLKTCK = 17, /* frequency at which times() increments */
|
||||
|
||||
/* 18...22 not used */
|
||||
AT_SECURE = 23, /* secure mode boolean */
|
||||
AT_SECURE = 23, /* secure mode boolean */
|
||||
AT_BASE_PLATFORM = 24, /* string identifying real platform, may
|
||||
* differ from AT_PLATFORM. */
|
||||
AT_RANDOM = 25, /* address of 16 random bytes */
|
||||
AT_HWCAP2 = 26, /* extension of AT_HWCAP */
|
||||
AT_RANDOM = 25, /* address of 16 random bytes */
|
||||
AT_HWCAP2 = 26, /* extension of AT_HWCAP */
|
||||
|
||||
/* 28...30 not used */
|
||||
AT_EXECFN = 31, /* filename of program */
|
||||
AT_EXECFN = 31, /* filename of program */
|
||||
AT_SYSINFO = 32,
|
||||
|
||||
/* Occlum-specific entries */
|
||||
AT_OCCLUM_ENTRY = 48, /* the entry point of Occlum, i.e., syscall */
|
||||
}
|
||||
|
||||
static AUX_KEYS: &'static [AuxKey] = &[
|
||||
AuxKey::AT_NULL,
|
||||
AuxKey::AT_IGNORE,
|
||||
AuxKey::AT_EXECFD,
|
||||
AuxKey::AT_PHDR,
|
||||
AuxKey::AT_PHENT,
|
||||
AuxKey::AT_PHNUM,
|
||||
AuxKey::AT_PAGESZ,
|
||||
AuxKey::AT_BASE,
|
||||
AuxKey::AT_FLAGS,
|
||||
AuxKey::AT_ENTRY,
|
||||
AuxKey::AT_NOTELF,
|
||||
AuxKey::AT_UID,
|
||||
AuxKey::AT_EUID,
|
||||
AuxKey::AT_GID,
|
||||
AuxKey::AT_EGID,
|
||||
AuxKey::AT_PLATFORM,
|
||||
AuxKey::AT_HWCAP,
|
||||
AuxKey::AT_CLKTCK,
|
||||
AuxKey::AT_SECURE,
|
||||
AuxKey::AT_BASE_PLATFORM,
|
||||
AuxKey::AT_RANDOM,
|
||||
AuxKey::AT_HWCAP2,
|
||||
AuxKey::AT_EXECFN,
|
||||
];
|
||||
|
||||
impl AuxKey {
|
||||
pub const MAX: usize = 32;
|
||||
|
||||
pub fn next(&self) -> Option<AuxKey> {
|
||||
let self_idx = AUX_KEYS.iter().position(|x| *x == *self).unwrap();
|
||||
let next_idx = self_idx + 1;
|
||||
if next_idx < AUX_KEYS.len() {
|
||||
Some(AUX_KEYS[next_idx])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Copy, Debug)]
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct AuxTable {
|
||||
values: [Option<u64>; AuxKey::MAX],
|
||||
table: HashMap<AuxKey, u64>,
|
||||
}
|
||||
|
||||
impl AuxTable {
|
||||
pub fn new() -> AuxTable {
|
||||
AuxTable {
|
||||
values: [None; AuxKey::MAX],
|
||||
table: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_val(&mut self, key: AuxKey, val: u64) -> Result<(), Error> {
|
||||
impl AuxTable {
|
||||
pub fn set(&mut self, key: AuxKey, val: u64) -> Result<(), Error> {
|
||||
if key == AuxKey::AT_NULL || key == AuxKey::AT_IGNORE {
|
||||
return errno!(EINVAL, "Illegal key");
|
||||
}
|
||||
self.values[key as usize] = Some(val);
|
||||
self.table.entry(key)
|
||||
.and_modify(|val_mut| *val_mut = val)
|
||||
.or_insert(val);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_val(&self, key: AuxKey) -> Option<u64> {
|
||||
self.values[key as usize]
|
||||
pub fn get(&self, key: AuxKey) -> Option<u64> {
|
||||
self.table.get(&key).map(|val_ref| *val_ref)
|
||||
}
|
||||
|
||||
pub fn del_val(&mut self, key: AuxKey) {
|
||||
self.values[key as usize] = None;
|
||||
pub fn del(&mut self, key: AuxKey) -> Option<u64>{
|
||||
self.table.remove(&key)
|
||||
}
|
||||
|
||||
pub fn iter<'a>(&'a self) -> AuxTableIter<'a> {
|
||||
AuxTableIter {
|
||||
tbl: self,
|
||||
key: Some(AuxKey::AT_NULL),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a AuxTable {
|
||||
type Item = (AuxKey, u64);
|
||||
type IntoIter = AuxTableIter<'a>;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.iter()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AuxTableIter<'a> {
|
||||
tbl: &'a AuxTable,
|
||||
key: Option<AuxKey>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for AuxTableIter<'a> {
|
||||
type Item = (AuxKey, u64);
|
||||
|
||||
fn next(&mut self) -> Option<(AuxKey, u64)> {
|
||||
loop {
|
||||
if self.key == None {
|
||||
return None;
|
||||
}
|
||||
let key = self.key.unwrap();
|
||||
|
||||
let item = self.tbl.get_val(key).map(|val| (key, val));
|
||||
self.key = key.next();
|
||||
|
||||
if item != None {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
pub fn table(&self) -> &HashMap<AuxKey, u64> {
|
||||
&self.table
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result<ProcessVM, Error> {
|
||||
|
||||
// Relocate symbols
|
||||
reloc_symbols(process_base_addr, elf_file)?;
|
||||
link_syscalls(process_base_addr, elf_file)?;
|
||||
//link_syscalls(process_base_addr, elf_file)?;
|
||||
|
||||
Ok(process_vm)
|
||||
}
|
||||
@ -69,7 +69,7 @@ fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Err
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/*
|
||||
fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Error> {
|
||||
let syscall_addr = __occlum_syscall as *const () as usize;
|
||||
|
||||
@ -92,7 +92,7 @@ fn link_syscalls(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Err
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
*/
|
||||
extern "C" {
|
||||
fn __occlum_syscall(num: i32, arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> i64;
|
||||
}
|
||||
|
@ -152,19 +152,24 @@ fn init_auxtbl(
|
||||
elf_file: &ElfFile,
|
||||
) -> Result<AuxTable, Error> {
|
||||
let mut auxtbl = AuxTable::new();
|
||||
auxtbl.set_val(AuxKey::AT_PAGESZ, 4096)?;
|
||||
auxtbl.set_val(AuxKey::AT_UID, 0)?;
|
||||
auxtbl.set_val(AuxKey::AT_GID, 0)?;
|
||||
auxtbl.set_val(AuxKey::AT_EUID, 0)?;
|
||||
auxtbl.set_val(AuxKey::AT_EGID, 0)?;
|
||||
auxtbl.set_val(AuxKey::AT_SECURE, 0)?;
|
||||
auxtbl.set(AuxKey::AT_PAGESZ, 4096)?;
|
||||
auxtbl.set(AuxKey::AT_UID, 0)?;
|
||||
auxtbl.set(AuxKey::AT_GID, 0)?;
|
||||
auxtbl.set(AuxKey::AT_EUID, 0)?;
|
||||
auxtbl.set(AuxKey::AT_EGID, 0)?;
|
||||
auxtbl.set(AuxKey::AT_SECURE, 0)?;
|
||||
|
||||
let ph = elf_helper::get_program_header_info(elf_file)?;
|
||||
auxtbl.set_val(AuxKey::AT_PHDR, (base_addr + ph.addr) as u64)?;
|
||||
auxtbl.set_val(AuxKey::AT_PHENT, ph.entry_size as u64)?;
|
||||
auxtbl.set_val(AuxKey::AT_PHNUM, ph.entry_num as u64)?;
|
||||
auxtbl.set(AuxKey::AT_PHDR, (base_addr + ph.addr) as u64)?;
|
||||
auxtbl.set(AuxKey::AT_PHENT, ph.entry_size as u64)?;
|
||||
auxtbl.set(AuxKey::AT_PHNUM, ph.entry_num as u64)?;
|
||||
|
||||
auxtbl.set_val(AuxKey::AT_ENTRY, program_entry as u64)?;
|
||||
auxtbl.set(AuxKey::AT_ENTRY, program_entry as u64)?;
|
||||
|
||||
auxtbl.set(AuxKey::AT_SYSINFO, 123)?;
|
||||
|
||||
let syscall_addr = __occlum_syscall as *const () as u64;
|
||||
auxtbl.set(AuxKey::AT_OCCLUM_ENTRY, syscall_addr)?;
|
||||
// TODO: init AT_EXECFN
|
||||
// auxtbl.set_val(AuxKey::AT_EXECFN, "program_name")?;
|
||||
|
||||
@ -177,3 +182,7 @@ fn parent_adopts_new_child(parent_ref: &ProcessRef, child_ref: &ProcessRef) {
|
||||
parent.children.push(Arc::downgrade(child_ref));
|
||||
child.parent = Some(parent_ref.clone());
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn __occlum_syscall(num: i32, arg0: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> i64;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ PROJECT_DIR := $(realpath $(CUR_DIR)/../)
|
||||
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||
TEST_DEPS := dev_null
|
||||
# Tests: need to be compiled and run by test-% target
|
||||
TESTS := empty argv hello_world malloc mmap file getpid spawn pipe time \
|
||||
TESTS := empty env hello_world malloc mmap file getpid spawn pipe time \
|
||||
truncate readdir mkdir link tls pthread uname rlimit client server \
|
||||
server_epoll unix_socket cout hostfs cpuid rdtsc device
|
||||
# Benchmarks: need to be compiled and run by bench-% target
|
||||
|
@ -1,30 +0,0 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Expected arguments are given by Makefile throught macro ARGC, ARG1, ARG2 and
|
||||
// ARG3
|
||||
const char* expected_argv[EXPECTED_ARGC] = {
|
||||
"argv",
|
||||
EXPECTED_ARG1,
|
||||
EXPECTED_ARG2,
|
||||
EXPECTED_ARG3,
|
||||
};
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
if (argc != EXPECTED_ARGC) {
|
||||
printf("ERROR: expect %d arguments, but %d are given\n", EXPECTED_ARGC, argc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (int arg_i = 0; arg_i < argc; arg_i++) {
|
||||
const char* actual_arg = argv[arg_i];
|
||||
const char* expected_arg = expected_argv[arg_i];
|
||||
if (strcmp(actual_arg, expected_arg) != 0) {
|
||||
printf("ERROR: expect argument %d is %s, but given %s\n",
|
||||
arg_i, expected_arg, actual_arg);
|
||||
}
|
||||
}
|
||||
|
||||
printf("main()'s argc and argv are as expected\n");
|
||||
return 0;
|
||||
}
|
0
test/argv/Makefile → test/env/Makefile
vendored
0
test/argv/Makefile → test/env/Makefile
vendored
57
test/env/main.c
vendored
Normal file
57
test/env/main.c
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <elf.h>
|
||||
#include <errno.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Expected arguments are given by Makefile throught macro ARGC, ARG1, ARG2 and
|
||||
// ARG3
|
||||
const char* expected_argv[EXPECTED_ARGC] = {
|
||||
"env",
|
||||
EXPECTED_ARG1,
|
||||
EXPECTED_ARG2,
|
||||
EXPECTED_ARG3,
|
||||
};
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
// Test argc
|
||||
if (argc != EXPECTED_ARGC) {
|
||||
printf("ERROR: expect %d arguments, but %d are given\n", EXPECTED_ARGC, argc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test argv
|
||||
for (int arg_i = 0; arg_i < argc; arg_i++) {
|
||||
printf("arg[%d] = %s\n", arg_i, argv[arg_i]);
|
||||
const char* actual_arg = argv[arg_i];
|
||||
const char* expected_arg = expected_argv[arg_i];
|
||||
if (strcmp(actual_arg, expected_arg) != 0) {
|
||||
printf("ERROR: expect argument %d is %s, but given %s\n",
|
||||
arg_i, expected_arg, actual_arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Test envp
|
||||
// Occlum LibOS by default passes an environment OCCLUM=yes
|
||||
const char* env_val = getenv("OCCLUM");
|
||||
if (env_val == 0) {
|
||||
printf("ERROR: cannot find environment variable OCCLUM\n");
|
||||
return -1;
|
||||
}
|
||||
else if (strcmp(env_val, "yes") != 0) {
|
||||
printf("ERROR: environment variable OCCLUM=yes expected, but given %s\n",
|
||||
env_val);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test aux
|
||||
unsigned long page_size = getauxval(AT_PAGESZ);
|
||||
if (errno != 0 || page_size != 4096) {
|
||||
printf("ERROR: auxilary vector does not pass correct the value\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -21,7 +21,7 @@ LLVM_PATH := $(abspath $(dir $(CLANG_BIN_PATH))../)
|
||||
|
||||
C_FLAGS = -Wall -I../include -O2 -fPIC $(EXTRA_C_FLAGS)
|
||||
C_FLAGS += -Xclang -load -Xclang $(LLVM_PATH)/lib/LLVMMDSFIIRInserter.so
|
||||
LINK_FLAGS = $(C_FLAGS) -pie -locclum_stub $(EXTRA_LINK_FLAGS)
|
||||
LINK_FLAGS = $(C_FLAGS) -pie $(EXTRA_LINK_FLAGS)
|
||||
|
||||
.PHONY: all test debug clean
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user