Skip to content

Commit

Permalink
use ELF-TLS on SGX
Browse files Browse the repository at this point in the history
  • Loading branch information
joboet committed Dec 12, 2022
1 parent f34356e commit 27437f9
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 328 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;

use super::{cvs, Cc, LinkerFlavor, Lld, Target, TargetOptions};
use super::{cvs, Cc, LinkerFlavor, Lld, Target, TargetOptions, TlsModel};

pub fn target() -> Target {
let pre_link_args = TargetOptions::link_args(
Expand Down Expand Up @@ -53,6 +53,9 @@ pub fn target() -> Target {
"EH_FRM_LEN",
"TEXT_BASE",
"TEXT_SIZE",
"TLS_INIT_BASE",
"TLS_INIT_SIZE",
"TLS_OFFSET",
];
let opts = TargetOptions {
os: "unknown".into(),
Expand All @@ -69,6 +72,8 @@ pub fn target() -> Target {
pre_link_args,
override_export_symbols: Some(EXPORT_SYMBOLS.iter().cloned().map(Cow::from).collect()),
relax_elf_relocations: true,
has_thread_local: true,
tls_model: TlsModel::LocalExec,
..Default::default()
};
Target {
Expand Down
111 changes: 53 additions & 58 deletions library/std/src/sys/sgx/abi/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ IMAGE_BASE:
globvar EH_FRM_OFFSET 8
/* The size in bytes of enclacve .eh_frame section */
globvar EH_FRM_LEN 8
/* The base address (relative to enclave start) of the TLS initialization image */
globvar TLS_INIT_BASE 8
/* The size in bytes of the TLS initialization image */
globvar TLS_INIT_SIZE 8
/* The TLS module offset of this enclave (see the ELF-TLS specification for more details) */
globvar TLS_OFFSET 8

.org .Lxsave_clear+512
.Lxsave_header:
Expand All @@ -80,32 +86,32 @@ IMAGE_BASE:
.byte 0

/* TCS local storage section */
.equ tcsls_tos, 0x00 /* initialized by loader to *offset* from image base to TOS */
.equ tcsls_flags, 0x08 /* initialized by loader */
.equ tcsls_tp, 0x00 /* initialized by loader to *offset* from image base to this field */
.equ tcsls_tos, 0x08 /* initialized by loader to *offset* from image base to TOS */
.equ tcsls_flags, 0x10 /* initialized by loader */
.equ tcsls_flag_secondary, 0 /* initialized by loader; 0 = standard TCS, 1 = secondary TCS */
.equ tcsls_flag_init_once, 1 /* initialized by loader to 0 */
/* 14 unused bits */
.equ tcsls_user_fcw, 0x0a
.equ tcsls_user_mxcsr, 0x0c
.equ tcsls_last_rsp, 0x10 /* initialized by loader to 0 */
.equ tcsls_panic_last_rsp, 0x18 /* initialized by loader to 0 */
.equ tcsls_debug_panic_buf_ptr, 0x20 /* initialized by loader to 0 */
.equ tcsls_user_rsp, 0x28
.equ tcsls_user_retip, 0x30
.equ tcsls_user_rbp, 0x38
.equ tcsls_user_r12, 0x40
.equ tcsls_user_r13, 0x48
.equ tcsls_user_r14, 0x50
.equ tcsls_user_r15, 0x58
.equ tcsls_tls_ptr, 0x60
.equ tcsls_user_fcw, 0x12
.equ tcsls_user_mxcsr, 0x14
.equ tcsls_last_rsp, 0x18 /* initialized by loader to 0 */
.equ tcsls_panic_last_rsp, 0x20 /* initialized by loader to 0 */
.equ tcsls_debug_panic_buf_ptr, 0x28 /* initialized by loader to 0 */
.equ tcsls_user_rsp, 0x30
.equ tcsls_user_retip, 0x38
.equ tcsls_user_rbp, 0x40
.equ tcsls_user_r12, 0x48
.equ tcsls_user_r13, 0x50
.equ tcsls_user_r14, 0x58
.equ tcsls_user_r15, 0x60
.equ tcsls_tcs_addr, 0x68

.macro load_tcsls_flag_secondary_bool reg:req comments:vararg
.ifne tcsls_flag_secondary /* to convert to a bool, must be the first bit */
.abort
.endif
mov $(1<<tcsls_flag_secondary),%e\reg
and %gs:tcsls_flags,%\reg
and %fs:tcsls_flags,%\reg
.endm

/* We place the ELF entry point in a separate section so it can be removed by
Expand Down Expand Up @@ -157,21 +163,21 @@ elf_entry:
.type sgx_entry,function
sgx_entry:
/* save user registers */
mov %rcx,%gs:tcsls_user_retip
mov %rsp,%gs:tcsls_user_rsp
mov %rbp,%gs:tcsls_user_rbp
mov %r12,%gs:tcsls_user_r12
mov %r13,%gs:tcsls_user_r13
mov %r14,%gs:tcsls_user_r14
mov %r15,%gs:tcsls_user_r15
mov %rbx,%gs:tcsls_tcs_addr
stmxcsr %gs:tcsls_user_mxcsr
fnstcw %gs:tcsls_user_fcw
mov %rcx,%fs:tcsls_user_retip
mov %rsp,%fs:tcsls_user_rsp
mov %rbp,%fs:tcsls_user_rbp
mov %r12,%fs:tcsls_user_r12
mov %r13,%fs:tcsls_user_r13
mov %r14,%fs:tcsls_user_r14
mov %r15,%fs:tcsls_user_r15
mov %rbx,%fs:tcsls_tcs_addr
stmxcsr %fs:tcsls_user_mxcsr
fnstcw %fs:tcsls_user_fcw

/* check for debug buffer pointer */
testb $0xff,DEBUG(%rip)
jz .Lskip_debug_init
mov %r10,%gs:tcsls_debug_panic_buf_ptr
mov %r10,%fs:tcsls_debug_panic_buf_ptr
.Lskip_debug_init:
/* reset cpu state */
mov %rdx, %r10
Expand All @@ -181,20 +187,23 @@ sgx_entry:
mov %r10, %rdx

/* check if returning from usercall */
mov %gs:tcsls_last_rsp,%r11
mov %fs:tcsls_last_rsp,%r11
test %r11,%r11
jnz .Lusercall_ret
/* setup stack */
mov %gs:tcsls_tos,%rsp /* initially, RSP is not set to the correct value */
mov %fs:tcsls_tos,%rsp /* initially, RSP is not set to the correct value */
/* here. This is fixed below under "adjust stack". */
/* check for thread init */
bts $tcsls_flag_init_once,%gs:tcsls_flags
bts $tcsls_flag_init_once,%fs:tcsls_flags
jc .Lskip_init
/* adjust stack */
lea IMAGE_BASE(%rip),%rax
add %rax,%rsp
mov %rsp,%gs:tcsls_tos
mov %rsp,%fs:tcsls_tos
entry_sanitize_final
/* adjust thread pointer */
lea IMAGE_BASE(%rip),%rax
add %rax,%fs:0
/* call tcs_init */
/* store caller-saved registers in callee-saved registers */
mov %rdi,%rbx
Expand Down Expand Up @@ -246,15 +255,15 @@ sgx_entry:
pushq $0
popfq
/* restore user registers */
mov %gs:tcsls_user_r12,%r12
mov %gs:tcsls_user_r13,%r13
mov %gs:tcsls_user_r14,%r14
mov %gs:tcsls_user_r15,%r15
mov %gs:tcsls_user_retip,%rbx
mov %gs:tcsls_user_rsp,%rsp
mov %gs:tcsls_user_rbp,%rbp
fldcw %gs:tcsls_user_fcw
ldmxcsr %gs:tcsls_user_mxcsr
mov %fs:tcsls_user_r12,%r12
mov %fs:tcsls_user_r13,%r13
mov %fs:tcsls_user_r14,%r14
mov %fs:tcsls_user_r15,%r15
mov %fs:tcsls_user_retip,%rbx
mov %fs:tcsls_user_rsp,%rsp
mov %fs:tcsls_user_rbp,%rbp
fldcw %fs:tcsls_user_fcw
ldmxcsr %fs:tcsls_user_mxcsr
/* exit enclave */
mov $0x4,%eax /* EEXIT */
enclu
Expand Down Expand Up @@ -288,7 +297,7 @@ usercall:
sub $8, %rsp
fstcw 4(%rsp)
stmxcsr (%rsp)
movq %rsp,%gs:tcsls_last_rsp
movq %rsp,%fs:tcsls_last_rsp
.Lusercall_noreturn:
/* clear general purpose register state */
/* RAX overwritten by ENCLU */
Expand All @@ -308,7 +317,7 @@ usercall:
/* exit */
jmp .Lsgx_exit
.Lusercall_ret:
movq $0,%gs:tcsls_last_rsp
movq $0,%fs:tcsls_last_rsp
/* restore callee-saved state, cf. "save" above */
mov %r11,%rsp
ldmxcsr (%rsp)
Expand Down Expand Up @@ -344,29 +353,15 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64

.global get_tcs_addr
get_tcs_addr:
mov %gs:tcsls_tcs_addr,%rax
pop %r11
lfence
jmp *%r11

.global get_tls_ptr
get_tls_ptr:
mov %gs:tcsls_tls_ptr,%rax
pop %r11
lfence
jmp *%r11

.global set_tls_ptr
set_tls_ptr:
mov %rdi,%gs:tcsls_tls_ptr
mov %fs:tcsls_tcs_addr,%rax
pop %r11
lfence
jmp *%r11

.global take_debug_panic_buf_ptr
take_debug_panic_buf_ptr:
xor %rax,%rax
xchg %gs:tcsls_debug_panic_buf_ptr,%rax
xchg %fs:tcsls_debug_panic_buf_ptr,%rax
pop %r11
lfence
jmp *%r11
5 changes: 2 additions & 3 deletions library/std/src/sys/sgx/abi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,11 @@ unsafe extern "C" fn tcs_init(secondary: bool) {
#[no_mangle]
extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> EntryReturn {
// FIXME: how to support TLS in library mode?
let tls = Box::new(tls::Tls::new());
let tls_guard = unsafe { tls.activate() };
let tls = unsafe { tls::Tls::init() };

if secondary {
let join_notifier = super::thread::Thread::entry();
drop(tls_guard);
drop(tls);
drop(join_notifier);

EntryReturn(0, 0)
Expand Down
49 changes: 49 additions & 0 deletions library/std/src/sys/sgx/abi/tls.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use super::mem;
use crate::arch::asm;

extern "C" {
static TLS_INIT_BASE: u64;
static TLS_INIT_SIZE: usize;
static TLS_OFFSET: usize;
}

pub struct Tls {}

impl Tls {
/// Initialize the thread local storage to a fresh state.
///
/// # Safety
/// * may only be called once per thread
/// * must be dropped before thread exit
/// * must be called before any `#[thread_local]` variable is used
pub unsafe fn init() -> Tls {
// The thread pointer points to the end of the TLS section. It is stored
// both in the `fs` segment base address (initialized by the loader) and
// at the address it itself points to (initialized during TCS
// initialization).
let tp: *mut u8;
unsafe {
asm!("mov fs:0, {}", out(reg) tp, options(preserves_flags, readonly));
}

// Initialize the TLS data.
unsafe {
let init_base = mem::rel_ptr_mut(TLS_INIT_BASE);
// The first `TLS_INIT_SIZE` bytes of the TLS section hold non-trivial
// data that needs to be copied from the initialization image.
tp.sub(TLS_OFFSET).copy_from_nonoverlapping(init_base, TLS_INIT_SIZE);
// All remaining bytes are initialized to zero.
tp.sub(TLS_OFFSET).add(TLS_INIT_SIZE).write_bytes(0, TLS_OFFSET - TLS_INIT_SIZE);
}

Tls {}
}
}

impl Drop for Tls {
fn drop(&mut self) {
unsafe {
crate::sys::thread_local_dtor::run_dtors();
}
}
}
Loading

0 comments on commit 27437f9

Please sign in to comment.