summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJethro Beekman <jethro@fortanix.com>2018-08-27 21:33:26 -0700
committerJethro Beekman <jethro@fortanix.com>2018-12-07 11:26:50 +0530
commit4a3505682e97c8e667338056ae216e4b84b22dd7 (patch)
tree64f04641da2097afb5c6a386f8e26a36a2687e6e
parentc559216ad0d2f0737f8dbb51a7d42b1727b77b3c (diff)
downloadrust-4a3505682e97c8e667338056ae216e4b84b22dd7.tar.gz
Add x86_64-fortanix-unknown-sgx target to libstd and dependencies
The files src/libstd/sys/sgx/*.rs are mostly copied/adapted from the wasm target. This also updates the dlmalloc submodule to the very latest version.
-rw-r--r--.gitmodules4
-rw-r--r--Cargo.lock9
-rw-r--r--src/bootstrap/dist.rs1
m---------src/dlmalloc0
m---------src/liblibc0
-rw-r--r--src/libpanic_abort/lib.rs6
-rw-r--r--src/libpanic_unwind/lib.rs2
-rw-r--r--src/libstd/Cargo.toml5
-rw-r--r--src/libstd/io/error.rs2
-rw-r--r--src/libstd/lib.rs7
-rw-r--r--src/libstd/sys/mod.rs3
-rw-r--r--src/libstd/sys/sgx/abi/entry.S327
-rw-r--r--src/libstd/sys/sgx/abi/mem.rs31
-rw-r--r--src/libstd/sys/sgx/abi/mod.rs94
-rw-r--r--src/libstd/sys/sgx/abi/panic.rs58
-rw-r--r--src/libstd/sys/sgx/abi/reloc.rs40
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/mod.rs12
-rw-r--r--src/libstd/sys/sgx/abi/usercalls/raw.rs231
-rw-r--r--src/libstd/sys/sgx/alloc.rs39
-rw-r--r--src/libstd/sys/sgx/args.rs57
-rw-r--r--src/libstd/sys/sgx/backtrace.rs37
-rw-r--r--src/libstd/sys/sgx/cmath.rs41
-rw-r--r--src/libstd/sys/sgx/condvar.rs43
-rw-r--r--src/libstd/sys/sgx/env.rs19
-rw-r--r--src/libstd/sys/sgx/fs.rs304
-rw-r--r--src/libstd/sys/sgx/memchr.rs11
-rw-r--r--src/libstd/sys/sgx/mod.rs151
-rw-r--r--src/libstd/sys/sgx/mutex.rs78
-rw-r--r--src/libstd/sys/sgx/net.rs356
-rw-r--r--src/libstd/sys/sgx/os.rs120
-rw-r--r--src/libstd/sys/sgx/os_str.rs189
-rw-r--r--src/libstd/sys/sgx/path.rs29
-rw-r--r--src/libstd/sys/sgx/pipe.rs35
-rw-r--r--src/libstd/sys/sgx/process.rs162
-rw-r--r--src/libstd/sys/sgx/rwlock.rs82
-rw-r--r--src/libstd/sys/sgx/stack_overflow.rs23
-rw-r--r--src/libstd/sys/sgx/stdio.rs73
-rw-r--r--src/libstd/sys/sgx/thread.rs51
-rw-r--r--src/libstd/sys/sgx/thread_local.rs50
-rw-r--r--src/libstd/sys/sgx/time.rs61
-rw-r--r--src/libstd/sys_common/mod.rs8
-rw-r--r--src/libtest/lib.rs10
-rw-r--r--src/libunwind/lib.rs5
m---------src/rust-sgx0
-rw-r--r--src/rustc/fortanix-sgx-abi_shim/Cargo.toml14
m---------src/stdsimd0
-rw-r--r--src/tools/tidy/src/lib.rs1
47 files changed, 2869 insertions, 12 deletions
diff --git a/.gitmodules b/.gitmodules
index 4a136cff1cd..3fc6e45db3e 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -61,10 +61,12 @@
path = src/tools/clang
url = https://github.com/rust-lang-nursery/clang.git
branch = rust-release-80-v2
-
[submodule "src/doc/rustc-guide"]
path = src/doc/rustc-guide
url = https://github.com/rust-lang/rustc-guide.git
[submodule "src/doc/edition-guide"]
path = src/doc/edition-guide
url = https://github.com/rust-lang-nursery/edition-guide
+[submodule "src/rust-sgx"]
+ path = src/rust-sgx
+ url = https://github.com/fortanix/rust-sgx
diff --git a/Cargo.lock b/Cargo.lock
index 02c63200a28..316724ca651 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -798,6 +798,14 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
+name = "fortanix-sgx-abi"
+version = "0.0.0"
+dependencies = [
+ "compiler_builtins 0.0.0",
+ "core 0.0.0",
+]
+
+[[package]]
name = "fs2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2773,6 +2781,7 @@ dependencies = [
"compiler_builtins 0.0.0",
"core 0.0.0",
"dlmalloc 0.0.0",
+ "fortanix-sgx-abi 0.0.0",
"libc 0.0.0",
"panic_abort 0.0.0",
"panic_unwind 0.0.0",
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index cd8d5642b25..6108692e43c 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -874,6 +874,7 @@ impl Step for Src {
"src/rustc/compiler_builtins_shim",
"src/rustc/libc_shim",
"src/rustc/dlmalloc_shim",
+ "src/rustc/fortanix-sgx-abi_shim",
"src/libtest",
"src/libterm",
"src/libprofiler_builtins",
diff --git a/src/dlmalloc b/src/dlmalloc
-Subproject c99638dc2ecfc750cc1656f6edb2bd062c1e098
+Subproject de99f4b0c886f5916cd1a146464276d65bef61b
diff --git a/src/liblibc b/src/liblibc
-Subproject c75ca6465a139704e00295be355b1f067af2f53
+Subproject 5b403753da9ec8ff501adf34cb6d63b319b4a3a
diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs
index 9235f8e7660..95c3514185e 100644
--- a/src/libpanic_abort/lib.rs
+++ b/src/libpanic_abort/lib.rs
@@ -66,6 +66,12 @@ pub unsafe extern fn __rust_start_panic(_payload: usize) -> u32 {
unsafe fn abort() -> ! {
core::intrinsics::abort();
}
+
+ #[cfg(target_env="sgx")]
+ unsafe fn abort() -> ! {
+ extern "C" { pub fn panic_exit() -> !; }
+ panic_exit();
+ }
}
// This... is a bit of an oddity. The tl;dr; is that this is required to link
diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs
index cfe671c626b..49f8a429126 100644
--- a/src/libpanic_unwind/lib.rs
+++ b/src/libpanic_unwind/lib.rs
@@ -62,7 +62,7 @@ cfg_if! {
if #[cfg(target_os = "emscripten")] {
#[path = "emcc.rs"]
mod imp;
- } else if #[cfg(target_arch = "wasm32")] {
+ } else if #[cfg(any(target_arch = "wasm32", target_env = "sgx"))] {
#[path = "dummy.rs"]
mod imp;
} else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] {
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index cae2f405318..274d5bec662 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -35,9 +35,12 @@ rustc_lsan = { path = "../librustc_lsan" }
rustc_msan = { path = "../librustc_msan" }
rustc_tsan = { path = "../librustc_tsan" }
-[target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies]
+[target.'cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx"))'.dependencies]
dlmalloc = { path = '../rustc/dlmalloc_shim' }
+[target.x86_64-fortanix-unknown-sgx.dependencies]
+fortanix-sgx-abi = { path = "../rustc/fortanix-sgx-abi_shim" }
+
[build-dependencies]
cc = "1.0"
build_helper = { path = "../build_helper" }
diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs
index 386de080b85..32e29962760 100644
--- a/src/libstd/io/error.rs
+++ b/src/libstd/io/error.rs
@@ -184,7 +184,7 @@ pub enum ErrorKind {
}
impl ErrorKind {
- fn as_str(&self) -> &'static str {
+ pub(crate) fn as_str(&self) -> &'static str {
match *self {
ErrorKind::NotFound => "entity not found",
ErrorKind::PermissionDenied => "permission denied",
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 78109a1a690..bf1e64efd37 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -312,6 +312,7 @@
#![feature(non_exhaustive)]
#![feature(alloc_layout_extra)]
#![feature(maybe_uninit)]
+#![cfg_attr(target_env = "sgx", feature(global_asm, range_contains))]
#![default_lib_allocator]
@@ -354,6 +355,12 @@ extern crate unwind;
// testing gives test-std access to real-std lang items and globals. See #2912
#[cfg(test)] extern crate std as realstd;
+#[cfg(target_env = "sgx")]
+#[macro_use]
+#[allow(unused_imports)] // FIXME: without `#[macro_use]`, get error: “cannot
+ // determine resolution for the macro `usercalls_asm`”
+extern crate fortanix_sgx_abi;
+
// The standard macros that are not built-in to the compiler.
#[macro_use]
mod macros;
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs
index 61e4ce66eec..04c47aeb827 100644
--- a/src/libstd/sys/mod.rs
+++ b/src/libstd/sys/mod.rs
@@ -48,6 +48,9 @@ cfg_if! {
} else if #[cfg(target_arch = "wasm32")] {
mod wasm;
pub use self::wasm::*;
+ } else if #[cfg(target_env = "sgx")] {
+ mod sgx;
+ pub use self::sgx::*;
} else {
compile_error!("libstd doesn't compile for this platform yet");
}
diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S
new file mode 100644
index 00000000000..4d5cc02e11e
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/entry.S
@@ -0,0 +1,327 @@
+/* Copyright 2018 The Rust Project Developers. See the COPYRIGHT */
+/* file at the top-level directory of this distribution and at */
+/* http://rust-lang.org/COPYRIGHT. */
+/* */
+/* Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or */
+/* http://www.apache.org/licenses/LICENSE-2.0> or the MIT license */
+/* <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your */
+/* option. This file may not be copied, modified, or distributed */
+/* except according to those terms. */
+
+/* This symbol is used at runtime to figure out the virtual address that the */
+/* enclave is loaded at. */
+.section absolute
+.global IMAGE_BASE
+IMAGE_BASE:
+
+.section .rodata
+/* The XSAVE area needs to be a large chunk of readable memory, but since we are */
+/* going to restore everything to its initial state (XSTATE_BV=0), only certain */
+/* parts need to have a defined value. In particular: */
+/* */
+/* * MXCSR in the legacy area. This register is always restored if RFBM[1] or */
+/* RFBM[2] is set, regardless of the value of XSTATE_BV */
+/* * XSAVE header */
+.align 64
+.Lxsave_clear:
+.org .+24
+.Lxsave_mxcsr:
+ .int 0
+
+/* We can store a bunch of data in the gap between MXCSR and the XSAVE header */
+
+/* The following symbols point at read-only data that will be filled in by the */
+/* post-linker. */
+
+/* When using this macro, don't forget to adjust the linker version script! */
+.macro globvar name:req size:req
+ .global \name
+ .protected \name
+ .align \size
+ .size \name , \size
+ \name :
+ .org .+\size
+.endm
+ /* The base address (relative to enclave start) of the heap area */
+ globvar HEAP_BASE 8
+ /* The heap size in bytes */
+ globvar HEAP_SIZE 8
+ /* Value of the RELA entry in the dynamic table */
+ globvar RELA 8
+ /* Value of the RELACOUNT entry in the dynamic table */
+ globvar RELACOUNT 8
+ /* The enclave size in bytes */
+ globvar ENCLAVE_SIZE 8
+ /* The base address (relative to enclave start) of the enclave configuration area */
+ globvar CFGDATA_BASE 8
+ /* Non-zero if debugging is enabled, zero otherwise */
+ globvar DEBUG 1
+
+.Lreentry_panic_msg:
+ .asciz "Re-entered panicked enclave!"
+.Lreentry_panic_msg_end:
+
+.Lusercall_panic_msg:
+ .asciz "Invalid usercall#!"
+.Lusercall_panic_msg_end:
+
+.org .Lxsave_clear+512
+.Lxsave_header:
+ .int 0, 0 /* XSTATE_BV */
+ .int 0, 0 /* XCOMP_BV */
+ .org .+48 /* reserved bits */
+
+.data
+.Lpanicked:
+ .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_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_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
+.endm
+
+.text
+.global sgx_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
+/* reset user state */
+ cld /* x86-64 ABI requires DF to be unset at function entry/exit */
+/* check for debug buffer pointer */
+ testb $0xff,DEBUG(%rip)
+ jz .Lskip_debug_init
+ mov %r10,%gs:tcsls_debug_panic_buf_ptr
+.Lskip_debug_init:
+/* check if returning from usercall */
+ mov %gs: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 */
+ /* here. This is fixed below under "adjust stack". */
+/* check for thread init */
+ bts $tcsls_flag_init_once,%gs:tcsls_flags
+ jc .Lskip_init
+/* adjust stack */
+ lea IMAGE_BASE(%rip),%rax
+ add %rax,%rsp
+ mov %rsp,%gs:tcsls_tos
+/* call tcs_init */
+/* store caller-saved registers in callee-saved registers */
+ mov %rdi,%rbx
+ mov %rsi,%r12
+ mov %rdx,%r13
+ mov %r8,%r14
+ mov %r9,%r15
+ load_tcsls_flag_secondary_bool di /* RDI = tcs_init() argument: secondary: bool */
+ call tcs_init
+/* reload caller-saved registers */
+ mov %rbx,%rdi
+ mov %r12,%rsi
+ mov %r13,%rdx
+ mov %r14,%r8
+ mov %r15,%r9
+.Lskip_init:
+/* check for panic */
+ bt $0,.Lpanicked(%rip)
+ jc .Lreentry_panic
+/* call into main entry point */
+ load_tcsls_flag_secondary_bool cx /* RCX = entry() argument: secondary: bool */
+ call entry /* RDI, RSI, RDX, R8, R9 passed in from userspace */
+ mov %rax,%rsi /* RSI = return value */
+ /* NOP: mov %rdx,%rdx */ /* RDX = return value */
+ xor %rdi,%rdi /* RDI = normal exit */
+.Lexit:
+/* clear general purpose register state */
+ /* RAX overwritten by ENCLU */
+ /* RBX set later */
+ /* RCX overwritten by ENCLU */
+ /* RDX contains return value */
+ /* RSP set later */
+ /* RBP set later */
+ /* RDI contains exit mode */
+ /* RSI contains return value */
+ xor %r8,%r8
+ xor %r9,%r9
+ xor %r10,%r10
+ xor %r11,%r11
+ /* R12 ~ R15 set by sgx_exit */
+.Lsgx_exit:
+/* clear extended register state */
+ mov %rdx, %rcx /* save RDX */
+ mov $-1, %rax
+ mov %rax, %rdx
+ xrstor .Lxsave_clear(%rip)
+ mov %rcx, %rdx /* restore RDX */
+/* clear flags */
+ 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
+/* exit enclave */
+ mov $0x4,%eax /* EEXIT */
+ enclu
+/* end sgx_entry */
+
+.Lreentry_panic:
+ lea .Lreentry_panic_msg(%rip),%rdi
+ mov $.Lreentry_panic_msg_end-.Lreentry_panic_msg,%esi
+ orq $8,%rsp
+ jmp panic_msg
+
+.Lusercall_panic:
+ lea .Lusercall_panic_msg(%rip),%rdi
+ mov $.Lusercall_panic_msg_end-.Lusercall_panic_msg,%esi
+ orq $8,%rsp
+ jmp panic_msg
+
+.macro push_callee_saved_registers
+ push %r15
+ push %r14
+ push %r13
+ push %r12
+ push %rbp
+ push %rbx
+ sub $8, %rsp
+ fstcw 4(%rsp)
+ stmxcsr (%rsp)
+.endm
+
+.global panic_exit
+panic_exit:
+/* save registers in DEBUG mode, so that debugger can reconstruct the stack */
+ testb $0xff,DEBUG(%rip)
+ jz .Lskip_save_registers
+ push_callee_saved_registers
+ movq %rsp,%gs:tcsls_panic_last_rsp
+.Lskip_save_registers:
+/* set panicked bit */
+ movb $1,.Lpanicked(%rip)
+/* call usercall exit(true) */
+ mov $1,%esi /* RSI = usercall() argument: panic = true */
+ xor %rdx,%rdx /* RDX cleared */
+ movq $usercall_nr_exit,%rdi /* RDI = usercall exit */
+ jmp .Lexit
+
+/* This *MUST* be called with 6 parameters, otherwise register information */
+/* might leak! */
+.global usercall
+usercall:
+ test %rdi,%rdi
+ jle .Lusercall_panic
+/* save callee-saved state */
+ push_callee_saved_registers
+ movq %rsp,%gs:tcsls_last_rsp
+/* clear general purpose register state */
+ /* RAX overwritten by ENCLU */
+ /* RBX set by sgx_exit */
+ /* RCX overwritten by ENCLU */
+ /* RDX contains parameter */
+ /* RSP set by sgx_exit */
+ /* RBP set by sgx_exit */
+ /* RDI contains parameter */
+ /* RSI contains parameter */
+ /* R8 contains parameter */
+ /* R9 contains parameter */
+ xor %r10,%r10
+ xor %r11,%r11
+ /* R12 ~ R15 set by sgx_exit */
+/* extended registers/flags cleared by sgx_exit */
+/* exit */
+ jmp .Lsgx_exit
+.Lusercall_ret:
+ movq $0,%gs:tcsls_last_rsp
+/* restore callee-saved state, cf. push_callee_saved_registers */
+ mov %r11,%rsp
+ ldmxcsr (%rsp)
+ fldcw 4(%rsp)
+ add $8, %rsp
+ pop %rbx
+ pop %rbp
+ pop %r12
+ pop %r13
+ pop %r14
+ pop %r15
+/* return */
+ mov %rsi,%rax /* RAX = return value */
+ /* NOP: mov %rdx,%rdx */ /* RDX = return value */
+ ret
+
+/*
+The following functions need to be defined externally:
+```
+// Called by entry code when it needs to panic
+extern "C" fn panic_msg(msg: &'static str) -> ! {
+ panic!(msg)
+}
+
+// Called once when a TCS is first entered
+extern "C" fn tcs_init(secondary: bool);
+
+// Standard TCS entrypoint
+extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64);
+```
+*/
+
+.global get_tcs_addr
+get_tcs_addr:
+ mov %gs:tcsls_tcs_addr,%rax
+ ret
+
+.global get_tls_ptr
+get_tls_ptr:
+ mov %gs:tcsls_tls_ptr,%rax
+ ret
+
+.global set_tls_ptr
+set_tls_ptr:
+ mov %rdi,%gs:tcsls_tls_ptr
+ ret
+
+.global take_debug_panic_buf_ptr
+take_debug_panic_buf_ptr:
+ xor %rax,%rax
+ xchg %gs:tcsls_debug_panic_buf_ptr,%rax
+ ret
diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs
new file mode 100644
index 00000000000..aedf6ec7acb
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/mem.rs
@@ -0,0 +1,31 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Do not remove inline: will result in relocation failure
+#[inline(always)]
+pub unsafe fn rel_ptr<T>(offset: u64) -> *const T {
+ (image_base()+offset) as *const T
+}
+
+// Do not remove inline: will result in relocation failure
+#[inline(always)]
+pub unsafe fn rel_ptr_mut<T>(offset: u64) -> *mut T {
+ (image_base()+offset) as *mut T
+}
+
+// Do not remove inline: will result in relocation failure
+// For the same reason we use inline ASM here instead of an extern static to
+// locate the base
+#[inline(always)]
+fn image_base() -> u64 {
+ let base;
+ unsafe{asm!("lea IMAGE_BASE(%rip),$0":"=r"(base))};
+ base
+}
diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs
new file mode 100644
index 00000000000..cade96e3f52
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/mod.rs
@@ -0,0 +1,94 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use core::sync::atomic::{AtomicUsize, Ordering};
+use io::Write;
+
+// runtime features
+mod reloc;
+mod mem;
+pub(super) mod panic;
+
+// library features
+#[macro_use]
+mod usercalls;
+
+global_asm!(concat!(usercalls_asm!(), include_str!("entry.S")));
+
+#[no_mangle]
+unsafe extern "C" fn tcs_init(secondary: bool) {
+ // Be very careful when changing this code: it runs before the binary has been
+ // relocated. Any indirect accesses to symbols will likely fail.
+ const UNINIT: usize = 0;
+ const BUSY: usize = 1;
+ const DONE: usize = 2;
+ // Three-state spin-lock
+ static RELOC_STATE: AtomicUsize = AtomicUsize::new(UNINIT);
+
+ if secondary && RELOC_STATE.load(Ordering::Relaxed) != DONE {
+ panic::panic_msg("Entered secondary TCS before main TCS!")
+ }
+
+ // Try to atomically swap UNINIT with BUSY. The returned state can be:
+ match RELOC_STATE.compare_and_swap(UNINIT, BUSY, Ordering::Acquire) {
+ // This thread just obtained the lock and other threads will observe BUSY
+ UNINIT => {
+ reloc::relocate_elf_rela();
+ RELOC_STATE.store(DONE, Ordering::Release);
+ },
+ // We need to wait until the initialization is done.
+ BUSY => while RELOC_STATE.load(Ordering::Acquire) == BUSY {
+ ::core::arch::x86_64::_mm_pause()
+ },
+ // Initialization is done.
+ DONE => {},
+ _ => unreachable!()
+ }
+}
+
+// FIXME: this item should only exist if this is linked into an executable
+// (main function exists). If this is a library, the crate author should be
+// able to specify this
+#[no_mangle]
+#[allow(unreachable_code)]
+extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) {
+ if secondary {
+ unimplemented!("thread entrypoint");
+
+ (0, 0)
+ } else {
+ extern "C" {
+ fn main(argc: isize, argv: *const *const u8) -> isize;
+ }
+
+ // check entry is being called according to ABI
+ assert_eq!(p3, 0);
+ assert_eq!(p4, 0);
+ assert_eq!(p5, 0);
+
+ unsafe {
+ // The actual types of these arguments are `p1: *const Arg, p2:
+ // usize`. We can't currently customize the argument list of Rust's
+ // main function, so we pass these in as the standard pointer-sized
+ // values in `argc` and `argv`.
+ let ret = main(p2 as _, p1 as _);
+ exit_with_code(ret)
+ }
+ }
+}
+
+pub(super) fn exit_with_code(code: isize) -> ! {
+ if code != 0 {
+ if let Some(mut out) = panic::SgxPanicOutput::new() {
+ let _ = write!(out, "Exited with status code {}", code);
+ }
+ }
+ unsafe { usercalls::raw::exit(code != 0) };
+}
diff --git a/src/libstd/sys/sgx/abi/panic.rs b/src/libstd/sys/sgx/abi/panic.rs
new file mode 100644
index 00000000000..dd9159b9fe2
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/panic.rs
@@ -0,0 +1,58 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io::{self, Write};
+use slice::from_raw_parts_mut;
+
+extern "C" {
+ fn take_debug_panic_buf_ptr() -> *mut u8;
+ static DEBUG: u8;
+}
+
+pub(crate) struct SgxPanicOutput(Option<&'static mut [u8]>);
+
+impl SgxPanicOutput {
+ pub(crate) fn new() -> Option<Self> {
+ if unsafe { DEBUG == 0 } {
+ None
+ } else {
+ Some(SgxPanicOutput(None))
+ }
+ }
+
+ fn init(&mut self) -> &mut &'static mut [u8] {
+ self.0.get_or_insert_with(|| unsafe {
+ let ptr = take_debug_panic_buf_ptr();
+ if ptr.is_null() {
+ &mut []
+ } else {
+ from_raw_parts_mut(ptr, 1024)
+ }
+ })
+ }
+}
+
+impl Write for SgxPanicOutput {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.init().write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ self.init().flush()
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn panic_msg(msg: &str) -> ! {
+ let _ = SgxPanicOutput::new().map(|mut out| out.write(msg.as_bytes()));
+ unsafe { panic_exit(); }
+}
+
+extern "C" { pub fn panic_exit() -> !; }
diff --git a/src/libstd/sys/sgx/abi/reloc.rs b/src/libstd/sys/sgx/abi/reloc.rs
new file mode 100644
index 00000000000..2d5e14d6ad1
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/reloc.rs
@@ -0,0 +1,40 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use slice::from_raw_parts;
+use super::mem;
+
+const R_X86_64_RELATIVE: u32 = 8;
+
+#[repr(packed)]
+struct Rela<T> {
+ offset: T,
+ info: T,
+ addend: T,
+}
+
+pub fn relocate_elf_rela() {
+ extern {
+ static RELA: u64;
+ static RELACOUNT: usize;
+ }
+
+ if unsafe { RELACOUNT } == 0 { return } // unsafe ok: link-time constant
+
+ let relas = unsafe {
+ from_raw_parts::<Rela<u64>>(mem::rel_ptr(RELA), RELACOUNT) // unsafe ok: link-time constant
+ };
+ for rela in relas {
+ if rela.info != (/*0 << 32 |*/ R_X86_64_RELATIVE as u64) {
+ panic!("Invalid relocation");
+ }
+ unsafe { *mem::rel_ptr_mut::<*const ()>(rela.offset) = mem::rel_ptr(rela.addend) };
+ }
+}
diff --git a/src/libstd/sys/sgx/abi/usercalls/mod.rs b/src/libstd/sys/sgx/abi/usercalls/mod.rs
new file mode 100644
index 00000000000..370e058badf
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/usercalls/mod.rs
@@ -0,0 +1,12 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[macro_use]
+pub mod raw;
diff --git a/src/libstd/sys/sgx/abi/usercalls/raw.rs b/src/libstd/sys/sgx/abi/usercalls/raw.rs
new file mode 100644
index 00000000000..a28d41c1b74
--- /dev/null
+++ b/src/libstd/sys/sgx/abi/usercalls/raw.rs
@@ -0,0 +1,231 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(unused)]
+
+use fortanix_sgx_abi::*;
+
+use ptr::NonNull;
+
+#[repr(C)]
+struct UsercallReturn(u64, u64);
+
+extern "C" {
+ fn usercall(nr: u64, p1: u64, p2: u64, _ignore: u64, p3: u64, p4: u64) -> UsercallReturn;
+}
+
+unsafe fn do_usercall(nr: u64, p1: u64, p2: u64, p3: u64, p4: u64) -> (u64, u64) {
+ if nr==0 { panic!("Invalid usercall number {}",nr) }
+ let UsercallReturn(a, b) = usercall(nr,p1,p2,0,p3,p4);
+ (a, b)
+}
+
+type Register = u64;
+
+trait RegisterArgument {
+ fn from_register(Register) -> Self;
+ fn into_register(self) -> Register;
+}
+
+trait ReturnValue {
+ fn from_registers(call: &'static str, regs: (Register, Register)) -> Self;
+}
+
+macro_rules! define_usercalls {
+ // Using `$r:tt` because `$r:ty` doesn't match ! in `clobber_diverging`
+ ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:tt)*; )*) => {
+ #[repr(C)]
+ #[allow(non_camel_case_types)]
+ enum Usercalls {
+ __enclave_usercalls_invalid,
+ $($f,)*
+ }
+
+ $(enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) $(-> $r)*);)*
+ };
+}
+
+macro_rules! define_usercalls_asm {
+ ($(fn $f:ident($($n:ident: $t:ty),*) $(-> $r:ty)*; )*) => {
+ macro_rules! usercalls_asm {
+ () => {
+ concat!(
+ ".equ usercall_nr_LAST, 0\n",
+ $(
+ ".equ usercall_nr_", stringify!($f), ", usercall_nr_LAST+1\n",
+ ".equ usercall_nr_LAST, usercall_nr_", stringify!($f), "\n"
+ ),*
+ )
+ }
+ }
+ };
+}
+
+macro_rules! define_ra {
+ (< $i:ident > $t:ty) => {
+ impl<$i> RegisterArgument for $t {
+ fn from_register(a: Register) -> Self {
+ a as _
+ }
+ fn into_register(self) -> Register {
+ self as _
+ }
+ }
+ };
+ ($i:ty as $t:ty) => {
+ impl RegisterArgument for $t {
+ fn from_register(a: Register) -> Self {
+ a as $i as _
+ }
+ fn into_register(self) -> Register {
+ self as $i as _
+ }
+ }
+ };
+ ($t:ty) => {
+ impl RegisterArgument for $t {
+ fn from_register(a: Register) -> Self {
+ a as _
+ }
+ fn into_register(self) -> Register {
+ self as _
+ }
+ }
+ };
+}
+
+define_ra!(Register);
+define_ra!(i64);
+define_ra!(u32);
+define_ra!(u32 as i32);
+define_ra!(u16);
+define_ra!(u16 as i16);
+define_ra!(u8);
+define_ra!(u8 as i8);
+define_ra!(usize);
+define_ra!(usize as isize);
+define_ra!(<T> *const T);
+define_ra!(<T> *mut T);
+
+impl RegisterArgument for bool {
+ fn from_register(a: Register) -> bool {
+ if a != 0 {
+ true
+ } else {
+ false
+ }
+ }
+ fn into_register(self) -> Register {
+ self as _
+ }
+}
+
+impl<T: RegisterArgument> RegisterArgument for Option<NonNull<T>> {
+ fn from_register(a: Register) -> Option<NonNull<T>> {
+ NonNull::new(a as _)
+ }
+ fn into_register(self) -> Register {
+ self.map_or(0 as _, NonNull::as_ptr) as _
+ }
+}
+
+impl ReturnValue for ! {
+ fn from_registers(call: &'static str, _regs: (Register, Register)) -> Self {
+ panic!("Usercall {}: did not expect to be re-entered", call);
+ }
+}
+
+impl ReturnValue for () {
+ fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
+ assert_eq!(regs.0, 0, "Usercall {}: expected {} return value to be 0", call, "1st");
+ assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
+ ()
+ }
+}
+
+impl<T: RegisterArgument> ReturnValue for T {
+ fn from_registers(call: &'static str, regs: (Register, Register)) -> Self {
+ assert_eq!(regs.1, 0, "Usercall {}: expected {} return value to be 0", call, "2nd");
+ T::from_register(regs.0)
+ }
+}
+
+impl<T: RegisterArgument, U: RegisterArgument> ReturnValue for (T, U) {
+ fn from_registers(_call: &'static str, regs: (Register, Register)) -> Self {
+ (
+ T::from_register(regs.0),
+ U::from_register(regs.1)
+ )
+ }
+}
+
+macro_rules! enclave_usercalls_internal_define_usercalls {
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty,
+ $n3:ident: $t3:ty, $n4:ident: $t4:ty) -> $r:ty) => (
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3, $n4: $t4) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ Usercalls::$f as Register,
+ RegisterArgument::into_register($n1),
+ RegisterArgument::into_register($n2),
+ RegisterArgument::into_register($n3),
+ RegisterArgument::into_register($n4),
+ ))
+ }
+ );
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty, $n3:ident: $t3:ty) -> $r:ty) => (
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1, $n2: $t2, $n3: $t3) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ Usercalls::$f as Register,
+ RegisterArgument::into_register($n1),
+ RegisterArgument::into_register($n2),
+ RegisterArgument::into_register($n3),
+ 0
+ ))
+ }
+ );
+ (def fn $f:ident($n1:ident: $t1:ty, $n2:ident: $t2:ty) -> $r:ty) => (
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1, $n2: $t2) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ Usercalls::$f as Register,
+ RegisterArgument::into_register($n1),
+ RegisterArgument::into_register($n2),
+ 0,0
+ ))
+ }
+ );
+ (def fn $f:ident($n1:ident: $t1:ty) -> $r:ty) => (
+ #[inline(always)]
+ pub unsafe fn $f($n1: $t1) -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ Usercalls::$f as Register,
+ RegisterArgument::into_register($n1),
+ 0,0,0
+ ))
+ }
+ );
+ (def fn $f:ident() -> $r:ty) => (
+ #[inline(always)]
+ pub unsafe fn $f() -> $r {
+ ReturnValue::from_registers(stringify!($f), do_usercall(
+ Usercalls::$f as Register,
+ 0,0,0,0
+ ))
+ }
+ );
+ (def fn $f:ident($($n:ident: $t:ty),*)) => (
+ enclave_usercalls_internal_define_usercalls!(def fn $f($($n: $t),*) -> ());
+ );
+}
+
+invoke_with_usercalls!(define_usercalls);
+invoke_with_usercalls!(define_usercalls_asm);
diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs
new file mode 100644
index 00000000000..a31f93ae493
--- /dev/null
+++ b/src/libstd/sys/sgx/alloc.rs
@@ -0,0 +1,39 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+extern crate dlmalloc;
+
+use alloc::{GlobalAlloc, Layout, System};
+
+// FIXME: protect this value for concurrent access
+static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ DLMALLOC.malloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ DLMALLOC.calloc(layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ DLMALLOC.free(ptr, layout.size(), layout.align())
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size)
+ }
+}
diff --git a/src/libstd/sys/sgx/args.rs b/src/libstd/sys/sgx/args.rs
new file mode 100644
index 00000000000..64cb83b462a
--- /dev/null
+++ b/src/libstd/sys/sgx/args.rs
@@ -0,0 +1,57 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::OsString;
+use fortanix_sgx_abi::ByteBuffer;
+
+pub unsafe fn init(argc: isize, argv: *const *const u8) {
+ // See ABI
+ let _len: usize = argc as _;
+ let _args: *const ByteBuffer = argv as _;
+
+ // TODO
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub fn args() -> Args {
+ Args
+}
+
+pub struct Args;
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ &[]
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ None
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (0, Some(0))
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ 0
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ None
+ }
+}
diff --git a/src/libstd/sys/sgx/backtrace.rs b/src/libstd/sys/sgx/backtrace.rs
new file mode 100644
index 00000000000..ca4a7c9561c
--- /dev/null
+++ b/src/libstd/sys/sgx/backtrace.rs
@@ -0,0 +1,37 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use sys::unsupported;
+use sys_common::backtrace::Frame;
+
+pub struct BacktraceContext;
+
+pub fn unwind_backtrace(_frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ unsupported()
+}
+
+pub fn resolve_symname<F>(_frame: Frame,
+ _callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsupported()
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+ _: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ unsupported()
+}
diff --git a/src/libstd/sys/sgx/cmath.rs b/src/libstd/sys/sgx/cmath.rs
new file mode 100644
index 00000000000..0c1300f61f8
--- /dev/null
+++ b/src/libstd/sys/sgx/cmath.rs
@@ -0,0 +1,41 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![cfg(not(test))]
+
+// These symbols are all defined in `compiler-builtins`
+extern {
+ pub fn acos(n: f64) -> f64;
+ pub fn acosf(n: f32) -> f32;
+ pub fn asin(n: f64) -> f64;
+ pub fn asinf(n: f32) -> f32;
+ pub fn atan(n: f64) -> f64;
+ pub fn atan2(a: f64, b: f64) -> f64;
+ pub fn atan2f(a: f32, b: f32) -> f32;
+ pub fn atanf(n: f32) -> f32;
+ pub fn cbrt(n: f64) -> f64;
+ pub fn cbrtf(n: f32) -> f32;
+ pub fn cosh(n: f64) -> f64;
+ pub fn coshf(n: f32) -> f32;
+ pub fn expm1(n: f64) -> f64;
+ pub fn expm1f(n: f32) -> f32;
+ pub fn fdim(a: f64, b: f64) -> f64;
+ pub fn fdimf(a: f32, b: f32) -> f32;
+ pub fn hypot(x: f64, y: f64) -> f64;
+ pub fn hypotf(x: f32, y: f32) -> f32;
+ pub fn log1p(n: f64) -> f64;
+ pub fn log1pf(n: f32) -> f32;
+ pub fn sinh(n: f64) -> f64;
+ pub fn sinhf(n: f32) -> f32;
+ pub fn tan(n: f64) -> f64;
+ pub fn tanf(n: f32) -> f32;
+ pub fn tanh(n: f64) -> f64;
+ pub fn tanhf(n: f32) -> f32;
+}
diff --git a/src/libstd/sys/sgx/condvar.rs b/src/libstd/sys/sgx/condvar.rs
new file mode 100644
index 00000000000..2097280a064
--- /dev/null
+++ b/src/libstd/sys/sgx/condvar.rs
@@ -0,0 +1,43 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use sys::mutex::Mutex;
+use time::Duration;
+
+pub struct Condvar { }
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar { }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {}
+
+ #[inline]
+ pub unsafe fn notify_one(&self) {
+ }
+
+ #[inline]
+ pub unsafe fn notify_all(&self) {
+ }
+
+ pub unsafe fn wait(&self, _mutex: &Mutex) {
+ panic!("can't block with web assembly")
+ }
+
+ pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
+ panic!("can't block with web assembly");
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ }
+}
diff --git a/src/libstd/sys/sgx/env.rs b/src/libstd/sys/sgx/env.rs
new file mode 100644
index 00000000000..146ce02754b
--- /dev/null
+++ b/src/libstd/sys/sgx/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod os {
+ pub const FAMILY: &'static str = "";
+ pub const OS: &'static str = "";
+ pub const DLL_PREFIX: &'static str = "";
+ pub const DLL_SUFFIX: &'static str = ".sgxs";
+ pub const DLL_EXTENSION: &'static str = "sgxs";
+ pub const EXE_SUFFIX: &'static str = ".sgxs";
+ pub const EXE_EXTENSION: &'static str = "sgxs";
+}
diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs
new file mode 100644
index 00000000000..1dcea3e8eac
--- /dev/null
+++ b/src/libstd/sys/sgx/fs.rs
@@ -0,0 +1,304 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::OsString;
+use fmt;
+use hash::{Hash, Hasher};
+use io::{self, SeekFrom};
+use path::{Path, PathBuf};
+use sys::time::SystemTime;
+use sys::{unsupported, Void};
+
+pub struct File(Void);
+
+pub struct FileAttr(Void);
+
+pub struct ReadDir(Void);
+
+pub struct DirEntry(Void);
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions { }
+
+pub struct FilePermissions(Void);
+
+pub struct FileType(Void);
+
+#[derive(Debug)]
+pub struct DirBuilder { }
+
+impl FileAttr {
+ pub fn size(&self) -> u64 {
+ match self.0 {}
+ }
+
+ pub fn perm(&self) -> FilePermissions {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> FileType {
+ match self.0 {}
+ }
+
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileAttr {
+ fn clone(&self) -> FileAttr {
+ match self.0 {}
+ }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn set_readonly(&mut self, _readonly: bool) {
+ match self.0 {}
+ }
+}
+
+impl Clone for FilePermissions {
+ fn clone(&self) -> FilePermissions {
+ match self.0 {}
+ }
+}
+
+impl PartialEq for FilePermissions {
+ fn eq(&self, _other: &FilePermissions) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FilePermissions {
+}
+
+impl fmt::Debug for FilePermissions {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_file(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn is_symlink(&self) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Clone for FileType {
+ fn clone(&self) -> FileType {
+ match self.0 {}
+ }
+}
+
+impl Copy for FileType {}
+
+impl PartialEq for FileType {
+ fn eq(&self, _other: &FileType) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for FileType {
+}
+
+impl Hash for FileType {
+ fn hash<H: Hasher>(&self, _h: &mut H) {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for FileType {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ match self.0 {}
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ match self.0 {}
+ }
+
+ pub fn file_name(&self) -> OsString {
+ match self.0 {}
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ match self.0 {}
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions { }
+ }
+
+ pub fn read(&mut self, _read: bool) { }
+ pub fn write(&mut self, _write: bool) { }
+ pub fn append(&mut self, _append: bool) { }
+ pub fn truncate(&mut self, _truncate: bool) { }
+ pub fn create(&mut self, _create: bool) { }
+ pub fn create_new(&mut self, _create_new: bool) { }
+}
+
+impl File {
+ pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
+ unsupported()
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ match self.0 {}
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn truncate(&self, _size: u64) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ match self.0 {}
+ }
+
+ pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder { }
+ }
+
+ pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
+ unsupported()
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
+ unsupported()
+}
+
+pub fn unlink(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
+ match perm.0 {}
+}
+
+pub fn rmdir(_p: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn stat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
+ unsupported()
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
+ unsupported()
+}
diff --git a/src/libstd/sys/sgx/memchr.rs b/src/libstd/sys/sgx/memchr.rs
new file mode 100644
index 00000000000..0998bc5db4c
--- /dev/null
+++ b/src/libstd/sys/sgx/memchr.rs
@@ -0,0 +1,11 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
new file mode 100644
index 00000000000..f38c69e90c7
--- /dev/null
+++ b/src/libstd/sys/sgx/mod.rs
@@ -0,0 +1,151 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! System bindings for the Fortanix SGX platform
+//!
+//! This module contains the facade (aka platform-specific) implementations of
+//! OS level functionality for Fortanix SGX.
+
+use io;
+use os::raw::c_char;
+use sync::atomic::{AtomicBool, Ordering};
+
+pub mod abi;
+
+pub mod alloc;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod fs;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod os_str;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+pub mod stdio;
+
+#[cfg(not(test))]
+pub fn init() {
+}
+
+/// This function is used to implement functionality that simply doesn't exist.
+/// Programs relying on this functionality will need to deal with the error.
+pub fn unsupported<T>() -> io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> io::Error {
+ io::Error::new(io::ErrorKind::Other,
+ "operation not supported on SGX yet")
+}
+
+/// This function is used to implement various functions that doesn't exist,
+/// but the lack of which might not be reason for error. If no error is
+/// returned, the program might very well be able to function normally. This is
+/// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is
+/// `false`, the behavior is the same as `unsupported`.
+pub fn sgx_ineffective<T>(v: T) -> io::Result<T> {
+ static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false);
+ if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) {
+ Err(io::Error::new(io::ErrorKind::Other,
+ "operation can't be trusted to have any effect on SGX"))
+ } else {
+ Ok(v)
+ }
+}
+
+pub fn decode_error_kind(code: i32) -> io::ErrorKind {
+ use fortanix_sgx_abi::Error;
+
+ // FIXME: not sure how to make sure all variants of Error are covered
+ if code == Error::NotFound as _ {
+ io::ErrorKind::NotFound
+ } else if code == Error::PermissionDenied as _ {
+ io::ErrorKind::PermissionDenied
+ } else if code == Error::ConnectionRefused as _ {
+ io::ErrorKind::ConnectionRefused
+ } else if code == Error::ConnectionReset as _ {
+ io::ErrorKind::ConnectionReset
+ } else if code == Error::ConnectionAborted as _ {
+ io::ErrorKind::ConnectionAborted
+ } else if code == Error::NotConnected as _ {
+ io::ErrorKind::NotConnected
+ } else if code == Error::AddrInUse as _ {
+ io::ErrorKind::AddrInUse
+ } else if code == Error::AddrNotAvailable as _ {
+ io::ErrorKind::AddrNotAvailable
+ } else if code == Error::BrokenPipe as _ {
+ io::ErrorKind::BrokenPipe
+ } else if code == Error::AlreadyExists as _ {
+ io::ErrorKind::AlreadyExists
+ } else if code == Error::WouldBlock as _ {
+ io::ErrorKind::WouldBlock
+ } else if code == Error::InvalidInput as _ {
+ io::ErrorKind::InvalidInput
+ } else if code == Error::InvalidData as _ {
+ io::ErrorKind::InvalidData
+ } else if code == Error::TimedOut as _ {
+ io::ErrorKind::TimedOut
+ } else if code == Error::WriteZero as _ {
+ io::ErrorKind::WriteZero
+ } else if code == Error::Interrupted as _ {
+ io::ErrorKind::Interrupted
+ } else if code == Error::Other as _ {
+ io::ErrorKind::Other
+ } else if code == Error::UnexpectedEof as _ {
+ io::ErrorKind::UnexpectedEof
+ } else {
+ io::ErrorKind::Other
+ }
+}
+
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
+pub unsafe fn strlen(mut s: *const c_char) -> usize {
+ let mut n = 0;
+ while *s != 0 {
+ n += 1;
+ s = s.offset(1);
+ }
+ return n
+}
+
+pub unsafe fn abort_internal() -> ! {
+ abi::panic::panic_exit()
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ fn rdrand64() -> u64 {
+ unsafe {
+ let mut ret: u64 = ::mem::uninitialized();
+ for _ in 0..10 {
+ if ::arch::x86_64::_rdrand64_step(&mut ret) == 1 {
+ return ret;
+ }
+ }
+ panic!("Failed to obtain random data");
+ }
+ }
+ (rdrand64(), rdrand64())
+}
diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs
new file mode 100644
index 00000000000..ffaa4014e14
--- /dev/null
+++ b/src/libstd/sys/sgx/mutex.rs
@@ -0,0 +1,78 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cell::UnsafeCell;
+
+pub struct Mutex {
+ locked: UnsafeCell<bool>,
+}
+
+unsafe impl Send for Mutex {}
+unsafe impl Sync for Mutex {} // FIXME
+
+impl Mutex {
+ pub const fn new() -> Mutex {
+ Mutex { locked: UnsafeCell::new(false) }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ }
+
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let locked = self.locked.get();
+ assert!(!*locked, "cannot recursively acquire mutex");
+ *locked = true;
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ *self.locked.get() = false;
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ let locked = self.locked.get();
+ if *locked {
+ false
+ } else {
+ *locked = true;
+ true
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ }
+}
+
+// FIXME
+pub struct ReentrantMutex {
+}
+
+impl ReentrantMutex {
+ pub unsafe fn uninitialized() -> ReentrantMutex {
+ ReentrantMutex { }
+ }
+
+ pub unsafe fn init(&mut self) {}
+
+ pub unsafe fn lock(&self) {}
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ true
+ }
+
+ pub unsafe fn unlock(&self) {}
+
+ pub unsafe fn destroy(&self) {}
+}
diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs
new file mode 100644
index 00000000000..094683e28b8
--- /dev/null
+++ b/src/libstd/sys/sgx/net.rs
@@ -0,0 +1,356 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use fmt;
+use io;
+use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
+use time::Duration;
+use sys::{unsupported, Void};
+use convert::TryFrom;
+
+pub struct TcpStream(Void);
+
+impl TcpStream {
+ pub fn connect(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
+ unsupported()
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpStream> {
+ match self.0 {}
+ }
+
+ pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpStream {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct TcpListener(Void);
+
+impl TcpListener {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
+ unsupported()
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<TcpListener> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn only_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for TcpListener {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct UdpSocket(Void);
+
+impl UdpSocket {
+ pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
+ unsupported()
+ }
+
+ pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+ match self.0 {}
+ }
+
+ pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ match self.0 {}
+ }
+
+ pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn duplicate(&self) -> io::Result<UdpSocket> {
+ match self.0 {}
+ }
+
+ pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ match self.0 {}
+ }
+
+ pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn broadcast(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v4(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn multicast_loop_v6(&self) -> io::Result<bool> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
+ -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn set_ttl(&self, _: u32) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn ttl(&self) -> io::Result<u32> {
+ match self.0 {}
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ match self.0 {}
+ }
+
+ pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn send(&self, _: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
+ match self.0 {}
+ }
+}
+
+impl fmt::Debug for UdpSocket {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct LookupHost(Void);
+
+impl LookupHost {
+ pub fn port(&self) -> u16 {
+ match self.0 {}
+ }
+}
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<SocketAddr> {
+ match self.0 {}
+ }
+}
+
+impl<'a> TryFrom<&'a str> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: &'a str) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
+ type Error = io::Error;
+
+ fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
+ unsupported()
+ }
+}
+
+#[allow(bad_style)]
+pub mod netc {
+ pub const AF_INET: u8 = 0;
+ pub const AF_INET6: u8 = 1;
+ pub type sa_family_t = u8;
+
+ #[derive(Copy, Clone)]
+ pub struct in_addr {
+ pub s_addr: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: u16,
+ pub sin_addr: in_addr,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: u16,
+ pub sin6_addr: in6_addr,
+ pub sin6_flowinfo: u32,
+ pub sin6_scope_id: u32,
+ }
+
+ #[derive(Copy, Clone)]
+ pub struct sockaddr {
+ }
+
+ pub type socklen_t = usize;
+}
diff --git a/src/libstd/sys/sgx/os.rs b/src/libstd/sys/sgx/os.rs
new file mode 100644
index 00000000000..38d82efaf17
--- /dev/null
+++ b/src/libstd/sys/sgx/os.rs
@@ -0,0 +1,120 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use fortanix_sgx_abi::{Error, RESULT_SUCCESS};
+
+use error::Error as StdError;
+use ffi::{OsString, OsStr};
+use fmt;
+use io;
+use path::{self, PathBuf};
+use str;
+use sys::{unsupported, Void, sgx_ineffective, decode_error_kind};
+
+pub fn errno() -> i32 {
+ RESULT_SUCCESS
+}
+
+pub fn error_string(errno: i32) -> String {
+ if errno == RESULT_SUCCESS {
+ "operation succesful".into()
+ } else if ((Error::UserRangeStart as _)..=(Error::UserRangeEnd as _)).contains(&errno) {
+ format!("user-specified error {:08x}", errno)
+ } else {
+ decode_error_kind(errno).as_str().into()
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ sgx_ineffective(())
+}
+
+pub struct SplitPaths<'a>(&'a Void);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ match *self.0 {}
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ "not supported in SGX yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str {
+ "not supported in SGX yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env;
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ None
+ }
+}
+
+pub fn env() -> Env {
+ Env
+}
+
+pub fn getenv(_k: &OsStr) -> io::Result<Option<OsString>> {
+ unsupported()
+}
+
+pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
+ sgx_ineffective(()) // FIXME: this could trigger a panic higher up the stack
+}
+
+pub fn unsetenv(_k: &OsStr) -> io::Result<()> {
+ sgx_ineffective(()) // FIXME: this could trigger a panic higher up the stack
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem in SGX")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(code: i32) -> ! {
+ super::abi::exit_with_code(code as _)
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids in SGX")
+}
diff --git a/src/libstd/sys/sgx/os_str.rs b/src/libstd/sys/sgx/os_str.rs
new file mode 100644
index 00000000000..9bfb84db209
--- /dev/null
+++ b/src/libstd/sys/sgx/os_str.rs
@@ -0,0 +1,189 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+/// The underlying OsString/OsStr implementation on Unix systems: just
+/// a `Vec<u8>`/`[u8]`.
+
+use borrow::Cow;
+use fmt;
+use str;
+use mem;
+use rc::Rc;
+use sync::Arc;
+use sys_common::{AsInner, IntoInner};
+use sys_common::bytestring::debug_fmt_bytestring;
+use core::str::lossy::Utf8Lossy;
+
+#[derive(Clone, Hash)]
+pub struct Buf {
+ pub inner: Vec<u8>
+}
+
+pub struct Slice {
+ pub inner: [u8]
+}
+
+impl fmt::Debug for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ debug_fmt_bytestring(&self.inner, formatter)
+ }
+}
+
+impl fmt::Display for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+ }
+}
+
+impl fmt::Debug for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl fmt::Display for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl IntoInner<Vec<u8>> for Buf {
+ fn into_inner(self) -> Vec<u8> {
+ self.inner
+ }
+}
+
+impl AsInner<[u8]> for Buf {
+ fn as_inner(&self) -> &[u8] {
+ &self.inner
+ }
+}
+
+
+impl Buf {
+ pub fn from_string(s: String) -> Buf {
+ Buf { inner: s.into_bytes() }
+ }
+
+ #[inline]
+ pub fn with_capacity(capacity: usize) -> Buf {
+ Buf {
+ inner: Vec::with_capacity(capacity)
+ }
+ }
+
+ #[inline]
+ pub fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ #[inline]
+ pub fn reserve(&mut self, additional: usize) {
+ self.inner.reserve(additional)
+ }
+
+ #[inline]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.inner.reserve_exact(additional)
+ }
+
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ #[inline]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.inner.shrink_to(min_capacity)
+ }
+
+ pub fn as_slice(&self) -> &Slice {
+ unsafe { mem::transmute(&*self.inner) }
+ }
+
+ pub fn into_string(self) -> Result<String, Buf> {
+ String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
+ }
+
+ pub fn push_slice(&mut self, s: &Slice) {
+ self.inner.extend_from_slice(&s.inner)
+ }
+
+ #[inline]
+ pub fn into_box(self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+ }
+
+ #[inline]
+ pub fn from_box(boxed: Box<Slice>) -> Buf {
+ let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Buf { inner: inner.into_vec() }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ self.as_slice().into_arc()
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ self.as_slice().into_rc()
+ }
+}
+
+impl Slice {
+ fn from_u8_slice(s: &[u8]) -> &Slice {
+ unsafe { mem::transmute(s) }
+ }
+
+ pub fn from_str(s: &str) -> &Slice {
+ Slice::from_u8_slice(s.as_bytes())
+ }
+
+ pub fn to_str(&self) -> Option<&str> {
+ str::from_utf8(&self.inner).ok()
+ }
+
+ pub fn to_string_lossy(&self) -> Cow<str> {
+ String::from_utf8_lossy(&self.inner)
+ }
+
+ pub fn to_owned(&self) -> Buf {
+ Buf { inner: self.inner.to_vec() }
+ }
+
+ #[inline]
+ pub fn into_box(&self) -> Box<Slice> {
+ let boxed: Box<[u8]> = self.inner.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ pub fn empty_box() -> Box<Slice> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ let arc: Arc<[u8]> = Arc::from(&self.inner);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ let rc: Rc<[u8]> = Rc::from(&self.inner);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
+ }
+}
diff --git a/src/libstd/sys/sgx/path.rs b/src/libstd/sys/sgx/path.rs
new file mode 100644
index 00000000000..afe0c490426
--- /dev/null
+++ b/src/libstd/sys/sgx/path.rs
@@ -0,0 +1,29 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use path::Prefix;
+use ffi::OsStr;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
+ None
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs
new file mode 100644
index 00000000000..6c6cbc14a8a
--- /dev/null
+++ b/src/libstd/sys/sgx/pipe.rs
@@ -0,0 +1,35 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ _v1: &mut Vec<u8>,
+ _p2: AnonPipe,
+ _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/src/libstd/sys/sgx/process.rs b/src/libstd/sys/sgx/process.rs
new file mode 100644
index 00000000000..01a12fba043
--- /dev/null
+++ b/src/libstd/sys/sgx/process.rs
@@ -0,0 +1,162 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ffi::OsStr;
+use fmt;
+use io;
+use sys::fs::File;
+use sys::pipe::AnonPipe;
+use sys::{unsupported, Void};
+use sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default()
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {
+ }
+
+ pub fn stdin(&mut self, _stdin: Stdio) {
+ }
+
+ pub fn stdout(&mut self, _stdout: Stdio) {
+ }
+
+ pub fn stderr(&mut self, _stderr: Stdio) {
+ }
+
+ pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ file.diverge()
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(bool);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(false);
+ pub const FAILURE: ExitCode = ExitCode(true);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
new file mode 100644
index 00000000000..2c0b1a45206
--- /dev/null
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -0,0 +1,82 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use cell::UnsafeCell;
+
+pub struct RWLock {
+ mode: UnsafeCell<isize>,
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {} // FIXME
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ mode: UnsafeCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ let mode = self.mode.get();
+ if *mode >= 0 {
+ *mode += 1;
+ } else {
+ rtabort!("rwlock locked for writing");
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ let mode = self.mode.get();
+ if *mode >= 0 {
+ *mode += 1;
+ true
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ let mode = self.mode.get();
+ if *mode == 0 {
+ *mode = -1;
+ } else {
+ rtabort!("rwlock locked for reading")
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ let mode = self.mode.get();
+ if *mode == 0 {
+ *mode = -1;
+ true
+ } else {
+ false
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ *self.mode.get() -= 1;
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ *self.mode.get() += 1;
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ }
+}
diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs
new file mode 100644
index 00000000000..0176b748a87
--- /dev/null
+++ b/src/libstd/sys/sgx/stack_overflow.rs
@@ -0,0 +1,23 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {
+}
+
+pub unsafe fn cleanup() {
+}
diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs
new file mode 100644
index 00000000000..540599a3596
--- /dev/null
+++ b/src/libstd/sys/sgx/stdio.rs
@@ -0,0 +1,73 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use io;
+use sys::unsupported;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> {
+ Ok(Stdin)
+ }
+
+ pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> {
+ unsupported()
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> {
+ Ok(Stdout)
+ }
+
+ pub fn write(&self, _data: &[u8]) -> io::Result<usize> {
+ unsupported()
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> {
+ Ok(Stderr)
+ }
+
+ pub fn write(&self, _data: &[u8]) -> io::Result<usize> {
+ unsupported()
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ (&*self).write(data)
+ }
+ fn flush(&mut self) -> io::Result<()> {
+ (&*self).flush()
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+ true
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ super::abi::panic::SgxPanicOutput::new()
+}
diff --git a/src/libstd/sys/sgx/thread.rs b/src/libstd/sys/sgx/thread.rs
new file mode 100644
index 00000000000..ff8df12302c
--- /dev/null
+++ b/src/libstd/sys/sgx/thread.rs
@@ -0,0 +1,51 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use boxed::FnBox;
+use ffi::CStr;
+use io;
+use sys::{unsupported, Void};
+use time::Duration;
+
+pub struct Thread(Void);
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(_stack: usize, _p: Box<dyn FnBox()>)
+ -> io::Result<Thread>
+ {
+ unsupported()
+ }
+
+ pub fn yield_now() {
+ // do nothing
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // nope
+ }
+
+ pub fn sleep(_dur: Duration) {
+ panic!("can't sleep");
+ }
+
+ pub fn join(self) {
+ match self.0 {}
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+ pub unsafe fn deinit() {}
+}
diff --git a/src/libstd/sys/sgx/thread_local.rs b/src/libstd/sys/sgx/thread_local.rs
new file mode 100644
index 00000000000..2126e0a853e
--- /dev/null
+++ b/src/libstd/sys/sgx/thread_local.rs
@@ -0,0 +1,50 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use boxed::Box;
+use ptr;
+
+pub type Key = usize;
+
+struct Allocated {
+ value: *mut u8,
+ dtor: Option<unsafe extern fn(*mut u8)>,
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
+ Box::into_raw(Box::new(Allocated {
+ value: ptr::null_mut(),
+ dtor,
+ })) as usize
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ (*(key as *mut Allocated)).value = value;
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ (*(key as *mut Allocated)).value
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+ let key = Box::from_raw(key as *mut Allocated);
+ if let Some(f) = key.dtor {
+ f(key.value);
+ }
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/src/libstd/sys/sgx/time.rs b/src/libstd/sys/sgx/time.rs
new file mode 100644
index 00000000000..894680b0b65
--- /dev/null
+++ b/src/libstd/sys/sgx/time.rs
@@ -0,0 +1,61 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use time::Duration;
+use sys::unsupported_err;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(Duration);
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(Duration);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+
+impl Instant {
+ pub fn now() -> Instant {
+ panic!("{}", unsupported_err());
+ }
+
+ pub fn sub_instant(&self, other: &Instant) -> Duration {
+ self.0 - other.0
+ }
+
+ pub fn add_duration(&self, other: &Duration) -> Instant {
+ Instant(self.0 + *other)
+ }
+
+ pub fn sub_duration(&self, other: &Duration) -> Instant {
+ Instant(self.0 - *other)
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ panic!("{}", unsupported_err());
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+ }
+
+ pub fn add_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime(self.0 + *other)
+ }
+
+ pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+ self.0.checked_add(*other).map(|d| SystemTime(d))
+ }
+
+ pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime(self.0 - *other)
+ }
+}
diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs
index 4b8cde3d1f4..881794d9f16 100644
--- a/src/libstd/sys_common/mod.rs
+++ b/src/libstd/sys_common/mod.rs
@@ -57,9 +57,11 @@ pub mod bytestring;
pub mod process;
cfg_if! {
- if #[cfg(any(target_os = "cloudabi", target_os = "l4re", target_os = "redox"))] {
- pub use sys::net;
- } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
+ if #[cfg(any(target_os = "cloudabi",
+ target_os = "l4re",
+ target_os = "redox",
+ all(target_arch = "wasm32", not(target_os = "emscripten")),
+ target_env = "sgx"))] {
pub use sys::net;
} else {
pub mod net;
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index 7c26d042a7c..b8711a69147 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -1018,10 +1018,12 @@ fn use_color(opts: &TestOpts) -> bool {
}
}
-#[cfg(any(target_os = "cloudabi", target_os = "redox",
- all(target_arch = "wasm32", not(target_os = "emscripten"))))]
+#[cfg(any(target_os = "cloudabi",
+ target_os = "redox",
+ all(target_arch = "wasm32", not(target_os = "emscripten")),
+ target_env = "sgx"))]
fn stdout_isatty() -> bool {
- // FIXME: Implement isatty on Redox
+ // FIXME: Implement isatty on Redox and SGX
false
}
#[cfg(unix)]
@@ -1246,7 +1248,7 @@ fn get_concurrency() -> usize {
1
}
- #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))]
+ #[cfg(any(all(target_arch = "wasm32", not(target_os = "emscripten")), target_env = "sgx"))]
fn num_cpus() -> usize {
1
}
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
index 954eb9d6d03..eb53332ab33 100644
--- a/src/libunwind/lib.rs
+++ b/src/libunwind/lib.rs
@@ -26,7 +26,10 @@ mod macros;
cfg_if! {
if #[cfg(target_env = "msvc")] {
// no extra unwinder support needed
- } else if #[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] {
+ } else if #[cfg(any(
+ all(target_arch = "wasm32", not(target_os = "emscripten")),
+ target_env = "sgx"
+ ))] {
// no unwinder on the system!
} else {
extern crate libc;
diff --git a/src/rust-sgx b/src/rust-sgx
new file mode 160000
+Subproject 9656260888095f44830641ca7bb3da609a79345
diff --git a/src/rustc/fortanix-sgx-abi_shim/Cargo.toml b/src/rustc/fortanix-sgx-abi_shim/Cargo.toml
new file mode 100644
index 00000000000..fd81d3db3a7
--- /dev/null
+++ b/src/rustc/fortanix-sgx-abi_shim/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "fortanix-sgx-abi"
+version = "0.0.0"
+authors = ["The Rust Project Developers"]
+
+[lib]
+path = "../../rust-sgx/fortanix-sgx-abi/src/lib.rs"
+test = false
+bench = false
+doc = false
+
+[dependencies]
+core = { path = "../../libcore" }
+compiler_builtins = { path = "../../rustc/compiler_builtins_shim" }
diff --git a/src/stdsimd b/src/stdsimd
-Subproject 0309be1ade6bf61066f2c69f77ac3567b7dc31b
+Subproject 5e628c5120c619a22799187371f057ec41e06f8
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 700103d35d8..53db589beaf 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -76,6 +76,7 @@ fn filter_dirs(path: &Path) -> bool {
"src/tools/lldb",
"src/target",
"src/stdsimd",
+ "src/rust-sgx",
"target",
"vendor",
];