mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-11 11:50:06 +00:00
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.
This commit is contained in:
parent
c627209832
commit
71b108d7eb
@ -137,6 +137,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
|
||||
@ -167,6 +169,7 @@ ENTRY(__getcontext)
|
||||
#ifdef PIC
|
||||
ldw -32(%sp), %r19
|
||||
#endif
|
||||
ldw -60(%sp), %ret1
|
||||
bv %r0(%r2)
|
||||
ldwm -64(%sp), %r4
|
||||
END(__getcontext)
|
||||
|
@ -33,6 +33,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
|
||||
@ -154,6 +156,7 @@ ENTRY(__setcontext)
|
||||
#ifdef PIC
|
||||
ldw -32(%r30), %r19
|
||||
#endif
|
||||
ldw -60(%r30), %ret1
|
||||
bv %r0(%r2)
|
||||
ldwm -64(%r30), %r3
|
||||
L(pseudo_end):
|
||||
|
@ -17,6 +17,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);
|
||||
@ -24,17 +25,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");
|
||||
|
||||
/* mark sc_sar flag to skip the setcontext call on reactivation. */
|
||||
if (oucp->uc_mcontext.sc_sar == 0) {
|
||||
oucp->uc_mcontext.sc_sar++;
|
||||
/* 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");
|
||||
|
||||
/* Restore the machine context in ucp. */
|
||||
__setcontext (ucp);
|
||||
}
|
||||
/* 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");
|
||||
|
||||
/* Load return pointer. */
|
||||
asm ("ldw %0(%%ret1),%%rp" : : "i" (oR28));
|
||||
|
||||
/* A successful call to setcontext does not return. */
|
||||
asm ("bv,n %r0(%rp)");
|
||||
|
||||
/* Make gcc happy. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user