You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
4.5 KiB
147 lines
4.5 KiB
2 years ago
|
commit c6f9085ee4e913a0b8260340ac7b75c426b780ce
|
||
|
Author: John David Anglin <danglin@gcc.gnu.org>
|
||
|
Date: Fri Feb 18 20:38:25 2022 +0000
|
||
|
|
||
|
hppa: Fix swapcontext
|
||
|
|
||
|
This change fixes the failure of stdlib/tst-setcontext2 and
|
||
|
stdlib/tst-setcontext7 on hppa. The implementation of swapcontext
|
||
|
in C is broken. C saves the return pointer (rp) and any non
|
||
|
call-clobbered registers (in this case r3, r4 and r5) on the
|
||
|
stack. However, the setcontext call in swapcontext pops the
|
||
|
stack and subsequent calls clobber the saved registers. When
|
||
|
the context in oucp is restored, both tests fault.
|
||
|
|
||
|
Here we rewrite swapcontext in assembly code to avoid using
|
||
|
the stack for register values that need to be used after
|
||
|
restoration. The getcontext and setcontext routines are
|
||
|
revised to save and restore register ret1 for normal returns.
|
||
|
We copy the oucp pointer to ret1. This allows access to
|
||
|
the old context after calling getcontext and setcontext.
|
||
|
|
||
|
(cherry picked from commit 71b108d7eb33b2bf3e61d5e92d2a47f74c1f7d96)
|
||
|
|
||
|
diff --git a/sysdeps/unix/sysv/linux/hppa/getcontext.S b/sysdeps/unix/sysv/linux/hppa/getcontext.S
|
||
|
index 1405b42819c38993..c8b690aab8ecc47c 100644
|
||
|
--- a/sysdeps/unix/sysv/linux/hppa/getcontext.S
|
||
|
+++ b/sysdeps/unix/sysv/linux/hppa/getcontext.S
|
||
|
@@ -138,6 +138,8 @@ ENTRY(__getcontext)
|
||
|
stw %r19, -32(%sp)
|
||
|
.cfi_offset 19, 32
|
||
|
#endif
|
||
|
+ stw %ret1, -60(%sp)
|
||
|
+ .cfi_offset 29, 4
|
||
|
|
||
|
/* Set up the trampoline registers.
|
||
|
r20, r23, r24, r25, r26 and r2 are clobbered
|
||
|
@@ -168,6 +170,7 @@ ENTRY(__getcontext)
|
||
|
#ifdef PIC
|
||
|
ldw -32(%sp), %r19
|
||
|
#endif
|
||
|
+ ldw -60(%sp), %ret1
|
||
|
bv %r0(%r2)
|
||
|
ldwm -64(%sp), %r4
|
||
|
END(__getcontext)
|
||
|
diff --git a/sysdeps/unix/sysv/linux/hppa/setcontext.S b/sysdeps/unix/sysv/linux/hppa/setcontext.S
|
||
|
index 8fc5f5e56cb31f51..e1ae3aefcaac198d 100644
|
||
|
--- a/sysdeps/unix/sysv/linux/hppa/setcontext.S
|
||
|
+++ b/sysdeps/unix/sysv/linux/hppa/setcontext.S
|
||
|
@@ -34,6 +34,8 @@ ENTRY(__setcontext)
|
||
|
stw %r19, -32(%sp)
|
||
|
.cfi_offset 19, 32
|
||
|
#endif
|
||
|
+ stw %ret1, -60(%sp)
|
||
|
+ .cfi_offset 29, 4
|
||
|
|
||
|
/* Save ucp. */
|
||
|
copy %r26, %r3
|
||
|
@@ -155,6 +157,7 @@ ENTRY(__setcontext)
|
||
|
#ifdef PIC
|
||
|
ldw -32(%r30), %r19
|
||
|
#endif
|
||
|
+ ldw -60(%r30), %ret1
|
||
|
bv %r0(%r2)
|
||
|
ldwm -64(%r30), %r3
|
||
|
L(pseudo_end):
|
||
|
diff --git a/sysdeps/unix/sysv/linux/hppa/swapcontext.c b/sysdeps/unix/sysv/linux/hppa/swapcontext.c
|
||
|
index f9a8207543c164cb..562f00ff0546177d 100644
|
||
|
--- a/sysdeps/unix/sysv/linux/hppa/swapcontext.c
|
||
|
+++ b/sysdeps/unix/sysv/linux/hppa/swapcontext.c
|
||
|
@@ -18,6 +18,7 @@
|
||
|
<https://www.gnu.org/licenses/>. */
|
||
|
|
||
|
#include <ucontext.h>
|
||
|
+#include "ucontext_i.h"
|
||
|
|
||
|
extern int __getcontext (ucontext_t *ucp);
|
||
|
extern int __setcontext (const ucontext_t *ucp);
|
||
|
@@ -25,17 +26,61 @@ extern int __setcontext (const ucontext_t *ucp);
|
||
|
int
|
||
|
__swapcontext (ucontext_t *oucp, const ucontext_t *ucp)
|
||
|
{
|
||
|
+ /* Save ucp in stack argument slot. */
|
||
|
+ asm ("stw %r25,-40(%sp)");
|
||
|
+ asm (".cfi_offset 25, -40");
|
||
|
+
|
||
|
+ /* Save rp for debugger. */
|
||
|
+ asm ("stw %rp,-20(%sp)");
|
||
|
+ asm (".cfi_offset 2, -20");
|
||
|
+
|
||
|
+ /* Copy rp to ret0 (r28). */
|
||
|
+ asm ("copy %rp,%ret0");
|
||
|
+
|
||
|
+ /* Create a frame. */
|
||
|
+ asm ("ldo 64(%sp),%sp");
|
||
|
+ asm (".cfi_def_cfa_offset -64");
|
||
|
+
|
||
|
/* Save the current machine context to oucp. */
|
||
|
- __getcontext (oucp);
|
||
|
+ asm ("bl __getcontext,%rp");
|
||
|
+
|
||
|
+ /* Copy oucp to register ret1 (r29). __getcontext saves and restores it
|
||
|
+ on a normal return. It is restored from oR29 on reactivation. */
|
||
|
+ asm ("copy %r26,%ret1");
|
||
|
+
|
||
|
+ /* Pop frame. */
|
||
|
+ asm ("ldo -64(%sp),%sp");
|
||
|
+ asm (".cfi_def_cfa_offset 0");
|
||
|
+
|
||
|
+ /* Load return pointer from oR28. */
|
||
|
+ asm ("ldw %0(%%ret1),%%rp" : : "i" (oR28));
|
||
|
+
|
||
|
+ /* Return if error. */
|
||
|
+ asm ("or,= %r0,%ret0,%r0");
|
||
|
+ asm ("bv,n %r0(%rp)");
|
||
|
+
|
||
|
+ /* Load sc_sar flag. */
|
||
|
+ asm ("ldw %0(%%ret1),%%r20" : : "i" (oSAR));
|
||
|
+
|
||
|
+ /* Return if oucp context has been reactivated. */
|
||
|
+ asm ("or,= %r0,%r20,%r0");
|
||
|
+ asm ("bv,n %r0(%rp)");
|
||
|
+
|
||
|
+ /* Mark sc_sar flag. */
|
||
|
+ asm ("1: ldi 1,%r20");
|
||
|
+ asm ("stw %%r20,%0(%%ret1)" : : "i" (oSAR));
|
||
|
+
|
||
|
+ /* Activate the machine context in ucp. */
|
||
|
+ asm ("bl __setcontext,%rp");
|
||
|
+ asm ("ldw -40(%sp),%r26");
|
||
|
|
||
|
- /* mark sc_sar flag to skip the setcontext call on reactivation. */
|
||
|
- if (oucp->uc_mcontext.sc_sar == 0) {
|
||
|
- oucp->uc_mcontext.sc_sar++;
|
||
|
+ /* Load return pointer. */
|
||
|
+ asm ("ldw %0(%%ret1),%%rp" : : "i" (oR28));
|
||
|
|
||
|
- /* Restore the machine context in ucp. */
|
||
|
- __setcontext (ucp);
|
||
|
- }
|
||
|
+ /* A successful call to setcontext does not return. */
|
||
|
+ asm ("bv,n %r0(%rp)");
|
||
|
|
||
|
+ /* Make gcc happy. */
|
||
|
return 0;
|
||
|
}
|
||
|
|