rt: Make __morestack (without unwinding) work on 32-bit linux
This commit is contained in:
parent
a69c5617f0
commit
6bdf347418
3
mk/rt.mk
3
mk/rt.mk
|
@ -67,7 +67,8 @@ RUNTIME_CS_$(1) := \
|
|||
|
||||
RUNTIME_S_$(1) := rt/arch/$$(HOST_$(1))/_context.S \
|
||||
rt/arch/$$(HOST_$(1))/ccall.S \
|
||||
rt/arch/$$(HOST_$(1))/morestack.S
|
||||
rt/arch/$$(HOST_$(1))/morestack.S \
|
||||
rt/arch/$$(HOST_$(1))/record_sp.S
|
||||
|
||||
RUNTIME_HDR_$(1) := rt/globals.h \
|
||||
rt/rust.h \
|
||||
|
|
|
@ -29,6 +29,14 @@
|
|||
#define ALIGNMENT 8
|
||||
#endif
|
||||
|
||||
#if defined (__APPLE__) || defined(_WIN32)
|
||||
#define NEW_STACK_ADDR rust_new_stack_sym-.L$pic_ref_pt_0(%eax)
|
||||
#define DEL_STACK_ADDR rust_del_stack_sym-.L$pic_ref_pt_1(%edx)
|
||||
#else
|
||||
#define NEW_STACK_ADDR $rust_new_stack
|
||||
#define DEL_STACK_ADDR $rust_del_stack
|
||||
#endif
|
||||
|
||||
#define RETURN_OFFSET 7
|
||||
|
||||
.globl RUST_NEW_STACK
|
||||
|
@ -39,6 +47,10 @@
|
|||
.globl UPCALL_CALL_C_STACK
|
||||
.globl MORESTACK
|
||||
|
||||
#ifdef __ELF__
|
||||
.type MORESTACK,@function
|
||||
#endif
|
||||
|
||||
MORESTACK:
|
||||
|
||||
// Sanity check to make sure that there is a currently-running task.
|
||||
|
@ -47,34 +59,33 @@ MORESTACK:
|
|||
testl %eax,%eax
|
||||
jz L$bail
|
||||
|
||||
subl $12,%esp
|
||||
pushl $12
|
||||
movl $12, (%esp)
|
||||
calll UPCALL_ALLOC_C_STACK
|
||||
movl %eax,%edx
|
||||
|
||||
movl %esp, 12(%edx)
|
||||
// C stack | esp+12
|
||||
// ---------------------+-------------------------
|
||||
movl 20(%esp),%eax // | ra stksz argsz x ra args
|
||||
movl %eax,8(%edx) // argsz > | ra stksz argsz x ra args
|
||||
leal 32(%esp),%eax // argsz | ra stksz argsz x ra args
|
||||
leal 28+ALIGNMENT(%esp),%eax // argsz | ra stksz argsz x ra args
|
||||
movl %eax,4(%edx) // argp > argsz | ra stksz argsz x ra args
|
||||
movl 16(%esp),%eax // argp argsz | ra stksz argsz x ra args
|
||||
movl %eax,(%edx) // stksz > argp argsz | ra stksz argsz x ra args
|
||||
|
||||
calll L$pic_ref_pt_0
|
||||
L$pic_ref_pt_0:
|
||||
calll .L$pic_ref_pt_0
|
||||
.L$pic_ref_pt_0:
|
||||
popl %eax
|
||||
|
||||
movl rust_new_stack_sym-L$pic_ref_pt_0(%eax),%eax
|
||||
movl NEW_STACK_ADDR,%eax
|
||||
movl %eax,(%esp)
|
||||
movl %edx,4(%esp)
|
||||
calll UPCALL_CALL_C_STACK
|
||||
|
||||
movl 16(%esp),%edx // Grab the return pointer.
|
||||
movl 12(%esp),%edx // Grab the return pointer.
|
||||
addl $RETURN_OFFSET,%edx // Skip past the `add esp,4` and the `ret`.
|
||||
|
||||
movl %eax,%esp // Switch stacks.
|
||||
subl $12,%esp // Align the stack.
|
||||
calll *%edx // Re-enter the function that called us.
|
||||
|
||||
// Now the function that called us has returned, so we need to delete the
|
||||
|
@ -86,22 +97,22 @@ L$pic_ref_pt_0:
|
|||
movl $0,(%esp)
|
||||
calll UPCALL_ALLOC_C_STACK
|
||||
|
||||
calll L$pic_ref_pt_1
|
||||
L$pic_ref_pt_1:
|
||||
calll .L$pic_ref_pt_1
|
||||
.L$pic_ref_pt_1:
|
||||
popl %edx
|
||||
|
||||
movl rust_del_stack_sym-L$pic_ref_pt_1(%edx),%edx
|
||||
movl DEL_STACK_ADDR,%edx
|
||||
movl %edx,(%esp)
|
||||
movl %eax,4(%esp)
|
||||
calll UPCALL_CALL_C_STACK
|
||||
|
||||
addl $16,%esp
|
||||
retl $16 + ALIGNMENT // ra stksz argsz x ra args
|
||||
addl $12,%esp
|
||||
retl $8 // ra stksz argsz x ra args
|
||||
|
||||
L$bail:
|
||||
movl 12(%esp),%edx
|
||||
addl $RETURN_OFFSET,%edx
|
||||
addl $12+16,%esp
|
||||
addl $12+4+8+ALIGNMENT,%esp
|
||||
jmpl *%edx
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
@ -114,10 +125,5 @@ rust_del_stack_sym:
|
|||
.indirect_symbol RUST_DEL_STACK
|
||||
.long 0
|
||||
|
||||
#else
|
||||
|
||||
rust_new_stack_sym:
|
||||
rust_del_stack_sym:
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
.text
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
#define RECORD_SP _record_sp
|
||||
#else
|
||||
#define RECORD_SP record_sp
|
||||
#endif
|
||||
|
||||
.globl RECORD_SP
|
||||
|
||||
#if defined(__linux__)
|
||||
RECORD_SP:
|
||||
movl 4(%esp), %eax
|
||||
movl %eax, %gs:48
|
||||
ret
|
||||
#else
|
||||
RECORD_SP:
|
||||
ret
|
||||
#endif
|
|
@ -94,6 +94,9 @@ static size_t const BUF_BYTES = 2048;
|
|||
// The error status to use when the process fails
|
||||
#define PROC_FAIL_CODE 101;
|
||||
|
||||
// FIXME: We want this to be 128 but need to slim the red zone calls down
|
||||
#define RED_ZONE_SIZE 256
|
||||
|
||||
// Every reference counted object should use this macro and initialize
|
||||
// ref_count.
|
||||
|
||||
|
|
|
@ -367,10 +367,14 @@ rust_scheduler::init_tls() {
|
|||
tls_initialized = true;
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
record_sp(void *limit);
|
||||
|
||||
void
|
||||
rust_scheduler::place_task_in_tls(rust_task *task) {
|
||||
int result = pthread_setspecific(task_key, task);
|
||||
assert(!result && "Couldn't place the task in TLS!");
|
||||
record_sp(task->stk->data + RED_ZONE_SIZE);
|
||||
}
|
||||
|
||||
rust_task *
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "globals.h"
|
||||
|
||||
#define RED_ZONE_SIZE 128
|
||||
|
||||
// Stack size
|
||||
size_t g_custom_min_stack_size = 0;
|
||||
|
@ -63,30 +62,41 @@ del_stk(rust_task *task, stk_seg *stk)
|
|||
task->free(stk);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
record_sp(void *limit);
|
||||
|
||||
// Entry points for `__morestack` (see arch/*/morestack.S).
|
||||
extern "C" void *
|
||||
rust_new_stack(size_t stk_sz, void *args_addr, size_t args_sz) {
|
||||
std::cerr << "*** New stack!\n";
|
||||
|
||||
rust_new_stack(size_t stk_sz, void *args_addr, size_t args_sz,
|
||||
uintptr_t current_sp) {
|
||||
rust_task *task = rust_scheduler::get_task();
|
||||
if (!task)
|
||||
return NULL;
|
||||
|
||||
stk_seg *stk_seg = new_stk(task->sched, task, stk_sz);
|
||||
memcpy(stk_seg->data, args_addr, args_sz);
|
||||
return stk_seg->data;
|
||||
stk_seg *stk_seg = new_stk(task->sched, task, stk_sz + args_sz);
|
||||
|
||||
// Save the previous stack pointer so it can be restored later
|
||||
stk_seg->return_sp = current_sp;
|
||||
uint8_t *new_sp = (uint8_t*)stk_seg->limit;
|
||||
size_t sizeof_retaddr = sizeof(void*);
|
||||
// Make enough room on the new stack to hold the old stack pointer
|
||||
// in addition to the function arguments
|
||||
new_sp = align_down(new_sp - (args_sz + sizeof_retaddr));
|
||||
new_sp += sizeof_retaddr;
|
||||
memcpy(new_sp, args_addr, args_sz);
|
||||
record_sp(stk_seg->data + RED_ZONE_SIZE);
|
||||
return new_sp;
|
||||
}
|
||||
|
||||
extern "C" void
|
||||
rust_del_stack() {
|
||||
rust_task *task = rust_scheduler::get_task();
|
||||
del_stk(task, task->stk);
|
||||
record_sp(task->stk->data + RED_ZONE_SIZE);
|
||||
}
|
||||
|
||||
extern "C" void *
|
||||
extern "C" uintptr_t
|
||||
rust_get_prev_stack() {
|
||||
rust_task *task = rust_scheduler::get_task();
|
||||
return task->stk->next;
|
||||
return task->stk->return_sp;
|
||||
}
|
||||
|
||||
extern "C" rust_task *
|
||||
|
|
|
@ -26,6 +26,7 @@ struct rust_box;
|
|||
struct stk_seg {
|
||||
stk_seg *next;
|
||||
uintptr_t limit;
|
||||
uintptr_t return_sp;
|
||||
unsigned int valgrind_id;
|
||||
#ifndef _LP64
|
||||
uint32_t pad;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// xfail-test
|
||||
fn getbig(i: int) {
|
||||
if i != 0 {
|
||||
getbig(i - 1);
|
||||
} else {
|
||||
fail;
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
getbig(10000000);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// xfail-test
|
||||
fn getbig(i: int) {
|
||||
if i != 0 {
|
||||
getbig(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
getbig(10000000);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// xfail-test
|
||||
fn getbig(i: int) -> int {
|
||||
let m = if i >= 0 {
|
||||
let j = getbig(i - 1);
|
||||
let k = getbig(j - 1);
|
||||
k
|
||||
} else {
|
||||
0
|
||||
};
|
||||
m
|
||||
}
|
||||
|
||||
fn main() {
|
||||
getbig(10000000);
|
||||
}
|
Loading…
Reference in New Issue