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::wait::{WaitQueue, Waiter};
|
||||||
pub use self::thread::{do_clone, CloneFlags, ThreadGroup};
|
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::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)]
|
#[allow(non_camel_case_types)]
|
||||||
pub type pid_t = u32;
|
pub type pid_t = u32;
|
||||||
@ -65,6 +66,7 @@ mod task;
|
|||||||
mod wait;
|
mod wait;
|
||||||
mod thread;
|
mod thread;
|
||||||
mod futex;
|
mod futex;
|
||||||
|
mod arch_prctl;
|
||||||
|
|
||||||
use self::task::Task;
|
use self::task::Task;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -6,6 +6,22 @@ use xmas_elf::symbol_table::Entry;
|
|||||||
use xmas_elf::symbol_table::{DynEntry64, Entry64};
|
use xmas_elf::symbol_table::{DynEntry64, Entry64};
|
||||||
use xmas_elf::{program, sections, ElfFile, P64};
|
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> {
|
pub fn print_program_headers(elf_file: &ElfFile) -> Result<(), Error> {
|
||||||
println!("Program headers:");
|
println!("Program headers:");
|
||||||
let ph_iter = elf_file.program_iter();
|
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> {
|
pub fn get_start_address<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<usize, Error> {
|
||||||
let sym_entries = get_sym_entries(elf_file)?;
|
let elf_header = &elf_file.header.pt2;
|
||||||
|
Ok(elf_header.entry_point() as usize)
|
||||||
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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sym_entries<'b, 'a: 'b>(elf_file: &'b ElfFile<'a>) -> Result<&'a [Entry64], Error> {
|
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 envp_cloned = clone_cstrings_on_stack(&stack_buf, envp)?;
|
||||||
let argv_cloned = clone_cstrings_on_stack(&stack_buf, argv)?;
|
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_auxtbl_on_stack(&stack_buf, auxtbl)?;
|
|
||||||
dump_cstrptrs_on_stack(&stack_buf, &envp_cloned);
|
dump_cstrptrs_on_stack(&stack_buf, &envp_cloned);
|
||||||
dump_cstrptrs_on_stack(&stack_buf, &argv_cloned);
|
dump_cstrptrs_on_stack(&stack_buf, &argv_cloned);
|
||||||
stack_buf.put(argv.len() as u64);
|
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
|
// Calculate the "real" addresses
|
||||||
let process_base_addr = process_vm.get_base_addr();
|
let process_base_addr = process_vm.get_base_addr();
|
||||||
let code_start = process_base_addr + code_start;
|
let code_start = code_start + process_base_addr;
|
||||||
let code_end = process_base_addr + code_end;
|
let code_end = code_end + process_base_addr;
|
||||||
let data_start = process_base_addr + data_start;
|
let data_start = data_start + process_base_addr;
|
||||||
let data_end = process_base_addr + data_end;
|
let data_end = data_end + process_base_addr;
|
||||||
code_seg.set_runtime_info(process_base_addr, code_start, code_end);
|
code_seg.set_runtime_info(process_base_addr, code_start, code_end);
|
||||||
data_seg.set_runtime_info(process_base_addr, data_start, data_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());
|
rela_entry.get_addend());
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* reloc type == R_X86_64_RELATIVE */
|
|
||||||
match rela_entry.get_type() {
|
match rela_entry.get_type() {
|
||||||
|
// reloc type == R_X86_64_RELATIVE
|
||||||
8 if rela_entry.get_symbol_table_index() == 0 => {
|
8 if rela_entry.get_symbol_table_index() == 0 => {
|
||||||
let rela_addr = process_base_addr + rela_entry.get_offset() as usize;
|
let rela_addr = process_base_addr + rela_entry.get_offset() as usize;
|
||||||
let rela_val = process_base_addr + rela_entry.get_addend() 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 (new_pid, new_process_ref) = {
|
||||||
let cwd = parent_ref.lock().unwrap().get_cwd().to_owned();
|
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[..])?;
|
||||||
|
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 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();
|
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 vm_ref = Arc::new(SgxMutex::new(vm));
|
||||||
let files_ref = {
|
let files_ref = {
|
||||||
@ -119,8 +121,9 @@ fn init_task(
|
|||||||
stack_top: usize,
|
stack_top: usize,
|
||||||
argv: &[CString],
|
argv: &[CString],
|
||||||
envp: &[CString],
|
envp: &[CString],
|
||||||
|
auxtbl: &AuxTable,
|
||||||
) -> Result<Task, Error> {
|
) -> 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 {
|
Ok(Task {
|
||||||
user_stack_addr: user_stack,
|
user_stack_addr: user_stack,
|
||||||
user_entry_addr: user_entry,
|
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();
|
let mut auxtbl = AuxTable::new();
|
||||||
auxtbl.set_val(AuxKey::AT_PAGESZ, 4096)?;
|
auxtbl.set_val(AuxKey::AT_PAGESZ, 4096)?;
|
||||||
auxtbl.set_val(AuxKey::AT_UID, 0)?;
|
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_EGID, 0)?;
|
||||||
auxtbl.set_val(AuxKey::AT_SECURE, 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) {
|
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_GETTIMEOFDAY => do_gettimeofday(arg0 as *mut timeval_t),
|
||||||
|
|
||||||
|
SYS_ARCH_PRCTL => do_arch_prctl(arg0 as u32, arg1 as *mut usize),
|
||||||
|
|
||||||
_ => do_unknown(num),
|
_ => do_unknown(num),
|
||||||
};
|
};
|
||||||
debug!("syscall return: {:?}", ret);
|
debug!("syscall return: {:?}", ret);
|
||||||
@ -653,3 +655,10 @@ fn do_unlink(path: *const i8) -> Result<isize, Error> {
|
|||||||
fs::do_unlink(&path)?;
|
fs::do_unlink(&path)?;
|
||||||
Ok(0)
|
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
|
bndcl %rsp, %bnd0
|
||||||
bndcu %rsp, %bnd0
|
bndcu %rsp, %bnd0
|
||||||
|
|
||||||
// Save the user stack
|
// Save the callee-saved registers
|
||||||
pushq %rbp
|
pushq %rbp
|
||||||
|
pushq %r12
|
||||||
|
// Save the user stack
|
||||||
movq %rsp, %rbp
|
movq %rsp, %rbp
|
||||||
|
|
||||||
// Get current task
|
// Get current task
|
||||||
@ -39,11 +41,13 @@ __occlum_syscall:
|
|||||||
// addq 0x08, %rsp
|
// addq 0x08, %rsp
|
||||||
|
|
||||||
// Use user fsbase
|
// Use user fsbase
|
||||||
movq TASK_KERNEL_FSBASE_ADDR(%r12), %r11
|
movq TASK_USER_FSBASE_ADDR(%r12), %r11
|
||||||
wrfsbase %r11
|
wrfsbase %r11
|
||||||
|
|
||||||
// Restore the user stack
|
// Switch to the user stack
|
||||||
movq %rbp, %rsp
|
movq %rbp, %rsp
|
||||||
|
// Restore callee-saved registers
|
||||||
|
popq %r12
|
||||||
popq %rbp
|
popq %rbp
|
||||||
|
|
||||||
// Check return target is a valid instruction (i.e., a cfi_label)
|
// 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
|
# Dependencies: need to be compiled but not to run by any Makefile target
|
||||||
TEST_DEPS := dev_null
|
TEST_DEPS := dev_null
|
||||||
# Tests: need to be compiled and run by test-% target
|
# 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
|
# Benchmarks: need to be compiled and run by bench-% target
|
||||||
BENCHES := spawn_and_exit_latency pipe_throughput
|
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