Skip to content

Commit e0d5bc1

Browse files
committed
Export SGX libunwind dependencies
1 parent 484e21e commit e0d5bc1

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

src/libstd/sys/sgx/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod stack_overflow;
3030
pub mod thread;
3131
pub mod thread_local;
3232
pub mod time;
33+
pub mod unwind;
3334
pub mod stdio;
3435

3536
pub use crate::sys_common::os_str_bytes as os_str;

src/libstd/sys/sgx/unwind.rs

+155
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//! This module consists of functions needed by the SGX port of libunwind.
2+
//! Since SGX does not have any libc it must link against some other
3+
//! implementation of the things it needs access to.
4+
//!
5+
//! This causes a circular dependency between `libunwind.a` and `libstd.rlib`.
6+
//! So this code must be placed somewhere that allows it to be present
7+
//! when libunwind happens to be linked.
8+
9+
#[cfg(not(test))]
10+
use crate::{
11+
alloc::{self, Layout},
12+
lock_api::RawRwLock as _,
13+
slice, str,
14+
sync::atomic::Ordering,
15+
};
16+
use crate::{parking_lot::RawRwLock, sync::atomic::AtomicBool};
17+
18+
#[cfg(not(test))]
19+
const EINVAL: i32 = 22;
20+
21+
#[repr(C)]
22+
pub struct RwLock {
23+
lock: RawRwLock,
24+
is_write_locked: AtomicBool,
25+
}
26+
27+
// used by libunwind port
28+
#[cfg(not(test))]
29+
#[no_mangle]
30+
pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RwLock) -> i32 {
31+
if p.is_null() {
32+
return EINVAL;
33+
}
34+
(*p).lock.lock_shared();
35+
return 0;
36+
}
37+
38+
#[cfg(not(test))]
39+
#[no_mangle]
40+
pub unsafe extern "C" fn __rust_rwlock_wrlock(p: *mut RwLock) -> i32 {
41+
if p.is_null() {
42+
return EINVAL;
43+
}
44+
(*p).lock.lock_exclusive();
45+
(*p).is_write_locked.store(true, Ordering::Relaxed);
46+
return 0;
47+
}
48+
#[cfg(not(test))]
49+
#[no_mangle]
50+
pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RwLock) -> i32 {
51+
if p.is_null() {
52+
return EINVAL;
53+
}
54+
if (*p)
55+
.is_write_locked
56+
.compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
57+
.is_ok()
58+
{
59+
(*p).lock.unlock_exclusive()
60+
} else {
61+
(*p).lock.unlock_shared();
62+
}
63+
return 0;
64+
}
65+
66+
// the following functions are also used by the libunwind port. They're
67+
// included here to make sure parallel codegen and LTO don't mess things up.
68+
#[cfg(not(test))]
69+
#[no_mangle]
70+
pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
71+
if s < 0 {
72+
return;
73+
}
74+
let buf = slice::from_raw_parts(m as *const u8, s as _);
75+
if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
76+
eprint!("{}", s);
77+
}
78+
}
79+
80+
#[cfg(not(test))]
81+
#[no_mangle]
82+
// NB. used by both libunwind and libpanic_abort
83+
pub unsafe extern "C" fn __rust_abort() {
84+
crate::sys::abort_internal();
85+
}
86+
87+
#[cfg(not(test))]
88+
#[no_mangle]
89+
pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
90+
alloc::alloc(Layout::from_size_align_unchecked(size, align))
91+
}
92+
93+
#[cfg(not(test))]
94+
#[no_mangle]
95+
pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
96+
alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
97+
}
98+
99+
#[cfg(test)]
100+
mod tests {
101+
use super::*;
102+
use crate::mem::{self, MaybeUninit};
103+
use core::array::FixedSizeArray;
104+
105+
// Verify that the bytes of an initialized RwLock are the same as in
106+
// libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to
107+
// be changed too.
108+
#[test]
109+
fn test_c_rwlock_initializer() {
110+
/// The value of a newly initialized `RwLock`. Which happens to be
111+
/// `RawRwLock::INIT` (a zeroed `usize`), a false boolean (zero)
112+
/// and then padding.
113+
const RWLOCK_INIT: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
114+
115+
#[inline(never)]
116+
fn zero_stack() {
117+
test::black_box(MaybeUninit::<[RwLock; 16]>::zeroed());
118+
}
119+
120+
#[inline(never)]
121+
unsafe fn rwlock_new(init: &mut MaybeUninit<RwLock>) {
122+
use crate::lock_api::RawRwLock as _;
123+
init.write(RwLock {
124+
lock: RawRwLock::INIT,
125+
is_write_locked: AtomicBool::new(false),
126+
});
127+
}
128+
129+
unsafe {
130+
// try hard to make sure that the padding/unused bytes in RwLock
131+
// get initialized as 0. If the assertion below fails, that might
132+
// just be an issue with the test code and not with the value of
133+
// RWLOCK_INIT.
134+
zero_stack();
135+
let mut init = MaybeUninit::<RwLock>::zeroed();
136+
rwlock_new(&mut init);
137+
assert_eq!(
138+
mem::transmute::<_, [u8; 16]>(init.assume_init()).as_slice(),
139+
RWLOCK_INIT
140+
)
141+
};
142+
}
143+
144+
#[test]
145+
fn test_rwlock_memory_layout() {
146+
assert_eq!(mem::size_of::<RwLock>(), mem::size_of::<usize>() * 2);
147+
assert_eq!(mem::align_of::<RwLock>(), mem::align_of::<usize>());
148+
}
149+
150+
#[test]
151+
fn test_sgx_on_64bit() {
152+
#[cfg(target_pointer_width = "32")]
153+
panic!("The RwLock implementation for SGX only works on 64 bit architectures for now");
154+
}
155+
}

0 commit comments

Comments
 (0)