Enable Thread Local Storage (TLS)
Add arch_prctl and pass necessary ELF info to libc via aux vector
This commit is contained in:
parent
b2e626760b
commit
db40e8f52b
43
src/libos/src/process/arch_prctl.rs
Normal file
43
src/libos/src/process/arch_prctl.rs
Normal file
@ -0,0 +1,43 @@
|
||||
use super::*;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug)]
|
||||
pub enum ArchPrctlCode {
|
||||
ARCH_SET_GS = 0x1001,
|
||||
ARCH_SET_FS = 0x1002,
|
||||
ARCH_GET_FS = 0x1003,
|
||||
ARCH_GET_GS = 0x1004,
|
||||
}
|
||||
|
||||
impl ArchPrctlCode {
|
||||
pub fn from_u32(bits: u32) -> Result<ArchPrctlCode, Error> {
|
||||
match bits {
|
||||
0x1001 => Ok(ArchPrctlCode::ARCH_SET_GS),
|
||||
0x1002 => Ok(ArchPrctlCode::ARCH_SET_FS),
|
||||
0x1003 => Ok(ArchPrctlCode::ARCH_GET_FS),
|
||||
0x1004 => Ok(ArchPrctlCode::ARCH_GET_GS),
|
||||
_ => errno!(EINVAL, "Unknown code for arch_prctl"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn do_arch_prctl(code: ArchPrctlCode, addr: *mut usize) -> Result<(), Error> {
|
||||
info!("do_arch_prctl: code: {:?}, addr: {:#o}", code, addr as usize);
|
||||
match code {
|
||||
ArchPrctlCode::ARCH_SET_FS => {
|
||||
let current_ref = get_current();
|
||||
let mut current = current_ref.lock().unwrap();
|
||||
let task = &mut current.task;
|
||||
task.user_fsbase_addr = addr as usize;
|
||||
},
|
||||
ArchPrctlCode::ARCH_GET_FS => {
|
||||
let current_ref = get_current();
|
||||
let current = current_ref.lock().unwrap();
|
||||
let task = ¤t.task;
|
||||
unsafe { *addr = task.user_fsbase_addr; }
|
||||
},
|
||||
ArchPrctlCode::ARCH_SET_GS | ArchPrctlCode::ARCH_GET_GS
|
||||
=> return errno!(EINVAL, "GS cannot be accessed from the user space"),
|
||||
}
|
||||
Ok(())
|
||||
}
|
@ -8,6 +8,7 @@ pub use self::spawn::{do_spawn, FileAction};
|
||||
pub use self::wait::{WaitQueue, Waiter};
|
||||
pub use self::thread::{do_clone, CloneFlags, ThreadGroup};
|
||||
pub use self::futex::{FutexOp, FutexFlags, futex_op_and_flags_from_u32, futex_wake, futex_wait};
|
||||
pub use self::arch_prctl::{ArchPrctlCode, do_arch_prctl};
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type pid_t = u32;
|
||||
@ -65,6 +66,7 @@ mod task;
|
||||
mod wait;
|
||||
mod thread;
|
||||
mod futex;
|
||||
mod arch_prctl;
|
||||
|
||||
use self::task::Task;
|
||||
use super::*;
|
||||
|
@ -6,6 +6,22 @@ use xmas_elf::symbol_table::Entry;
|
||||
use xmas_elf::symbol_table::{DynEntry64, Entry64};
|
||||
use xmas_elf::{program, sections, ElfFile, P64};
|
||||
|
||||
#[derive(Clone, Default, Copy, Debug)]
|
||||
pub struct ProgramHeaderInfo {
|
||||
pub addr: usize,
|
||||
pub entry_size: usize,
|
||||
pub entry_num: usize,
|
||||
}
|
||||
|
||||
pub fn get_program_header_info(elf_file: &ElfFile) -> Result<ProgramHeaderInfo, Error> {
|
||||
let elf_header = &elf_file.header.pt2;
|
||||
Ok(ProgramHeaderInfo {
|
||||
addr: elf_header.ph_offset() as usize,
|
||||
entry_size: elf_header.ph_entry_size() as usize,
|
||||
entry_num: elf_header.ph_count() as usize,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), Error> {
|
||||
println!("Program headers:");
|
||||
let ph_iter = elf_file.program_iter();
|
||||
@ -87,18 +103,8 @@ pub fn get_code_program_header<'b, 'a: 'b>(
|
||||
}
|
||||
|
||||
pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<usize, Error> {
|
||||
let sym_entries = get_sym_entries(elf_file)?;
|
||||
|
||||
for sym_entry in sym_entries {
|
||||
let sym_str = sym_entry
|
||||
.get_name(elf_file)
|
||||
.map_err(|e| Error::new(Errno::ENOEXEC, "Failed to get the name of a symbol"))?;
|
||||
if sym_str == "_start" {
|
||||
return Ok(sym_entry.value() as usize);
|
||||
}
|
||||
}
|
||||
|
||||
Err((Errno::ENOEXEC, "Failed to get the _start symbol").into())
|
||||
let elf_header = &elf_file.header.pt2;
|
||||
Ok(elf_header.entry_point() as usize)
|
||||
}
|
||||
|
||||
pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [Entry64], Error> {
|
||||
|
@ -58,7 +58,6 @@ pub fn do_init(
|
||||
let envp_cloned = clone_cstrings_on_stack(&stack_buf, envp)?;
|
||||
let argv_cloned = clone_cstrings_on_stack(&stack_buf, argv)?;
|
||||
dump_auxtbl_on_stack(&stack_buf, auxtbl)?;
|
||||
dump_auxtbl_on_stack(&stack_buf, auxtbl)?;
|
||||
dump_cstrptrs_on_stack(&stack_buf, &envp_cloned);
|
||||
dump_cstrptrs_on_stack(&stack_buf, &argv_cloned);
|
||||
stack_buf.put(argv.len() as u64);
|
||||
|
@ -25,10 +25,10 @@ pub fn do_init(elf_file: &ElfFile, elf_buf: &[u8]) -> Result<ProcessVM, Error> {
|
||||
|
||||
// Calculate the "real" addresses
|
||||
let process_base_addr = process_vm.get_base_addr();
|
||||
let code_start = process_base_addr + code_start;
|
||||
let code_end = process_base_addr + code_end;
|
||||
let data_start = process_base_addr + data_start;
|
||||
let data_end = process_base_addr + data_end;
|
||||
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);
|
||||
|
||||
@ -54,8 +54,8 @@ fn reloc_symbols(process_base_addr: usize, elf_file: &ElfFile) -> Result<(), Err
|
||||
rela_entry.get_addend());
|
||||
*/
|
||||
|
||||
/* reloc type == R_X86_64_RELATIVE */
|
||||
match rela_entry.get_type() {
|
||||
// reloc type == R_X86_64_RELATIVE
|
||||
8 if rela_entry.get_symbol_table_index() == 0 => {
|
||||
let rela_addr = process_base_addr + rela_entry.get_offset() as usize;
|
||||
let rela_val = process_base_addr + rela_entry.get_addend() as usize;
|
||||
|
@ -54,16 +54,18 @@ pub fn do_spawn<P: AsRef<Path>>(
|
||||
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 base_addr = vm.get_base_addr();
|
||||
let program_entry = {
|
||||
let program_entry = base_addr + elf_helper::get_start_address(&elf_file)?;
|
||||
if !vm.get_code_vma().contains_obj(program_entry, 16) {
|
||||
return Err(Error::new(Errno::EINVAL, "Invalid program entry"));
|
||||
}
|
||||
program_entry
|
||||
};
|
||||
let auxtbl = init_auxtbl(base_addr, program_entry, &elf_file)?;
|
||||
let task = {
|
||||
let program_entry = {
|
||||
let program_entry = vm.get_base_addr() + elf_helper::get_start_address(&elf_file)?;
|
||||
if !vm.get_code_vma().contains_obj(program_entry, 16) {
|
||||
return Err(Error::new(Errno::EINVAL, "Invalid program entry"));
|
||||
}
|
||||
program_entry
|
||||
};
|
||||
let stack_top = vm.get_stack_top();
|
||||
init_task(program_entry, stack_top, argv, envp)?
|
||||
init_task(program_entry, stack_top, argv, envp, &auxtbl)?
|
||||
};
|
||||
let vm_ref = Arc::new(SgxMutex::new(vm));
|
||||
let files_ref = {
|
||||
@ -119,8 +121,9 @@ fn init_task(
|
||||
stack_top: usize,
|
||||
argv: &[CString],
|
||||
envp: &[CString],
|
||||
auxtbl: &AuxTable,
|
||||
) -> Result<Task, Error> {
|
||||
let user_stack = init_stack(stack_top, argv, envp)?;
|
||||
let user_stack = init_stack::do_init(stack_top, 4096, argv, envp, auxtbl)?;
|
||||
Ok(Task {
|
||||
user_stack_addr: user_stack,
|
||||
user_entry_addr: user_entry,
|
||||
@ -128,7 +131,7 @@ fn init_task(
|
||||
})
|
||||
}
|
||||
|
||||
fn init_stack(stack_top: usize, argv: &[CString], envp: &[CString]) -> Result<usize, Error> {
|
||||
fn init_auxtbl(base_addr: usize, program_entry: usize, 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)?;
|
||||
@ -137,7 +140,16 @@ fn init_stack(stack_top: usize, argv: &[CString], envp: &[CString]) -> Result<us
|
||||
auxtbl.set_val(AuxKey::AT_EGID, 0)?;
|
||||
auxtbl.set_val(AuxKey::AT_SECURE, 0)?;
|
||||
|
||||
init_stack::do_init(stack_top, 4096, argv, envp, &auxtbl)
|
||||
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_val(AuxKey::AT_ENTRY, program_entry as u64)?;
|
||||
// TODO: init AT_EXECFN
|
||||
// auxtbl.set_val(AuxKey::AT_EXECFN, "program_name")?;
|
||||
|
||||
Ok(auxtbl)
|
||||
}
|
||||
|
||||
fn parent_adopts_new_child(parent_ref: &ProcessRef, child_ref: &ProcessRef) {
|
||||
|
@ -122,6 +122,8 @@ pub extern "C" fn dispatch_syscall(
|
||||
|
||||
SYS_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
|
||||
|
||||
SYS_ARCH_PRCTL => do_arch_prctl(arg0 as u32, arg1 as *mut usize),
|
||||
|
||||
_ => do_unknown(num),
|
||||
};
|
||||
debug!("syscall return: {:?}", ret);
|
||||
@ -653,3 +655,10 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> {
|
||||
fs::do_unlink(&path)?;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn do_arch_prctl(code: u32, addr: *mut usize) -> Result<isize, Error> {
|
||||
let code = process::ArchPrctlCode::from_u32(code)?;
|
||||
check_mut_ptr(addr)?;
|
||||
process::do_arch_prctl(code, addr).map(|_| 0)
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,10 @@ __occlum_syscall:
|
||||
bndcl %rsp, %bnd0
|
||||
bndcu %rsp, %bnd0
|
||||
|
||||
// Save the user stack
|
||||
// Save the callee-saved registers
|
||||
pushq %rbp
|
||||
pushq %r12
|
||||
// Save the user stack
|
||||
movq %rsp, %rbp
|
||||
|
||||
// Get current task
|
||||
@ -39,11 +41,13 @@ __occlum_syscall:
|
||||
// addq 0x08, %rsp
|
||||
|
||||
// Use user fsbase
|
||||
movq TASK_KERNEL_FSBASE_ADDR(%r12), %r11
|
||||
movq TASK_USER_FSBASE_ADDR(%r12), %r11
|
||||
wrfsbase %r11
|
||||
|
||||
// Restore the user stack
|
||||
// Switch to the user stack
|
||||
movq %rbp, %rsp
|
||||
// Restore callee-saved registers
|
||||
popq %r12
|
||||
popq %rbp
|
||||
|
||||
// Check return target is a valid instruction (i.e., a cfi_label)
|
||||
|
@ -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 file getpid spawn pipe time truncate readdir mkdir link clone
|
||||
TESTS := empty argv hello_world malloc file getpid spawn pipe time truncate readdir mkdir link clone tls
|
||||
# Benchmarks: need to be compiled and run by bench-% target
|
||||
BENCHES := spawn_and_exit_latency pipe_throughput
|
||||
|
||||
|
5
test/tls/Makefile
Normal file
5
test/tls/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
include ../test_common.mk
|
||||
|
||||
EXTRA_C_FLAGS :=
|
||||
EXTRA_LINK_FLAGS :=
|
||||
BIN_ARGS :=
|
11
test/tls/main.c
Normal file
11
test/tls/main.c
Normal file
@ -0,0 +1,11 @@
|
||||
volatile int g_int = 0;
|
||||
static void use_int(int* a) {
|
||||
g_int += *a;
|
||||
}
|
||||
|
||||
__thread int tls_g_int = 0;
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
use_int(&tls_g_int);
|
||||
return g_int;
|
||||
}
|
Loading…
Reference in New Issue
Block a user