]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/mod.rs
85ec8be4aae69bf157b89a7e6c86209279a20dc6
[rust.git] / src / libstd / sys / sgx / abi / mod.rs
1 #![cfg_attr(test, allow(unused))] // RT initialization logic is not compiled for test
2
3 use core::sync::atomic::{AtomicUsize, Ordering};
4 use crate::io::Write;
5
6 // runtime features
7 mod reloc;
8 pub(super) mod panic;
9
10 // library features
11 pub mod mem;
12 pub mod thread;
13 pub mod tls;
14 #[macro_use]
15 pub mod usercalls;
16
17 #[cfg(not(test))]
18 global_asm!(include_str!("entry.S"));
19
20 #[cfg(not(test))]
21 #[no_mangle]
22 unsafe extern "C" fn tcs_init(secondary: bool) {
23     // Be very careful when changing this code: it runs before the binary has been
24     // relocated. Any indirect accesses to symbols will likely fail.
25     const UNINIT: usize = 0;
26     const BUSY: usize = 1;
27     const DONE: usize = 2;
28     // Three-state spin-lock
29     static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);
30
31     if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
32         panic::panic_msg("Entered secondary TCS before main TCS!")
33     }
34
35     // Try to atomically swap UNINIT with BUSY. The returned state can be:
36     match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
37         // This thread just obtained the lock and other threads will observe BUSY
38         UNINIT => {
39             reloc::relocate_elf_rela();
40             RELOC_STATE.store(DONE, Ordering::Release);
41         },
42         // We need to wait until the initialization is done.
43         BUSY => while RELOC_STATE.load(Ordering::Acquire) == BUSY  {
44             core::arch::x86_64::_mm_pause()
45         },
46         // Initialization is done.
47         DONE => {},
48         _ => unreachable!()
49     }
50 }
51
52 // FIXME: this item should only exist if this is linked into an executable
53 // (main function exists). If this is a library, the crate author should be
54 // able to specify this
55 #[cfg(not(test))]
56 #[no_mangle]
57 extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
58     // FIXME: how to support TLS in library mode?
59     let tls = Box::new(tls::Tls::new());
60     let _tls_guard = unsafe { tls.activate() };
61
62     if secondary {
63         super::thread::Thread::entry();
64
65         (0, 0)
66     } else {
67         extern "C" {
68             fn main(argc: isize, argv: *const *const u8) -> isize;
69         }
70
71         // check entry is being called according to ABI
72         assert_eq!(p3, 0);
73         assert_eq!(p4, 0);
74         assert_eq!(p5, 0);
75
76         unsafe {
77             // The actual types of these arguments are `p1: *const Arg, p2:
78             // usize`. We can't currently customize the argument list of Rust's
79             // main function, so we pass these in as the standard pointer-sized
80             // values in `argc` and `argv`.
81             let ret = main(p2 as _, p1 as _);
82             exit_with_code(ret)
83         }
84     }
85 }
86
87 pub(super) fn exit_with_code(code: isize) -> ! {
88     if code != 0 {
89         if let Some(mut out) = panic::SgxPanicOutput::new() {
90             let _ = write!(out, "Exited with status code {}", code);
91         }
92     }
93     usercalls::exit(code != 0);
94 }