From d1a2fa597f993d56bcfa73a64509465d56b4ffac Mon Sep 17 00:00:00 2001 From: David Lichteblau Date: Mon, 12 Nov 2012 20:13:09 +0100 Subject: [PATCH] Some support for platforms whose libraries do not maintain a frame pointer For platforms on which system libraries are built with the equivalent of -fomit-frame-pointer, i.e. do not maintain EBP, save it in the thread structure upon entry to an exception handler, and restore the register during call_into_lisp. Currently for Windows on x86-64 only, where it is required. Analogous changes had been implemented for x86, but are not included here. Thanks to Anton Kovalenko. --- src/compiler/generic/objdef.lisp | 5 +++++ src/runtime/safepoint.c | 5 +++++ src/runtime/thread.c | 5 +++++ src/runtime/win32-os.c | 18 ++++++++++++++++++ src/runtime/x86-64-assem.S | 26 +++++++++++++++++++++++++- 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/compiler/generic/objdef.lisp b/src/compiler/generic/objdef.lisp index d3bd635..fda2758 100644 --- a/src/compiler/generic/objdef.lisp +++ b/src/compiler/generic/objdef.lisp @@ -426,6 +426,11 @@ (mach-port-name :c-type "mach_port_name_t") (nonpointer-data :c-type "struct nonpointer_thread_data *" :length #!+alpha 2 #!-alpha 1) #!+(and sb-safepoint x86) (selfptr :c-type "struct thread *") + ;; Context base pointer for running on top of system libraries built using + ;; -fomit-frame-pointer. Currently truly required and implemented only + ;; for (and win32 x86-64), but could be generalized to other platforms if + ;; needed: + #!+win32 (carried-base-pointer :c-type "os_context_register_t") #!+sb-safepoint (csp-around-foreign-call :c-type "lispobj *") #!+sb-safepoint (pc-around-foreign-call :c-type "lispobj *") #!+win32 (synchronous-io-handle-and-flag :c-type "HANDLE" :length 1) diff --git a/src/runtime/safepoint.c b/src/runtime/safepoint.c index 3faabe5..8a34a08 100644 --- a/src/runtime/safepoint.c +++ b/src/runtime/safepoint.c @@ -983,6 +983,11 @@ callback_wrapper_trampoline( if (!th) lose("callback invoked in non-lisp thread. Sorry, that is not supported yet."); +#ifdef LISP_FEATURE_WIN32 + /* arg2 is the pointer to a return value, which sits on the stack */ + th->carried_base_pointer = (os_context_register_t) *(((void**)arg2)-1); +#endif + WITH_GC_AT_SAFEPOINTS_ONLY() funcall3(SymbolValue(ENTER_ALIEN_CALLBACK, 0), arg0, arg1, arg2); } diff --git a/src/runtime/thread.c b/src/runtime/thread.c index 926009c..838a187 100644 --- a/src/runtime/thread.c +++ b/src/runtime/thread.c @@ -568,7 +568,12 @@ create_thread_struct(lispobj initial_function) { th->os_thread=0; #ifdef LISP_FEATURE_SB_SAFEPOINT +# ifdef LISP_FEATURE_WIN32 + th->carried_base_pointer = 0; +# endif +# ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK th->pc_around_foreign_call = 0; +# endif th->csp_around_foreign_call = csp_page; #endif diff --git a/src/runtime/win32-os.c b/src/runtime/win32-os.c index dc502b0..49358a1 100644 --- a/src/runtime/win32-os.c +++ b/src/runtime/win32-os.c @@ -1373,6 +1373,13 @@ handle_exception(EXCEPTION_RECORD *exception_record, context.sigmask = self ? self->os_thread->blocked_signal_set : 0; #endif + os_context_register_t oldbp = NULL; + if (self) { + oldbp = self ? self->carried_base_pointer : 0; + self->carried_base_pointer + = (os_context_register_t) voidreg(win32_context, bp); + } + /* For EXCEPTION_ACCESS_VIOLATION only. */ void *fault_address = (void *)exception_record->ExceptionInformation[1]; @@ -1415,6 +1422,9 @@ handle_exception(EXCEPTION_RECORD *exception_record, /* All else failed, drop through to the lisp-side exception handler. */ signal_internal_error_or_lose(ctx, exception_record, fault_address); + if (self) + self->carried_base_pointer = oldbp; + errno = lastErrno; SetLastError(lastError); return ExceptionContinueExecution; @@ -1451,6 +1461,14 @@ veh(EXCEPTION_POINTERS *ep) } #endif +os_context_register_t +carry_frame_pointer(os_context_register_t default_value) +{ + struct thread* self = arch_os_get_current_thread(); + os_context_register_t bp = self->carried_base_pointer; + return bp ? bp : default_value; +} + void wos_install_interrupt_handlers(struct lisp_exception_frame *handler) { diff --git a/src/runtime/x86-64-assem.S b/src/runtime/x86-64-assem.S index 7c91ef0..b85639e 100644 --- a/src/runtime/x86-64-assem.S +++ b/src/runtime/x86-64-assem.S @@ -156,12 +156,23 @@ GNAME(call_into_lisp_first_time): * return values in rax rdx * callee saves rbp rbx r12-15 if it uses them */ - +#ifdef LISP_FEATURE_WIN32 +# define SUPPORT_FOMIT_FRAME_POINTER +#endif .align align_16byte,0x90 GNAME(call_into_lisp): +#ifdef SUPPORT_FOMIT_FRAME_POINTER + mov %rbp,%rax +#endif push %rbp # Save old frame pointer. mov %rsp,%rbp # Establish new frame. Lstack: +#ifdef SUPPORT_FOMIT_FRAME_POINTER + /* If called through call_into_lisp_first_time, %r15 becomes invalid + * here, but we will not return in that case. */ + push %r15 + mov %rax,%r15 +#endif /* FIXME x86 saves FPU state here */ push %rbx # these regs are callee-saved according to C push %r12 # so must be preserved and restored when @@ -176,6 +187,13 @@ Lstack: push %rsi # push %rdx # #ifdef LISP_FEATURE_SB_THREAD +# ifdef SUPPORT_FOMIT_FRAME_POINTER + mov (%rbp),%rcx + sub $32,%rsp + call GNAME(carry_frame_pointer) + add $32,%rsp + mov %rax,(%rbp) +# endif #ifdef LISP_FEATURE_GCC_TLS movq %fs:0, %rax movq GNAME(current_thread)@TPOFF(%rax), %r12 @@ -238,7 +256,13 @@ LsingleValue: /* FIXME Restore the NPX state. */ mov %rdx,%rax # c-val +#ifdef SUPPORT_FOMIT_FRAME_POINTER + mov %r15,%rbp # orig rbp + pop %r15 # orig r15 + add $8,%rsp # no need for saved (overridden) rbp +#else leave +#endif ret SIZE(GNAME(call_into_lisp)) -- 1.7.10.4