1#ifdef __powerpc64__
2# PowerPC64 support for -fsplit-stack.
3# Copyright (C) 2009-2022 Free Software Foundation, Inc.
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#include <auto-host.h>
28
29#if _CALL_ELF == 2
30          .abiversion 2
31#define PARAMS 32
32#else
33#define PARAMS 48
34#endif
35#define MORESTACK_FRAMESIZE   (PARAMS+96)
36#define R2_SAVE                         -MORESTACK_FRAMESIZE+PARAMS-8
37#define PARAMREG_SAVE                   -MORESTACK_FRAMESIZE+PARAMS+0
38#define STATIC_CHAIN_SAVE     -MORESTACK_FRAMESIZE+PARAMS+64
39#define R29_SAVE              -MORESTACK_FRAMESIZE+PARAMS+72
40#define LINKREG_SAVE                    -MORESTACK_FRAMESIZE+PARAMS+80
41#define NEWSTACKSIZE_SAVE     -MORESTACK_FRAMESIZE+PARAMS+88
42
43# Excess space needed to call ld.so resolver for lazy plt
44# resolution.  Go uses sigaltstack so this doesn't need to
45# also cover signal frame size.
46#define BACKOFF 4096
47# Large excess allocated when calling non-split-stack code.
48#define NON_SPLIT_STACK 0x100000
49
50
51#if _CALL_ELF == 2
52
53#define BODY_LABEL(name) name
54
55#define ENTRY0(name)                                                  \
56          .global name;                                               \
57          .hidden   name;                                             \
58          .type name,@function;                                       \
59name##:
60
61#ifdef __PCREL__
62#define ENTRY(name)                                         \
63          ENTRY0(name);                                               \
64          .localentry name, 1
65#define JUMP_TARGET(name) name##@notoc
66#else
67#define ENTRY(name)                                         \
68          ENTRY0(name);                                               \
690:        addis %r2,%r12,.TOC.-0b@ha;                       \
70        addi %r2,%r2,.TOC.-0b@l;                            \
71          .localentry name, .-name
72#endif
73
74#else
75
76#define BODY_LABEL(name) .L.##name
77
78#define ENTRY0(name)                                                  \
79          .global name;                                               \
80          .hidden   name;                                             \
81          .type name,@function;                                       \
82          .pushsection ".opd","aw";                         \
83          .p2align 3;                                                 \
84name##: .quad BODY_LABEL (name), .TOC.@tocbase, 0;          \
85          .popsection;                                                \
86BODY_LABEL(name)##:
87
88#define ENTRY(name) ENTRY0(name)
89
90#endif
91
92#define SIZE(name) .size name, .-BODY_LABEL(name)
93
94#ifndef JUMP_TARGET
95#define JUMP_TARGET(name) name
96#endif
97
98          .text
99# Just like __morestack, but with larger excess allocation
100ENTRY0(__morestack_non_split)
101.LFB1:
102          .cfi_startproc
103# We use a cleanup to restore the tcbhead_t.__private_ss if
104# an exception is thrown through this code.
105#ifdef __PIC__
106          .cfi_personality 0x9b,DW.ref.__gcc_personality_v0
107          .cfi_lsda 0x1b,.LLSDA1
108#else
109          .cfi_personality 0x3,__gcc_personality_v0
110          .cfi_lsda 0x3,.LLSDA1
111#endif
112# LR is already saved by the split-stack prologue code.
113# We may as well have the unwinder skip over the call in the
114# prologue too.
115          .cfi_offset %lr,16
116
117          addis %r12,%r12,-NON_SPLIT_STACK@h
118          SIZE (__morestack_non_split)
119# Fall through into __morestack
120
121
122# This function is called with non-standard calling conventions.
123# On entry, r12 is the requested stack pointer.  One version of the
124# split-stack prologue that calls __morestack looks like
125#         ld %r0,-0x7000-64(%r13)
126#         addis %r12,%r1,-allocate@ha
127#         addi %r12,%r12,-allocate@l
128#         cmpld %r12,%r0
129#         bge+ enough
130#         mflr %r0
131#         std %r0,16(%r1)
132#         bl __morestack
133#         ld %r0,16(%r1)
134#         mtlr %r0
135#         blr
136# enough:
137# The normal function prologue follows here, with a small addition at
138# the end to set up the arg pointer.  The arg pointer is set up with:
139#         addi %r12,%r1,offset
140#         bge %cr7,.+8
141#         mr %r12,%r29
142#
143# Note that the lr save slot 16(%r1) has already been used.
144# r3 thru r11 possibly contain arguments and a static chain
145# pointer for the function we're calling, so must be preserved.
146# cr7 must also be preserved.
147
148ENTRY0(__morestack)
149
150#if _CALL_ELF == 2
151# Functions with localentry bits of zero cannot make calls if those
152# calls might change r2.  This is true generally, and also true for
153# __morestack with its special calling convention.  When __morestack's
154# caller is non-pcrel but libgcc is pcrel, the functions called here
155# might modify r2.  r2 must be preserved on exit, and also restored
156# for the call back to our caller.
157          std %r2,R2_SAVE(%r1)
158#endif
159
160# Save parameter passing registers, our arguments, lr, r29
161# and use r29 as a frame pointer.
162          std %r3,PARAMREG_SAVE+0(%r1)
163          sub %r3,%r1,%r12              # calculate requested stack size
164          mflr %r12
165          std %r4,PARAMREG_SAVE+8(%r1)
166          std %r5,PARAMREG_SAVE+16(%r1)
167          std %r6,PARAMREG_SAVE+24(%r1)
168          std %r7,PARAMREG_SAVE+32(%r1)
169          addi %r3,%r3,BACKOFF
170          std %r8,PARAMREG_SAVE+40(%r1)
171          std %r9,PARAMREG_SAVE+48(%r1)
172          std %r10,PARAMREG_SAVE+56(%r1)
173          std %r11,STATIC_CHAIN_SAVE(%r1)
174          std %r29,R29_SAVE(%r1)
175          std %r12,LINKREG_SAVE(%r1)
176          std %r3,NEWSTACKSIZE_SAVE(%r1)          # new stack size
177          mr %r29,%r1
178#if _CALL_ELF == 2
179          .cfi_offset %r2,R2_SAVE
180#endif
181          .cfi_offset %r29,R29_SAVE
182          .cfi_def_cfa_register %r29
183          stdu %r1,-MORESTACK_FRAMESIZE(%r1)
184
185#if _CALL_ELF == 2 && !defined __PCREL__
186# If this isn't a pcrel libgcc then the functions we call here will
187# require r2 to be valid.  If __morestack is called from pcrel code r2
188# won't be valid.  Set it up.
189          bcl 20,31,1f
1901:
191          mflr %r12
192          addis %r2,%r12,.TOC.-1b@ha
193          addi %r2,%r2,.TOC.-1b@l
194#endif
195
196          # void __morestack_block_signals (void)
197          bl JUMP_TARGET(__morestack_block_signals)
198
199          # void *__generic_morestack (size_t *pframe_size,
200          #                                  void *old_stack,
201          #                                  size_t param_size)
202          addi %r3,%r29,NEWSTACKSIZE_SAVE
203          mr %r4,%r29
204          li %r5,0                      # no copying from old stack
205          bl JUMP_TARGET(__generic_morestack)
206
207# Start using new stack
208          stdu %r29,-32(%r3)            # back-chain
209          mr %r1,%r3
210
211# Set __private_ss stack guard for the new stack.
212          ld %r12,NEWSTACKSIZE_SAVE(%r29)         # modified size
213          addi %r3,%r3,BACKOFF-32
214          sub %r3,%r3,%r12
215# Note that a signal frame has $pc pointing at the instruction
216# where the signal occurred.  For something like a timer
217# interrupt this means the instruction has already executed,
218# thus the region starts at the instruction modifying
219# __private_ss, not one instruction after.
220.LEHB0:
221          std %r3,-0x7000-64(%r13)      # tcbhead_t.__private_ss
222
223          # void __morestack_unblock_signals (void)
224          bl JUMP_TARGET(__morestack_unblock_signals)
225
226# Set up for a call to the target function, located 3
227# instructions after __morestack's return address.
228#
229          ld %r12,LINKREG_SAVE(%r29)
230#if _CALL_ELF == 2
231          ld %r2,R2_SAVE(%r29)
232#endif
233          ld %r3,PARAMREG_SAVE+0(%r29)  # restore arg regs
234          ld %r4,PARAMREG_SAVE+8(%r29)
235          ld %r5,PARAMREG_SAVE+16(%r29)
236          ld %r6,PARAMREG_SAVE+24(%r29)
237          ld %r7,PARAMREG_SAVE+32(%r29)
238          ld %r8,PARAMREG_SAVE+40(%r29)
239          ld %r9,PARAMREG_SAVE+48(%r29)
240          addi %r0,%r12,12              # add 3 instructions
241          ld %r10,PARAMREG_SAVE+56(%r29)
242          ld %r11,STATIC_CHAIN_SAVE(%r29)
243          cmpld %cr7,%r12,%r0           # indicate we were called
244          mtctr %r0
245          bctrl                                   # call caller!
246
247# On return, save regs possibly used to return a value, and
248# possibly trashed by calls to __morestack_block_signals,
249# __generic_releasestack and __morestack_unblock_signals.
250# Assume those calls don't use vector or floating point regs.
251          std %r3,PARAMREG_SAVE+0(%r29)
252          std %r4,PARAMREG_SAVE+8(%r29)
253          std %r5,PARAMREG_SAVE+16(%r29)
254          std %r6,PARAMREG_SAVE+24(%r29)
255#if _CALL_ELF == 2
256          std %r7,PARAMREG_SAVE+32(%r29)
257          std %r8,PARAMREG_SAVE+40(%r29)
258          std %r9,PARAMREG_SAVE+48(%r29)
259          std %r10,PARAMREG_SAVE+56(%r29)
260#endif
261
262#if _CALL_ELF == 2 && !defined __PCREL__
263# r2 was restored for calling back into our caller.  Set it up again.
264          bcl 20,31,1f
2651:
266          mflr %r12
267          addis %r2,%r12,.TOC.-1b@ha
268          addi %r2,%r2,.TOC.-1b@l
269#endif
270
271          bl JUMP_TARGET(__morestack_block_signals)
272
273          # void *__generic_releasestack (size_t *pavailable)
274          addi %r3,%r29,NEWSTACKSIZE_SAVE
275          bl JUMP_TARGET(__generic_releasestack)
276
277# Reset __private_ss stack guard to value for old stack
278          ld %r12,NEWSTACKSIZE_SAVE(%r29)
279          addi %r3,%r3,BACKOFF
280          sub %r3,%r3,%r12
281.LEHE0:
282          std %r3,-0x7000-64(%r13)      # tcbhead_t.__private_ss
283
284          bl JUMP_TARGET(__morestack_unblock_signals)
285
286# Use old stack again.
287          mr %r1,%r29
288
289# Restore return value regs, and return.
290          ld %r0,LINKREG_SAVE(%r29)
291          mtlr %r0
292#if _CALL_ELF == 2
293          ld %r2,R2_SAVE(%r29)
294#endif
295          ld %r3,PARAMREG_SAVE+0(%r29)
296          ld %r4,PARAMREG_SAVE+8(%r29)
297          ld %r5,PARAMREG_SAVE+16(%r29)
298          ld %r6,PARAMREG_SAVE+24(%r29)
299#if _CALL_ELF == 2
300          ld %r7,PARAMREG_SAVE+32(%r29)
301          ld %r8,PARAMREG_SAVE+40(%r29)
302          ld %r9,PARAMREG_SAVE+48(%r29)
303          ld %r10,PARAMREG_SAVE+56(%r29)
304#endif
305          ld %r29,R29_SAVE(%r29)
306          .cfi_def_cfa_register %r1
307          blr
308
309# This is the cleanup code called by the stack unwinder when
310# unwinding through code between .LEHB0 and .LEHE0 above.
311cleanup:
312          .cfi_def_cfa_register %r29
313          std %r3,PARAMREG_SAVE(%r29)   # Save exception header
314          # size_t __generic_findstack (void *stack)
315          mr %r3,%r29
316          bl JUMP_TARGET(__generic_findstack)
317          sub %r3,%r29,%r3
318          addi %r3,%r3,BACKOFF
319          std %r3,-0x7000-64(%r13)      # tcbhead_t.__private_ss
320          ld %r3,PARAMREG_SAVE(%r29)
321          bl JUMP_TARGET(_Unwind_Resume)
322#ifndef __PCREL__
323          nop
324#endif
325          .cfi_endproc
326          SIZE (__morestack)
327
328
329          .section .gcc_except_table,"a",@progbits
330          .p2align 2
331.LLSDA1:
332          .byte     0xff      # @LPStart format (omit)
333          .byte     0xff      # @TType format (omit)
334          .byte     0x1       # call-site format (uleb128)
335          .uleb128 .LLSDACSE1-.LLSDACSB1          # Call-site table length
336.LLSDACSB1:
337          .uleb128 .LEHB0-.LFB1         # region 0 start
338          .uleb128 .LEHE0-.LEHB0        # length
339          .uleb128 cleanup-.LFB1        # landing pad
340          .uleb128 0                    # no action, ie. a cleanup
341.LLSDACSE1:
342
343
344#ifdef __PIC__
345# Build a position independent reference to the personality function.
346          .hidden DW.ref.__gcc_personality_v0
347          .weak DW.ref.__gcc_personality_v0
348          .section .data.DW.ref.__gcc_personality_v0,"awG",@progbits,DW.ref.__gcc_personality_v0,comdat
349          .p2align 3
350DW.ref.__gcc_personality_v0:
351          .quad __gcc_personality_v0
352          .type DW.ref.__gcc_personality_v0, @object
353          .size DW.ref.__gcc_personality_v0, 8
354#endif
355
356
357          .text
358# Initialize the stack guard when the program starts or when a
359# new thread starts.  This is called from a constructor.
360# void __stack_split_initialize (void)
361ENTRY(__stack_split_initialize)
362          .cfi_startproc
363          addi %r3,%r1,-0x4000                    # We should have at least 16K.
364          std %r3,-0x7000-64(%r13)      # tcbhead_t.__private_ss
365          # void __generic_morestack_set_initial_sp (void *sp, size_t len)
366          mr %r3,%r1
367          li %r4, 0x4000
368          b JUMP_TARGET(__generic_morestack_set_initial_sp)
369# The lack of .cfi_endproc here is deliberate.  This function and the
370# following ones can all use the default FDE.
371          SIZE (__stack_split_initialize)
372
373
374# Return current __private_ss
375# void *__morestack_get_guard (void)
376ENTRY0(__morestack_get_guard)
377          ld %r3,-0x7000-64(%r13)                 # tcbhead_t.__private_ss
378          blr
379          SIZE (__morestack_get_guard)
380
381
382# Set __private_ss
383# void __morestack_set_guard (void *ptr)
384ENTRY0(__morestack_set_guard)
385          std %r3,-0x7000-64(%r13)      # tcbhead_t.__private_ss
386          blr
387          SIZE (__morestack_set_guard)
388
389
390# Return the stack guard value for given stack
391# void *__morestack_make_guard (void *stack, size_t size)
392ENTRY0(__morestack_make_guard)
393          sub %r3,%r3,%r4
394          addi %r3,%r3,BACKOFF
395          blr
396          .cfi_endproc
397          SIZE (__morestack_make_guard)
398
399
400# Make __stack_split_initialize a high priority constructor.
401#if HAVE_INITFINI_ARRAY_SUPPORT
402          .section .init_array.00000,"aw",@progbits
403#else
404          .section .ctors.65535,"aw",@progbits
405#endif
406          .p2align 3
407          .quad __stack_split_initialize
408          .quad __morestack_load_mmap
409
410          .section .note.GNU-stack,"",@progbits
411          .section .note.GNU-split-stack,"",@progbits
412          .section .note.GNU-no-split-stack,"",@progbits
413#endif /* __powerpc64__ */
414