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