From 131fafa7dac6437fd6bb320bac49b0198825b192 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Wed, 23 Jun 2010 17:03:11 -0400 Subject: [PATCH] [hppa] Fix *context stack usage for varargs The getcontext, and setcontext functions should not adjust the stack, and should load the stack pointer from the machine context. Calling makecontext should create a frame for spilled incoming arguments, and sync uc_stack.ss_sp to the machine context. We do not support calling getcontext, modifying ss_sp, and calling setcontext directly. --- ChangeLog.hppa | 13 ++++++++ sysdeps/unix/sysv/linux/hppa/getcontext.S | 21 +++++++----- sysdeps/unix/sysv/linux/hppa/makecontext.c | 53 ++++++++++++++++++++++-------- sysdeps/unix/sysv/linux/hppa/setcontext.S | 16 +++++---- 4 files changed, 75 insertions(+), 28 deletions(-) diff --git a/ChangeLog.hppa b/ChangeLog.hppa index 50a15d7..faad5e9 100644 --- a/ChangeLog.hppa +++ b/ChangeLog.hppa @@ -1,3 +1,16 @@ +2010-06-23 Carlos O'Donell + + * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext_ret): + Document that this function is a non-standard calling ABI. + Document register usage. + (__getcontext): Use normal %sp without adjustment. Use named + resgister %sp. + * sysdeps/unix/sysv/linux/hppa/makecontext.c: Remove FRAME_SIZE. + Define FRAME_SIZE_UL, FRAME_SIZE_BYTES, ARGS. + (__makecontext): Create and setup a stack frame. + * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): + Use named register %sp. Do not use oSS_SP. + 2010-06-07 Andreas Schwab * sysdeps/unix/sysv/linux/hppa/nptl/pthread.h: Update to agree diff --git a/sysdeps/unix/sysv/linux/hppa/getcontext.S b/sysdeps/unix/sysv/linux/hppa/getcontext.S index f88fa03..af810b3 100644 --- a/sysdeps/unix/sysv/linux/hppa/getcontext.S +++ b/sysdeps/unix/sysv/linux/hppa/getcontext.S @@ -23,17 +23,21 @@ #include "ucontext_i.h" - /* Trampoline function. */ + /* Trampoline function. Non-standard calling ABI. */ /* Can not use ENTRY(__getcontext_ret) here. */ .type __getcontext_ret, @function .hidden __getcontext_ret __getcontext_ret: .proc .callinfo FRAME=0,NO_CALLS + /* r26-r23 contain original r3-r6, but because setcontext + does not reload r3-r6 (it's using them as temporaries) + we must save them elsewhere and swap them back in. */ copy %r23, %r3 copy %r24, %r4 copy %r25, %r5 copy %r26, %r6 + /* r20 contains original return pointer. */ bv 0(%r20) copy %r0, %ret0 .procend @@ -72,13 +76,12 @@ ENTRY(__getcontext) stw %r27, oR27(%r26) stw %r28, oR28(%r26) stw %r29, oR29(%r26) - ldo -64(%sp), %r1 /* Calculate %sp in %r1. */ - stw %r1, oR30(%r26) /* Save new %sp. */ + stw %sp, oR30(%r26) stw %r31, oR31(%r26) stw %r0, oUC_FLAGS(%r26) /* stw %r0, oUC_LINK(%r26) - Do not overwrite. */ - stw %r1, oSS_SP(%r26) + stw %sp, oSS_SP(%r26) stw %r0, oSS_FLAGS(%r26) stw %r0, oSS_SIZE(%r26) @@ -127,9 +130,9 @@ ENTRY(__getcontext) fstds %fr31, 0(%r1) /* Prologue */ - stwm %r4, 64(%r30) + stwm %r4, 64(%sp) #ifdef PIC - stw %r19, -32(%r30) + stw %r19, -32(%sp) #endif /* Set up the trampoline registers. @@ -152,12 +155,12 @@ ENTRY(__getcontext) ldi SIG_BLOCK, %r26 /* Epilogue */ - ldw -84(%r30), %r2 + ldw -84(%sp), %r2 #ifdef PIC - ldw -96(%r30), %r19 + ldw -96(%sp), %r19 #endif bv %r0(%r2) - ldwm -64(%r30), %r4 + ldwm -64(%sp), %r4 END(__getcontext) weak_alias (__getcontext, getcontext) diff --git a/sysdeps/unix/sysv/linux/hppa/makecontext.c b/sysdeps/unix/sysv/linux/hppa/makecontext.c index cb036d0..d3e3fb8 100644 --- a/sysdeps/unix/sysv/linux/hppa/makecontext.c +++ b/sysdeps/unix/sysv/linux/hppa/makecontext.c @@ -26,26 +26,57 @@ #include /* POSIX only supports integer arguments. */ + +/* Stack must be 64-byte aligned at all times. */ #define STACK_ALIGN 64 -#define FRAME_SIZE 8 +/* Size of frame marker in unsigned long words. */ +#define FRAME_SIZE_UL 8 +/* Size of frame marker in bytes. */ +#define FRAME_SIZE_BYTES (8 * sizeof(unsigned long)) +/* Size of X arguments in bytes. */ +#define ARGS(x) (x * sizeof(unsigned long)) void __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) { - unsigned long *sp; + unsigned long *sp, *osp; va_list ap; int i; - /* Get stack pointer (64-byte aligned). */ - sp = (unsigned long *)((((unsigned long) ucp->uc_stack.ss_sp) - + FRAME_SIZE + argc + STACK_ALIGN) - & ~(STACK_ALIGN - 1)); + /* Create a 64-byte aligned frame to store args. Use ss_sp if + it is available, otherwise be robust and use the currently + saved stack pointer. */ + if (ucp->uc_stack.ss_sp && ucp->uc_stack.ss_size) + osp = (unsigned long *)ucp->uc_stack.ss_sp; + else + osp = (unsigned long *)ucp->uc_mcontext.sc_gr[30]; + + sp = (unsigned long *)((((unsigned long) osp) + + FRAME_SIZE_BYTES + ARGS(argc) + STACK_ALIGN) + & ~(STACK_ALIGN - 1)); + + /* Use new frame. */ + ucp->uc_mcontext.sc_gr[30] = ((unsigned long) sp); + + /* Finish frame setup. */ + if (ucp->uc_link) + { + /* Returning to the next context and next frame. */ + sp[-4/sizeof(unsigned long)] = ucp->uc_link->uc_mcontext.sc_gr[30]; + sp[-20/sizeof(unsigned long)] = ucp->uc_link->uc_mcontext.sc_gr[2]; + } + else + { + /* This is the main context. No frame marker, and no return address. */ + sp[-4/sizeof(unsigned long)] = 0x0; + sp[-20/sizeof(unsigned long)] = 0x0; + } /* Store address to jump to. */ ucp->uc_mcontext.sc_gr[2] = (unsigned long) func; + /* Process arguments. */ va_start (ap, argc); - /* Handle arguments. */ for (i = 0; i < argc; ++i) { if (i < 4) @@ -62,13 +93,9 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc, ...) } /* All other arguments go on the stack. */ - sp[-1 * (FRAME_SIZE + 1 + i)] = va_arg (ap, int); + sp[-1 * (FRAME_SIZE_UL + 1 + i)] = va_arg (ap, int); } va_end (ap); - - /* Adjust the stack pointer to last used argument. */ - ucp->uc_mcontext.sc_gr[30] = (unsigned long) sp; } - - weak_alias(__makecontext, makecontext) + diff --git a/sysdeps/unix/sysv/linux/hppa/setcontext.S b/sysdeps/unix/sysv/linux/hppa/setcontext.S index 43ccf24..3353d4e 100644 --- a/sysdeps/unix/sysv/linux/hppa/setcontext.S +++ b/sysdeps/unix/sysv/linux/hppa/setcontext.S @@ -25,9 +25,9 @@ ENTRY(__setcontext) /* Prologue */ - stwm %r3, 64(%r30) + stwm %r3, 64(%sp) #ifdef PIC - stw %r19, -32(%r30) + stw %r19, -32(%sp) #endif /* Save ucp. */ @@ -78,7 +78,7 @@ ENTRY(__setcontext) ldw oR27(%r3), %r27 ldw oR28(%r3), %r28 ldw oR29(%r3), %r29 - ldw oR30(%r3), %r30 + ldw oR30(%r3), %sp /* ldw oR31(%r3), %r31 - dyncall scratch register */ /* Restore floating-point registers. */ @@ -116,9 +116,13 @@ ENTRY(__setcontext) fldds,mb -8(%r22), %fr1 fldds,mb -8(%r22), %fr0 - /* Calculate new stack pointer. */ - ldw oSS_SP(%r3), %sp - ldo 64(%sp), %sp + /* Do not load oSS_SP into %sp. The value of oSS_SP indicates + the start of the user allocated stack, but not the sp that + should be used by the new context. In fact makecontext + will create a frame, and adjust sp as required. We do not + support calling getcontext and modifying ss_sp without + a call to makecontext to synchronize ss_sp into the machine + context. */ /* Call external function. */ copy %r2, %r22 -- 2.7.4