From 30aef27c76930730d38e2de14d9163c67736101d Mon Sep 17 00:00:00 2001 From: Jeremy Soller <jeremy@system76.com> Date: Sun, 14 Apr 2019 19:08:58 -0600 Subject: [PATCH] Correctly set up TLS on Redox and other fixes for pthread_clone --- src/header/dl-tls/mod.rs | 1 + src/ld_so/linker.rs | 4 +- src/ld_so/tcb.rs | 25 ++++++----- src/platform/linux/mod.rs | 11 ++++- src/platform/pte.rs | 94 ++++++++++++++++++++++++++------------- src/platform/redox/mod.rs | 11 ++++- 6 files changed, 97 insertions(+), 49 deletions(-) diff --git a/src/header/dl-tls/mod.rs b/src/header/dl-tls/mod.rs index f1a44b6f8..b61cc4ced 100644 --- a/src/header/dl-tls/mod.rs +++ b/src/header/dl-tls/mod.rs @@ -1,5 +1,6 @@ //! dl-tls implementation for Redox +use ld_so::tcb::Tcb; use platform::types::*; #[repr(C)] diff --git a/src/ld_so/linker.rs b/src/ld_so/linker.rs index e4e2c5482..980ff00ef 100644 --- a/src/ld_so/linker.rs +++ b/src/ld_so/linker.rs @@ -199,7 +199,7 @@ impl Linker { if let Some(name_res) = elf.dynstrtab.get(sym.st_name) { let name = name_res?; let value = mmap.as_ptr() as usize + sym.st_value as usize; - //println!(" global {}: {:x?} = {:#x}", name, sym, value); + // println!(" global {}: {:x?} = {:#x}", name, sym, value); globals.insert(name, value); } } @@ -356,7 +356,7 @@ impl Linker { }; let set_u64 = |value| { - //println!(" set_u64 {:#x}", value); + // println!(" set_u64 {:#x}", value); unsafe { *(ptr as *mut u64) = value; } }; diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index d39253bd8..643e51223 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -3,7 +3,7 @@ use core::{mem, ptr, slice}; use core::ops::Range; use goblin::error::{Error, Result}; -use header::sys_mman; +use header::{sys_mman, unistd}; use super::PAGE_SIZE; @@ -36,17 +36,17 @@ impl Master { #[repr(C)] pub struct Tcb { /// Pointer to the end of static TLS. Must be the first member - tls_end: *mut u8, + pub tls_end: *mut u8, /// Size of the memory allocated for the static TLS in bytes (multiple of PAGE_SIZE) - tls_len: usize, + pub tls_len: usize, /// Pointer to this structure - tcb_ptr: *mut Tcb, + pub tcb_ptr: *mut Tcb, /// Size of the memory allocated for this structure in bytes (should be PAGE_SIZE) - tcb_len: usize, + pub tcb_len: usize, /// Pointer to a list of initial TLS data - masters_ptr: *mut Master, + pub masters_ptr: *mut Master, /// Size of the masters list in bytes (multiple of mem::size_of::<Master>()) - masters_len: usize, + pub masters_len: usize, } impl Tcb { @@ -55,7 +55,7 @@ impl Tcb { let (tls, tcb_page) = Self::os_new(size)?; let tcb_ptr = tcb_page.as_mut_ptr() as *mut Self; - ptr::write(tcb_ptr, Tcb { + ptr::write(tcb_ptr, Self { tls_end: tls.as_mut_ptr().add(tls.len()), tls_len: tls.len(), tcb_ptr: tcb_ptr, @@ -171,11 +171,14 @@ impl Tcb { /// OS specific code to create a new TLS and TCB - Redox #[cfg(target_os = "redox")] unsafe fn os_new(size: usize) -> Result<(&'static mut [u8], &'static mut [u8])> { + //TODO: better method of finding fs offset + let pid = unistd::getpid(); + let tcb_addr = 0xB000_0000 + pid as usize * PAGE_SIZE; let tls = Self::map(size)?; Ok(( tls, //TODO: Consider allocating TCB as part of TLS - slice::from_raw_parts_mut(0xB000_0000 as *mut u8, PAGE_SIZE) + slice::from_raw_parts_mut(tcb_addr as *mut u8, PAGE_SIZE) )) } @@ -185,10 +188,10 @@ impl Tcb { unsafe fn arch_read(offset: usize) -> usize { let value; asm!(" - mov rax, [fs:rdi] + mov rax, fs:[rdi] " : "={rax}"(value) - : "{rax}"(offset) + : "{rdi}"(offset) : : "intel" ); diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index ed0cb7065..c3018d25a 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -343,9 +343,16 @@ impl Pal for Sys { test rax, rax jnz .parent - # Call entry point - pop rdi + # Load registers pop rax + pop rdi + pop rsi + pop rdx + pop rcx + pop r8 + pop r9 + + # Call entry point call rax # Exit diff --git a/src/platform/pte.rs b/src/platform/pte.rs index 37d14a33d..2a4bf5e97 100644 --- a/src/platform/pte.rs +++ b/src/platform/pte.rs @@ -7,6 +7,7 @@ use core::{intrinsics, ptr}; use header::sys_mman; use header::time::timespec; +use ld_so::tcb::{Tcb, Master}; use mutex::{FUTEX_WAIT, FUTEX_WAKE}; use platform::types::{c_int, c_uint, c_void, pid_t, size_t}; use platform::{Pal, Sys}; @@ -58,6 +59,27 @@ pub unsafe extern "C" fn pte_osInit() -> pte_osResult { PTE_OS_OK } +/// A shim to wrap thread entry points in logic to set up TLS, for example +unsafe extern "C" fn pte_osThreadShim( + entryPoint: pte_osThreadEntryPoint, + argv: *mut c_void, + mutex: pte_osMutexHandle, + tls_size: usize, + tls_masters_ptr: *mut Master, + tls_masters_len: usize +) { + let mut tcb = Tcb::new(tls_size).unwrap(); + tcb.masters_ptr = tls_masters_ptr; + tcb.masters_len = tls_masters_len; + tcb.copy_masters().unwrap(); + tcb.activate(); + + // Wait until pte_osThreadStart + pte_osMutexLock(mutex); + entryPoint(argv); + pte_osThreadExit(); +} + #[no_mangle] pub unsafe extern "C" fn pte_osThreadCreate( entryPoint: pte_osThreadEntryPoint, @@ -66,6 +88,9 @@ pub unsafe extern "C" fn pte_osThreadCreate( argv: *mut c_void, ppte_osThreadHandle: *mut pte_osThreadHandle, ) -> pte_osResult { + // Create a locked mutex, unlocked by pte_osThreadStart + let mutex: pte_osMutexHandle = Box::into_raw(Box::new(2)); + let stack_size = if stackSize == 0 { 1024 * 1024 } else { @@ -85,44 +110,49 @@ pub unsafe extern "C" fn pte_osThreadCreate( let stack_end = stack_base.add(stack_size); let mut stack = stack_end as *mut usize; { - stack = stack.offset(-1); - *stack = entryPoint as usize; + let mut push = |value: usize| { + stack = stack.offset(-1); + *stack = value; + }; + + if let Some(tcb) = Tcb::current() { + push(tcb.masters_len); + push(tcb.masters_ptr as usize); + push(tcb.tls_len); + } else { + push(0); + push(0); + push(0); + } - stack = stack.offset(-1); - *stack = argv as usize; - } + push(mutex as usize); - // Create a locked mutex, unlocked by pte_osThreadStart - let mutex = Box::into_raw(Box::new(2)); - { - let id = Sys::pte_clone(stack); - if id < 0 { - return PTE_OS_GENERAL_FAILURE; - } + push(argv as usize); + push(entryPoint as usize); - if id == 0 { - // Wait until pte_osThreadStart - pte_osMutexLock(mutex); - entryPoint(argv); - pte_osThreadExit(); - } else { - pte_osMutexLock(&mut pid_mutexes_lock); - if pid_mutexes.is_none() { - pid_mutexes = Some(BTreeMap::new()); - } - pid_mutexes.as_mut().unwrap().insert(id, mutex); - pte_osMutexUnlock(&mut pid_mutexes_lock); + push(pte_osThreadShim as usize); + } - pte_osMutexLock(&mut pid_stacks_lock); - if pid_stacks.is_none() { - pid_stacks = Some(BTreeMap::new()); - } - pid_stacks.as_mut().unwrap().insert(id, (stack_base, stack_size)); - pte_osMutexUnlock(&mut pid_stacks_lock); + let id = Sys::pte_clone(stack); + if id < 0 { + return PTE_OS_GENERAL_FAILURE; + } - *ppte_osThreadHandle = id; - } + pte_osMutexLock(&mut pid_mutexes_lock); + if pid_mutexes.is_none() { + pid_mutexes = Some(BTreeMap::new()); } + pid_mutexes.as_mut().unwrap().insert(id, mutex); + pte_osMutexUnlock(&mut pid_mutexes_lock); + + pte_osMutexLock(&mut pid_stacks_lock); + if pid_stacks.is_none() { + pid_stacks = Some(BTreeMap::new()); + } + pid_stacks.as_mut().unwrap().insert(id, (stack_base, stack_size)); + pte_osMutexUnlock(&mut pid_stacks_lock); + + *ppte_osThreadHandle = id; PTE_OS_OK } diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 09e1d6c3a..a2dfa9667 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -832,9 +832,16 @@ impl Pal for Sys { test rax, rax jnz .parent - # Call entry point - pop rdi + # Load registers pop rax + pop rdi + pop rsi + pop rdx + pop rcx + pop r8 + pop r9 + + # Call entry point call rax # Exit -- GitLab