mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
[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.
This commit is contained in:
parent
fdb3ec206e
commit
131fafa7da
@ -1,3 +1,16 @@
|
||||
2010-06-23 Carlos O'Donell <carlos@codesourcery.com>
|
||||
|
||||
* 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 <schwab@redhat.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/hppa/nptl/pthread.h: Update to agree
|
||||
|
@ -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)
|
||||
|
@ -26,26 +26,57 @@
|
||||
#include <ucontext.h>
|
||||
|
||||
/* 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)
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user