summaryrefslogtreecommitdiff
path: root/system/libucontext/ppc64-stack-layout.patch
blob: d030b61af109b21be7d2ebf4d40600d3a3aef49d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
From a17b01bc9df4004a1852ba272d452b0f46f5927c Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
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 <nenolod@dereferenced.org>
+ * Copyright (c) 2019 Bobby Bingham <koorogi@koorogi.info>
  *
  * 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 <stddef.h>
 #include <stdarg.h>
 #include <signal.h>
-#include <string.h>
 #include <stdint.h>
 
-
 #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