rt: Make __morestack (without unwinding) work on 32-bit linux

This commit is contained in:
Brian Anderson 2011-11-21 18:52:12 -08:00
parent a69c5617f0
commit 6bdf347418
10 changed files with 112 additions and 31 deletions

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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 *

View File

@ -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 *

View File

@ -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;

View File

@ -0,0 +1,12 @@
// xfail-test
fn getbig(i: int) {
if i != 0 {
getbig(i - 1);
} else {
fail;
}
}
fn main() {
getbig(10000000);
}

View File

@ -0,0 +1,10 @@
// xfail-test
fn getbig(i: int) {
if i != 0 {
getbig(i - 1);
}
}
fn main() {
getbig(10000000);
}

View File

@ -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);
}