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