Skip to content

Commit 4e6cb2c

Browse files
libc/powerpc64: Fix swapcontext(3)
On PowerPC platforms a valid link to the Table of Contents (TOC) is required for PLT lookups to function. This TOC pointer is stored in a dedicated register, and is used along with the stack pointer by both C prologue and PLT lookup code. When calling swapcontext() with uc_link != NULL, a PLT lookup to setcontext(3) is attempted from within the _ctx_done context. The exiting process has usually trashed both r1 and r2 at this point, leading to a crash within the PLT lookup before setcontext(2) is reached to restore the linked context. Save and restore r1 and r2, using r16 as a scratch register to bypass the prologue trampling r2. This ensures the subsequent PLT lookup to setcontext(3) succeeds. Signed-off-by: Timothy Pearson <[email protected]>
1 parent 88c8cba commit 4e6cb2c

File tree

2 files changed

+11
-1
lines changed

2 files changed

+11
-1
lines changed

lib/libc/powerpc64/gen/_ctx_start.S

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,20 @@
3636
#else
3737
/* Load global entry point */
3838
mr %r12,%r14
39+
40+
/* Create minimal stack frame and save TOC */
41+
stdu %r1,-32(%r1)
42+
std %r16,24(%r1)
3943
#endif
4044
mtlr %r14
4145
blrl /* branch to start function */
4246
mr %r3,%r15 /* pass pointer to ucontext as argument */
4347
nop
48+
#if defined(_CALL_ELF) && _CALL_ELF != 1
49+
/* Restore TOC and pop stack frame */
50+
ld %r2,24(%r1)
51+
ld %r1,0(%r1)
52+
#endif
4453
bl CNAME(_ctx_done) /* branch to ctxt completion func */
4554
/*
4655
* we should never return from the

lib/libc/powerpc64/gen/makecontext.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,15 @@ __makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
111111
va_end(ap);
112112

113113
/*
114-
* Use caller-saved regs 14/15 to hold params that _ctx_start
114+
* Use caller-saved regs 14/15/16 to hold params that _ctx_start
115115
* will use to invoke the user-supplied func
116116
*/
117117
#if !defined(_CALL_ELF) || _CALL_ELF == 1
118118
/* Cast to ensure this is treated as a function descriptor. */
119119
mc->mc_srr0 = *(uintptr_t *)_ctx_start;
120120
#else
121121
mc->mc_srr0 = (uintptr_t) _ctx_start;
122+
mc->mc_gpr[16] = mc->mc_gpr[2]; /* r16 <- TOC */
122123
#endif
123124
mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */
124125
mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */

0 commit comments

Comments
 (0)