Skip to content

Commit 5e49856

Browse files
committed
Auto merge of #176 - alexcrichton:probestack2, r=alexcrichton
Tweak definition of probestack functions It looks like the old `__rust_probestack` routine is incompatible with newer linux kernels. My best guess for this is that the kernel's auto-growth logic is failing to trigger, causing what looks like a legitimate segfault to get delivered. My best guess for why *that's* happening is that the faulting address is below `%rsp`, whereas previously all faulting stack addresses were above `%rsp`. The probestack routine does not modify `%rsp` as it's probing the stack, and presumably newer kernels are interpreting this as a legitimate violation. This commit tweaks the probestack routine to instead update `%rsp` incrementally as probing happens. The ABI of the function, however, requires that `%rsp` isn't changed as part of the function so it's restored at the end to the previous value.
2 parents e9b258b + 91eaa85 commit 5e49856

File tree

6 files changed

+51
-36
lines changed

6 files changed

+51
-36
lines changed

build.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@ fn main() {
2121
#[cfg(feature = "gen-tests")]
2222
tests::generate();
2323

24-
// Build missing intrinsics from compiler-rt C source code
25-
#[cfg(feature = "c")]
26-
c::compile(&llvm_target);
24+
// Build missing intrinsics from compiler-rt C source code. If we're
25+
// mangling names though we assume that we're also in test mode so we don't
26+
// build anything and we rely on the upstream implementation of compiler-rt
27+
// functions
28+
if !cfg!(feature = "mangled-names") {
29+
#[cfg(feature = "c")]
30+
c::compile(&llvm_target);
31+
}
2732

2833
// To compile intrinsics.rs for thumb targets, where there is no libc
2934
if llvm_target[0].starts_with("thumb") {
@@ -4099,11 +4104,9 @@ mod c {
40994104
// also needs to satisfy intrinsics that jemalloc or C in general may
41004105
// need, so include a few more that aren't typically needed by
41014106
// LLVM/Rust.
4102-
if env::var_os("CARGO_FEATURE_RUSTBUILD").is_some() {
4103-
sources.extend(&[
4104-
"ffsdi2.c",
4105-
]);
4106-
}
4107+
sources.extend(&[
4108+
"ffsdi2.c",
4109+
]);
41074110

41084111
if target_os != "ios" {
41094112
sources.extend(

ci/run.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ for rlib in $(echo $path); do
9393
uniq -d | \
9494
grep -v __x86.get_pc_thunk | \
9595
grep -v __builtin_cl | \
96+
grep -v __builtin_ctz | \
9697
grep 'T __'
9798

9899
if test $? = 0; then

examples/intrinsics.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#![feature(lang_items)]
1414
#![feature(start)]
1515
#![feature(i128_type)]
16+
#![feature(global_allocator)]
17+
#![feature(allocator_api)]
1618
#![cfg_attr(windows, feature(panic_unwind))]
1719
#![no_std]
1820

@@ -22,6 +24,10 @@ extern crate compiler_builtins;
2224
#[cfg(windows)]
2325
extern crate panic_unwind;
2426

27+
#[cfg(not(thumb))]
28+
#[global_allocator]
29+
static A: alloc_system::System = alloc_system::System;
30+
2531
// NOTE cfg(not(thumbv6m)) means that the operation is not supported on ARMv6-M at all. Not even
2632
// compiler-rt provides a C/assembly implementation.
2733

src/float/conv.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,9 @@ intrinsics! {
112112
int_to_float!(i, u32, f64)
113113
}
114114

115-
#[use_c_shim_if(all(any(target_arch = "x86", target_arch = "x86_64"),
116-
not(windows)))]
115+
#[use_c_shim_if(all(not(target_env = "msvc"),
116+
any(target_arch = "x86",
117+
all(not(windows), target_arch = "x86_64"))))]
117118
#[arm_aeabi_alias = __aeabi_ul2d]
118119
pub extern "C" fn __floatundidf(i: u64) -> f64 {
119120
int_to_float!(i, u64, f64)

src/probestack.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
#![cfg(not(windows))] // Windows already has builtins to do this
4545

4646
#[naked]
47-
#[no_mangle]
47+
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
4848
#[cfg(target_arch = "x86_64")]
4949
pub unsafe extern fn __rust_probestack() {
5050
// Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
@@ -53,36 +53,41 @@ pub unsafe extern fn __rust_probestack() {
5353
// The ABI here is that the stack frame size is located in `%eax`. Upon
5454
// return we're not supposed to modify `%esp` or `%eax`.
5555
asm!("
56-
lea 8(%rsp),%r11 // rsp before calling this routine -> r11
56+
mov %rax,%r11 // duplicate %rax as we're clobbering %r11
5757
58-
// Main loop, taken in one page increments. We're decrementing r11 by
58+
// Main loop, taken in one page increments. We're decrementing rsp by
5959
// a page each time until there's less than a page remaining. We're
6060
// guaranteed that this function isn't called unless there's more than a
61-
// page needed
61+
// page needed.
62+
//
63+
// Note that we're also testing against `8(%rsp)` to account for the 8
64+
// bytes pushed on the stack orginally with our return address. Using
65+
// `8(%rsp)` simulates us testing the stack pointer in the caller's
66+
// context.
6267
2:
68+
sub $$0x1000,%rsp
69+
test %rsp,8(%rsp)
6370
sub $$0x1000,%r11
64-
test %r11,(%r11)
65-
sub $$0x1000,%rax
66-
cmp $$0x1000,%rax
71+
cmp $$0x1000,%r11
6772
ja 2b
6873
6974
// Finish up the last remaining stack space requested, getting the last
70-
// bits out of rax
71-
sub %rax,%r11
72-
test %r11,(%r11)
75+
// bits out of r11
76+
sub %r11,%rsp
77+
test %rsp,8(%rsp)
7378
74-
// We now know that %r11 is (%rsp + 8 - %rax) so to recover rax
75-
// we calculate (%rsp + 8) - %r11 which will give us %rax
76-
lea 8(%rsp),%rax
77-
sub %r11,%rax
79+
// Restore the stack pointer to what it previously was when entering
80+
// this function. The caller will readjust the stack pointer after we
81+
// return.
82+
add %rax,%rsp
7883
7984
ret
8085
");
8186
::core::intrinsics::unreachable();
8287
}
8388

8489
#[naked]
85-
#[no_mangle]
90+
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
8691
#[cfg(target_arch = "x86")]
8792
pub unsafe extern fn __rust_probestack() {
8893
// This is the same as x86_64 above, only translated for 32-bit sizes. Note
@@ -92,19 +97,18 @@ pub unsafe extern fn __rust_probestack() {
9297
// The ABI here is the same as x86_64, except everything is 32-bits large.
9398
asm!("
9499
push %ecx
95-
lea 8(%esp),%ecx
100+
mov %eax,%ecx
96101
2:
102+
sub $$0x1000,%esp
103+
test %esp,8(%esp)
97104
sub $$0x1000,%ecx
98-
test %ecx,(%ecx)
99-
sub $$0x1000,%eax
100-
cmp $$0x1000,%eax
105+
cmp $$0x1000,%ecx
101106
ja 2b
102107
103-
sub %eax,%ecx
104-
test %ecx,(%ecx)
108+
sub %ecx,%esp
109+
test %esp,8(%esp)
105110
106-
lea 8(%esp),%eax
107-
sub %ecx,%eax
111+
add %eax,%esp
108112
pop %ecx
109113
ret
110114
");

src/x86_64.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use core::intrinsics;
1010

1111
#[cfg(windows)]
1212
#[naked]
13-
#[no_mangle]
13+
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
1414
pub unsafe fn ___chkstk_ms() {
1515
asm!("push %rcx
1616
push %rax
@@ -34,7 +34,7 @@ pub unsafe fn ___chkstk_ms() {
3434

3535
#[cfg(windows)]
3636
#[naked]
37-
#[no_mangle]
37+
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
3838
pub unsafe fn __alloca() {
3939
asm!("mov %rcx,%rax // x64 _alloca is a normal function with parameter in rcx
4040
jmp ___chkstk // Jump to ___chkstk since fallthrough may be unreliable");
@@ -43,7 +43,7 @@ pub unsafe fn __alloca() {
4343

4444
#[cfg(windows)]
4545
#[naked]
46-
#[no_mangle]
46+
#[cfg_attr(not(feature = "mangled-names"), no_mangle)]
4747
pub unsafe fn ___chkstk() {
4848
asm!("push %rcx
4949
cmp $$0x1000,%rax

0 commit comments

Comments
 (0)