]>
Commit | Line | Data |
---|---|---|
0f0fd745 AM |
1 | #ifdef __powerpc64__ |
2 | # PowerPC64 support for -fsplit-stack. | |
cbe34bb5 | 3 | # Copyright (C) 2009-2017 Free Software Foundation, Inc. |
0f0fd745 AM |
4 | # Contributed by Alan Modra <amodra@gmail.com>. |
5 | ||
6 | # This file is part of GCC. | |
7 | ||
8 | # GCC is free software; you can redistribute it and/or modify it under | |
9 | # the terms of the GNU General Public License as published by the Free | |
10 | # Software Foundation; either version 3, or (at your option) any later | |
11 | # version. | |
12 | ||
13 | # GCC is distributed in the hope that it will be useful, but WITHOUT ANY | |
14 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 | # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 | # for more details. | |
17 | ||
18 | # Under Section 7 of GPL version 3, you are granted additional | |
19 | # permissions described in the GCC Runtime Library Exception, version | |
20 | # 3.1, as published by the Free Software Foundation. | |
21 | ||
22 | # You should have received a copy of the GNU General Public License and | |
23 | # a copy of the GCC Runtime Library Exception along with this program; | |
24 | # see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
25 | # <http://www.gnu.org/licenses/>. | |
26 | ||
27 | #if _CALL_ELF == 2 | |
28 | .abiversion 2 | |
29 | #define PARAMS 32 | |
30 | #else | |
0f0fd745 AM |
31 | #define PARAMS 48 |
32 | #endif | |
33 | #define MORESTACK_FRAMESIZE (PARAMS+96) | |
34 | #define PARAMREG_SAVE -MORESTACK_FRAMESIZE+PARAMS+0 | |
35 | #define STATIC_CHAIN_SAVE -MORESTACK_FRAMESIZE+PARAMS+64 | |
36 | #define R29_SAVE -MORESTACK_FRAMESIZE+PARAMS+72 | |
37 | #define LINKREG_SAVE -MORESTACK_FRAMESIZE+PARAMS+80 | |
38 | #define NEWSTACKSIZE_SAVE -MORESTACK_FRAMESIZE+PARAMS+88 | |
39 | ||
40 | # Excess space needed to call ld.so resolver for lazy plt | |
41 | # resolution. Go uses sigaltstack so this doesn't need to | |
42 | # also cover signal frame size. | |
43 | #define BACKOFF 4096 | |
44 | # Large excess allocated when calling non-split-stack code. | |
45 | #define NON_SPLIT_STACK 0x100000 | |
46 | ||
47 | ||
48 | #if _CALL_ELF == 2 | |
49 | ||
50 | #define BODY_LABEL(name) name | |
51 | ||
52 | #define ENTRY0(name) \ | |
53 | .global name; \ | |
54 | .hidden name; \ | |
55 | .type name,@function; \ | |
56 | name##: | |
57 | ||
58 | #define ENTRY(name) \ | |
59 | ENTRY0(name); \ | |
60 | 0: addis %r2,%r12,.TOC.-0b@ha; \ | |
61 | addi %r2,%r2,.TOC.-0b@l; \ | |
62 | .localentry name, .-name | |
63 | ||
64 | #else | |
65 | ||
66 | #define BODY_LABEL(name) .L.##name | |
67 | ||
68 | #define ENTRY0(name) \ | |
69 | .global name; \ | |
70 | .hidden name; \ | |
71 | .type name,@function; \ | |
72 | .pushsection ".opd","aw"; \ | |
73 | .p2align 3; \ | |
74 | name##: .quad BODY_LABEL (name), .TOC.@tocbase, 0; \ | |
75 | .popsection; \ | |
76 | BODY_LABEL(name)##: | |
77 | ||
78 | #define ENTRY(name) ENTRY0(name) | |
79 | ||
80 | #endif | |
81 | ||
82 | #define SIZE(name) .size name, .-BODY_LABEL(name) | |
83 | ||
84 | ||
85 | .text | |
86 | # Just like __morestack, but with larger excess allocation | |
87 | ENTRY0(__morestack_non_split) | |
88 | .LFB1: | |
89 | .cfi_startproc | |
90 | # We use a cleanup to restore the tcbhead_t.__private_ss if | |
91 | # an exception is thrown through this code. | |
92 | #ifdef __PIC__ | |
93 | .cfi_personality 0x9b,DW.ref.__gcc_personality_v0 | |
94 | .cfi_lsda 0x1b,.LLSDA1 | |
95 | #else | |
96 | .cfi_personality 0x3,__gcc_personality_v0 | |
97 | .cfi_lsda 0x3,.LLSDA1 | |
98 | #endif | |
99 | # LR is already saved by the split-stack prologue code. | |
100 | # We may as well have the unwinder skip over the call in the | |
101 | # prologue too. | |
102 | .cfi_offset %lr,16 | |
103 | ||
104 | addis %r12,%r12,-NON_SPLIT_STACK@h | |
105 | SIZE (__morestack_non_split) | |
106 | # Fall through into __morestack | |
107 | ||
108 | ||
109 | # This function is called with non-standard calling conventions. | |
110 | # On entry, r12 is the requested stack pointer. One version of the | |
111 | # split-stack prologue that calls __morestack looks like | |
112 | # ld %r0,-0x7000-64(%r13) | |
113 | # addis %r12,%r1,-allocate@ha | |
114 | # addi %r12,%r12,-allocate@l | |
115 | # cmpld %r12,%r0 | |
116 | # bge+ enough | |
117 | # mflr %r0 | |
118 | # std %r0,16(%r1) | |
119 | # bl __morestack | |
120 | # ld %r0,16(%r1) | |
121 | # mtlr %r0 | |
122 | # blr | |
123 | # enough: | |
124 | # The normal function prologue follows here, with a small addition at | |
125 | # the end to set up the arg pointer. The arg pointer is set up with: | |
126 | # addi %r12,%r1,offset | |
127 | # bge %cr7,.+8 | |
128 | # mr %r12,%r29 | |
129 | # | |
130 | # Note that the lr save slot 16(%r1) has already been used. | |
131 | # r3 thru r11 possibly contain arguments and a static chain | |
132 | # pointer for the function we're calling, so must be preserved. | |
133 | # cr7 must also be preserved. | |
134 | ||
135 | ENTRY0(__morestack) | |
136 | # Save parameter passing registers, our arguments, lr, r29 | |
137 | # and use r29 as a frame pointer. | |
138 | std %r3,PARAMREG_SAVE+0(%r1) | |
139 | sub %r3,%r1,%r12 # calculate requested stack size | |
140 | mflr %r12 | |
141 | std %r4,PARAMREG_SAVE+8(%r1) | |
142 | std %r5,PARAMREG_SAVE+16(%r1) | |
143 | std %r6,PARAMREG_SAVE+24(%r1) | |
144 | std %r7,PARAMREG_SAVE+32(%r1) | |
145 | addi %r3,%r3,BACKOFF | |
146 | std %r8,PARAMREG_SAVE+40(%r1) | |
147 | std %r9,PARAMREG_SAVE+48(%r1) | |
148 | std %r10,PARAMREG_SAVE+56(%r1) | |
149 | std %r11,STATIC_CHAIN_SAVE(%r1) | |
150 | std %r29,R29_SAVE(%r1) | |
151 | std %r12,LINKREG_SAVE(%r1) | |
152 | std %r3,NEWSTACKSIZE_SAVE(%r1) # new stack size | |
153 | mr %r29,%r1 | |
154 | .cfi_offset %r29,R29_SAVE | |
155 | .cfi_def_cfa_register %r29 | |
156 | stdu %r1,-MORESTACK_FRAMESIZE(%r1) | |
157 | ||
158 | # void __morestack_block_signals (void) | |
159 | bl __morestack_block_signals | |
160 | ||
161 | # void *__generic_morestack (size_t *pframe_size, | |
162 | # void *old_stack, | |
163 | # size_t param_size) | |
164 | addi %r3,%r29,NEWSTACKSIZE_SAVE | |
165 | mr %r4,%r29 | |
166 | li %r5,0 # no copying from old stack | |
167 | bl __generic_morestack | |
168 | ||
169 | # Start using new stack | |
170 | stdu %r29,-32(%r3) # back-chain | |
171 | mr %r1,%r3 | |
172 | ||
173 | # Set __private_ss stack guard for the new stack. | |
174 | ld %r12,NEWSTACKSIZE_SAVE(%r29) # modified size | |
175 | addi %r3,%r3,BACKOFF-32 | |
176 | sub %r3,%r3,%r12 | |
177 | # Note that a signal frame has $pc pointing at the instruction | |
178 | # where the signal occurred. For something like a timer | |
179 | # interrupt this means the instruction has already executed, | |
180 | # thus the region starts at the instruction modifying | |
181 | # __private_ss, not one instruction after. | |
182 | .LEHB0: | |
183 | std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss | |
184 | ||
185 | # void __morestack_unblock_signals (void) | |
186 | bl __morestack_unblock_signals | |
187 | ||
188 | # Set up for a call to the target function, located 3 | |
189 | # instructions after __morestack's return address. | |
190 | # | |
191 | ld %r12,LINKREG_SAVE(%r29) | |
192 | ld %r3,PARAMREG_SAVE+0(%r29) # restore arg regs | |
193 | ld %r4,PARAMREG_SAVE+8(%r29) | |
194 | ld %r5,PARAMREG_SAVE+16(%r29) | |
195 | ld %r6,PARAMREG_SAVE+24(%r29) | |
196 | ld %r7,PARAMREG_SAVE+32(%r29) | |
197 | ld %r8,PARAMREG_SAVE+40(%r29) | |
198 | ld %r9,PARAMREG_SAVE+48(%r29) | |
199 | addi %r0,%r12,12 # add 3 instructions | |
200 | ld %r10,PARAMREG_SAVE+56(%r29) | |
201 | ld %r11,STATIC_CHAIN_SAVE(%r29) | |
202 | cmpld %cr7,%r12,%r0 # indicate we were called | |
203 | mtctr %r0 | |
204 | bctrl # call caller! | |
205 | ||
206 | # On return, save regs possibly used to return a value, and | |
207 | # possibly trashed by calls to __morestack_block_signals, | |
208 | # __generic_releasestack and __morestack_unblock_signals. | |
209 | # Assume those calls don't use vector or floating point regs. | |
210 | std %r3,PARAMREG_SAVE+0(%r29) | |
211 | std %r4,PARAMREG_SAVE+8(%r29) | |
212 | std %r5,PARAMREG_SAVE+16(%r29) | |
213 | std %r6,PARAMREG_SAVE+24(%r29) | |
214 | #if _CALL_ELF == 2 | |
215 | std %r7,PARAMREG_SAVE+32(%r29) | |
216 | std %r8,PARAMREG_SAVE+40(%r29) | |
217 | std %r9,PARAMREG_SAVE+48(%r29) | |
218 | std %r10,PARAMREG_SAVE+56(%r29) | |
219 | #endif | |
220 | ||
221 | bl __morestack_block_signals | |
222 | ||
223 | # void *__generic_releasestack (size_t *pavailable) | |
224 | addi %r3,%r29,NEWSTACKSIZE_SAVE | |
225 | bl __generic_releasestack | |
226 | ||
227 | # Reset __private_ss stack guard to value for old stack | |
228 | ld %r12,NEWSTACKSIZE_SAVE(%r29) | |
229 | addi %r3,%r3,BACKOFF | |
230 | sub %r3,%r3,%r12 | |
231 | .LEHE0: | |
232 | std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss | |
233 | ||
234 | bl __morestack_unblock_signals | |
235 | ||
236 | # Use old stack again. | |
237 | mr %r1,%r29 | |
238 | ||
239 | # Restore return value regs, and return. | |
240 | ld %r0,LINKREG_SAVE(%r29) | |
241 | mtlr %r0 | |
242 | ld %r3,PARAMREG_SAVE+0(%r29) | |
243 | ld %r4,PARAMREG_SAVE+8(%r29) | |
244 | ld %r5,PARAMREG_SAVE+16(%r29) | |
245 | ld %r6,PARAMREG_SAVE+24(%r29) | |
246 | #if _CALL_ELF == 2 | |
247 | ld %r7,PARAMREG_SAVE+32(%r29) | |
248 | ld %r8,PARAMREG_SAVE+40(%r29) | |
249 | ld %r9,PARAMREG_SAVE+48(%r29) | |
250 | ld %r10,PARAMREG_SAVE+56(%r29) | |
251 | #endif | |
252 | ld %r29,R29_SAVE(%r29) | |
253 | .cfi_def_cfa_register %r1 | |
254 | blr | |
255 | ||
256 | # This is the cleanup code called by the stack unwinder when | |
257 | # unwinding through code between .LEHB0 and .LEHE0 above. | |
258 | cleanup: | |
259 | .cfi_def_cfa_register %r29 | |
260 | std %r3,PARAMREG_SAVE(%r29) # Save exception header | |
261 | # size_t __generic_findstack (void *stack) | |
262 | mr %r3,%r29 | |
263 | bl __generic_findstack | |
264 | sub %r3,%r29,%r3 | |
265 | addi %r3,%r3,BACKOFF | |
266 | std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss | |
267 | ld %r3,PARAMREG_SAVE(%r29) | |
268 | bl _Unwind_Resume | |
269 | nop | |
270 | .cfi_endproc | |
271 | SIZE (__morestack) | |
272 | ||
273 | ||
274 | .section .gcc_except_table,"a",@progbits | |
275 | .p2align 2 | |
276 | .LLSDA1: | |
277 | .byte 0xff # @LPStart format (omit) | |
278 | .byte 0xff # @TType format (omit) | |
279 | .byte 0x1 # call-site format (uleb128) | |
280 | .uleb128 .LLSDACSE1-.LLSDACSB1 # Call-site table length | |
281 | .LLSDACSB1: | |
282 | .uleb128 .LEHB0-.LFB1 # region 0 start | |
283 | .uleb128 .LEHE0-.LEHB0 # length | |
284 | .uleb128 cleanup-.LFB1 # landing pad | |
285 | .uleb128 0 # no action, ie. a cleanup | |
286 | .LLSDACSE1: | |
287 | ||
288 | ||
289 | #ifdef __PIC__ | |
290 | # Build a position independent reference to the personality function. | |
291 | .hidden DW.ref.__gcc_personality_v0 | |
292 | .weak DW.ref.__gcc_personality_v0 | |
293 | .section .data.DW.ref.__gcc_personality_v0,"awG",@progbits,DW.ref.__gcc_personality_v0,comdat | |
294 | .p2align 3 | |
295 | DW.ref.__gcc_personality_v0: | |
296 | .quad __gcc_personality_v0 | |
297 | .type DW.ref.__gcc_personality_v0, @object | |
298 | .size DW.ref.__gcc_personality_v0, 8 | |
299 | #endif | |
300 | ||
301 | ||
302 | .text | |
303 | # Initialize the stack guard when the program starts or when a | |
304 | # new thread starts. This is called from a constructor. | |
305 | # void __stack_split_initialize (void) | |
306 | ENTRY(__stack_split_initialize) | |
307 | addi %r3,%r1,-0x4000 # We should have at least 16K. | |
308 | std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss | |
309 | # void __generic_morestack_set_initial_sp (void *sp, size_t len) | |
310 | mr %r3,%r1 | |
311 | li %r4, 0x4000 | |
312 | b __generic_morestack_set_initial_sp | |
313 | SIZE (__stack_split_initialize) | |
314 | ||
315 | ||
316 | # Return current __private_ss | |
317 | # void *__morestack_get_guard (void) | |
318 | ENTRY0(__morestack_get_guard) | |
319 | ld %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss | |
320 | blr | |
321 | SIZE (__morestack_get_guard) | |
322 | ||
323 | ||
324 | # Set __private_ss | |
325 | # void __morestack_set_guard (void *ptr) | |
326 | ENTRY0(__morestack_set_guard) | |
327 | std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss | |
328 | blr | |
329 | SIZE (__morestack_set_guard) | |
330 | ||
331 | ||
332 | # Return the stack guard value for given stack | |
333 | # void *__morestack_make_guard (void *stack, size_t size) | |
334 | ENTRY0(__morestack_make_guard) | |
335 | sub %r3,%r3,%r4 | |
336 | addi %r3,%r3,BACKOFF | |
337 | blr | |
338 | SIZE (__morestack_make_guard) | |
339 | ||
340 | ||
341 | # Make __stack_split_initialize a high priority constructor. | |
342 | .section .ctors.65535,"aw",@progbits | |
343 | .p2align 3 | |
344 | .quad __stack_split_initialize | |
345 | .quad __morestack_load_mmap | |
346 | ||
347 | .section .note.GNU-stack,"",@progbits | |
348 | .section .note.GNU-split-stack,"",@progbits | |
349 | .section .note.GNU-no-split-stack,"",@progbits | |
350 | #endif /* __powerpc64__ */ |