Home | History | Annotate | Line # | Download | only in rs6000
morestack.S revision 1.1.1.10
      1 #ifdef __powerpc64__
      2 # PowerPC64 support for -fsplit-stack.
      3 # Copyright (C) 2009-2024 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;				\
     59 name##:
     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);					\
     69 0:	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;					\
     84 name##: .quad BODY_LABEL (name), .TOC.@tocbase, 0;	\
     85 	.popsection;					\
     86 BODY_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
    100 ENTRY0(__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 
    148 ENTRY0(__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
    190 1:
    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,-PARAMS(%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-PARAMS
    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
    265 1:
    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.
    311 cleanup:
    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
    350 DW.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)
    361 ENTRY(__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)
    376 ENTRY0(__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)
    384 ENTRY0(__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)
    392 ENTRY0(__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",@init_array
    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