Skip to content

Commit f9f6bd0

Browse files
committed
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.
1 parent e9b258b commit f9f6bd0

File tree

1 file changed

+25
-21
lines changed

1 file changed

+25
-21
lines changed

src/probestack.rs

+25-21
Original file line numberDiff line numberDiff line change
@@ -53,28 +53,33 @@ 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
");
@@ -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
");

0 commit comments

Comments
 (0)