aboutsummaryrefslogtreecommitdiffstats
path: root/main/musl/0058-ppc64-fix-setjmp-longjmp-handling-of-TOC-pointer.patch
blob: 37d188b77cdaf94473f33cd388439ed3b5a36ef2 (plain)
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
From e31c8c2d796e8a9596503f079dc567c45f93c2ae Mon Sep 17 00:00:00 2001
From: Bobby Bingham <koorogi@koorogi.info>
Date: Fri, 4 Aug 2017 00:12:32 -0500
Subject: [PATCH] ppc64: fix setjmp/longjmp handling of TOC pointer

The TOC pointer is constant within a single dso, but needs to be saved
and restored around cross-dso calls.  The PLT stub saves it to the
caller's stack frame, and the linker adds code to the caller to restore
it.

With a local call, as within a single dso or with static linking, this
doesn't happen and the TOC pointer is always in r2.  Therefore,
setjmp/longjmp need to save/restore the TOC pointer from/to different
locations depending on whether the call to setjmp was a local or non-local
call.

It is always safe for longjmp to restore to both r2 and the caller's stack.
If the call to setjmp was local, and only r2 matters and the stack location
will be ignored, but is required by the ABI to be reserved for the TOC
pointer.  If the call was non-local, then only the stack location matters,
and whatever is restored into r2 will be clobbered anyway when the caller
reloads r2 from the stack.

A little extra care is required for sigsetjmp, because it uses setjmp
internally.  After the second return from this setjmp call, r2 will contain
the caller's TOC pointer instead of libc's TOC pointer.  We need to save
and restore the correct libc pointer before we can tail call to
__sigsetjmp_tail.
---
 src/setjmp/powerpc64/longjmp.s   | 14 +++++++++-----
 src/setjmp/powerpc64/setjmp.s    | 21 ++++++++++++++++-----
 src/signal/powerpc64/sigsetjmp.s | 21 ++++++++++++++-------
 3 files changed, 39 insertions(+), 17 deletions(-)

diff --git a/src/setjmp/powerpc64/longjmp.s b/src/setjmp/powerpc64/longjmp.s
index 7f241c2d..81d45ff6 100644
--- a/src/setjmp/powerpc64/longjmp.s
+++ b/src/setjmp/powerpc64/longjmp.s
@@ -10,10 +10,14 @@ longjmp:
 	# 1) restore cr
 	ld   0,  1*8(3)
 	mtcr 0
-	# 2) restore r1-r2 (SP and TOC)
+	# 2) restore SP
 	ld   1,  2*8(3)
+	# 3) restore TOC into both r2 and the caller's stack.
+	#    Which location is required depends on whether setjmp was called
+	#    locally or non-locally, but it's always safe to restore to both.
 	ld   2,  3*8(3)
-	# 3) restore r14-r31
+	std  2,   24(1)
+	# 4) restore r14-r31
 	ld  14,  4*8(3)
 	ld  15,  5*8(3)
 	ld  16,  6*8(3)
@@ -32,7 +36,7 @@ longjmp:
 	ld  29, 19*8(3)
 	ld  30, 20*8(3)
 	ld  31, 21*8(3)
-	# 4) restore floating point registers f14-f31
+	# 5) restore floating point registers f14-f31
 	lfd 14, 22*8(3)
 	lfd 15, 23*8(3)
 	lfd 16, 24*8(3)
@@ -52,7 +56,7 @@ longjmp:
 	lfd 30, 38*8(3)
 	lfd 31, 39*8(3)
 
-	# 5) restore vector registers v20-v31
+	# 6) restore vector registers v20-v31
 	addi 3, 3, 40*8
 	lvx 20, 0, 3 ; addi 3, 3, 16
 	lvx 21, 0, 3 ; addi 3, 3, 16
@@ -67,7 +71,7 @@ longjmp:
 	lvx 30, 0, 3 ; addi 3, 3, 16
 	lvx 31, 0, 3
 
-	# 6) return r4 ? r4 : 1
+	# 7) return r4 ? r4 : 1
 	mr    3,   4
 	cmpwi cr7, 4, 0
 	bne   cr7, 1f
diff --git a/src/setjmp/powerpc64/setjmp.s b/src/setjmp/powerpc64/setjmp.s
index d16d4bae..37683fda 100644
--- a/src/setjmp/powerpc64/setjmp.s
+++ b/src/setjmp/powerpc64/setjmp.s
@@ -1,24 +1,35 @@
-	.global ___setjmp
-	.hidden ___setjmp
 	.global __setjmp
 	.global _setjmp
 	.global setjmp
 	.type   __setjmp,@function
 	.type   _setjmp,@function
 	.type   setjmp,@function
-___setjmp:
 __setjmp:
 _setjmp:
 setjmp:
+	ld 5, 24(1)   # load from the TOC slot in the caller's stack frame
+	b __setjmp_toc
+
+	.localentry __setjmp,.-__setjmp
+	.localentry _setjmp,.-_setjmp
+	.localentry setjmp,.-setjmp
+	mr 5, 2
+
+	.global __setjmp_toc
+	.hidden __setjmp_toc
+	# same as normal setjmp, except TOC pointer to save is provided in r5.
+	# r4 would normally be the 2nd parameter, but we're using r5 to simplify calling from sigsetjmp.
+	# solves the problem of knowing whether to save the TOC pointer from r2 or the caller's stack frame.
+__setjmp_toc:
 	# 0) store IP into 0, then into the jmpbuf pointed to by r3 (first arg)
 	mflr  0
 	std   0,  0*8(3)
 	# 1) store cr
 	mfcr  0
 	std   0,  1*8(3)
-	# 2) store r1-r2 (SP and TOC)
+	# 2) store SP and TOC
 	std   1,  2*8(3)
-	std   2,  3*8(3)
+	std   5,  3*8(3)
 	# 3) store r14-31
 	std  14,  4*8(3)
 	std  15,  5*8(3)
diff --git a/src/signal/powerpc64/sigsetjmp.s b/src/signal/powerpc64/sigsetjmp.s
index 52ac1d03..410c2831 100644
--- a/src/signal/powerpc64/sigsetjmp.s
+++ b/src/signal/powerpc64/sigsetjmp.s
@@ -2,29 +2,36 @@
 	.global __sigsetjmp
 	.type sigsetjmp,%function
 	.type __sigsetjmp,%function
-	.hidden ___setjmp
+	.hidden __setjmp_toc
 sigsetjmp:
 __sigsetjmp:
 	addis 2, 12, .TOC.-__sigsetjmp@ha
 	addi  2,  2, .TOC.-__sigsetjmp@l
+	ld    5, 24(1)   # load from the TOC slot in the caller's stack frame
+	b     1f
+
 	.localentry sigsetjmp,.-sigsetjmp
 	.localentry __sigsetjmp,.-__sigsetjmp
+	mr    5,  2
 
+1:
 	cmpwi cr7, 4, 0
-	beq-  cr7, ___setjmp
+	beq-  cr7, __setjmp_toc
 
-	mflr  5
-	std   5, 512(3)
-	std  16, 512+8+8(3)
+	mflr  6
+	std   6, 512(3)
+	std   2, 512+16(3)
+	std  16, 512+24(3)
 	mr   16, 3
 
-	bl ___setjmp
+	bl __setjmp_toc
 
 	mr   4,  3
 	mr   3, 16
 	ld   5, 512(3)
 	mtlr 5
-	ld  16, 512+8+8(3)
+	ld   2, 512+16(3)
+	ld  16, 512+24(3)
 
 .hidden __sigsetjmp_tail
 	b __sigsetjmp_tail
-- 
2.13.1