xref: /netbsd-src/external/gpl3/gcc/dist/libgcc/config/rs6000/morestack.S (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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