[hppa] Fix *context stack usage for varargs
authorCarlos O'Donell <carlos@systemhalted.org>
Wed, 23 Jun 2010 21:03:11 +0000 (17:03 -0400)
committerCarlos O'Donell <carlos@systemhalted.org>
Wed, 23 Jun 2010 21:03:11 +0000 (17:03 -0400)
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
sysdeps/unix/sysv/linux/hppa/getcontext.S
sysdeps/unix/sysv/linux/hppa/makecontext.c
sysdeps/unix/sysv/linux/hppa/setcontext.S

index 50a15d7..faad5e9 100644 (file)
@@ -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
index f88fa03..af810b3 100644 (file)
 #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)
index cb036d0..d3e3fb8 100644 (file)
 #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)
+
index 43ccf24..3353d4e 100644 (file)
@@ -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