From a17b01bc9df4004a1852ba272d452b0f46f5927c Mon Sep 17 00:00:00 2001 From: Bobby Bingham Date: Tue, 19 Feb 2019 06:27:28 +0000 Subject: [PATCH 3/3] ppc64: fix stack frame layout --- arch/ppc64/makecontext.c | 48 +++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/arch/ppc64/makecontext.c b/arch/ppc64/makecontext.c index 9d6b998..6d9841c 100644 --- a/arch/ppc64/makecontext.c +++ b/arch/ppc64/makecontext.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 William Pitcock + * Copyright (c) 2019 Bobby Bingham * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -11,32 +12,39 @@ */ #define _GNU_SOURCE -#include #include #include -#include #include - #include "defs.h" extern void __start_context(void); +#define SAVEARG(i,val) \ + do { \ + *(i < 8 ? &ucp->uc_mcontext.gp_regs[3+i] : argp) = val; \ + argp++; \ + } while (0) + void __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) { greg_t *sp, *argp; va_list va; - int i; - unsigned int uc_link, stack_args; + unsigned int stack_args; + + /* We pass uc_link as an argument, so in total we have argc+1 args */ + stack_args = argc + 1; - stack_args = argc > 8 ? argc - 8 : 0; - uc_link = stack_args + 1; + /* We can pass 8 args before needing the stack. If any arg is passed + * on the stack, then stack space must be reserved for all args, even + * though the first 8 don't need to be stored there */ + if (stack_args <= 8) stack_args = 0; sp = (greg_t *) ((uintptr_t) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size); - sp -= (uc_link + 1); + sp -= stack_args + 4; sp = (greg_t *) (((uintptr_t) sp & -16L)); ucp->uc_mcontext.gp_regs[REG_NIP] = (uintptr_t) func; @@ -45,29 +53,13 @@ __makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...) ucp->uc_mcontext.gp_regs[REG_ENTRY] = (uintptr_t) func; ucp->uc_mcontext.gp_regs[REG_R31] = (uintptr_t) ucp->uc_link; - sp[0] = (uintptr_t) &__start_context; - sp[uc_link] = (uintptr_t) ucp->uc_link; - argp = &sp[2]; + sp[0] = 0; + argp = &sp[4]; va_start(va, argc); - for (i = 0; i < argc; i++) - switch (i) - { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - ucp->uc_mcontext.gp_regs[i + 3] = va_arg (va, greg_t); - break; - default: - *argp++ = va_arg (va, greg_t); - break; - } + for (int i = 0; i < argc; i++) SAVEARG(i, va_arg(va, greg_t)); + SAVEARG(argc, (uintptr_t) ucp->uc_link); va_end(va); } -- 2.19.2