| #ifdef __powerpc64__ |
| # PowerPC64 support for -fsplit-stack. |
| # Copyright (C) 2009-2021 Free Software Foundation, Inc. |
| # Contributed by Alan Modra <amodra@gmail.com>. |
| |
| # This file is part of GCC. |
| |
| # GCC is free software; you can redistribute it and/or modify it under |
| # the terms of the GNU General Public License as published by the Free |
| # Software Foundation; either version 3, or (at your option) any later |
| # version. |
| |
| # GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| # WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| # for more details. |
| |
| # Under Section 7 of GPL version 3, you are granted additional |
| # permissions described in the GCC Runtime Library Exception, version |
| # 3.1, as published by the Free Software Foundation. |
| |
| # You should have received a copy of the GNU General Public License and |
| # a copy of the GCC Runtime Library Exception along with this program; |
| # see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| # <http://www.gnu.org/licenses/>. |
| |
| #include <auto-host.h> |
| |
| #if _CALL_ELF == 2 |
| .abiversion 2 |
| #define PARAMS 32 |
| #else |
| #define PARAMS 48 |
| #endif |
| #define MORESTACK_FRAMESIZE (PARAMS+96) |
| #define R2_SAVE -MORESTACK_FRAMESIZE+PARAMS-8 |
| #define PARAMREG_SAVE -MORESTACK_FRAMESIZE+PARAMS+0 |
| #define STATIC_CHAIN_SAVE -MORESTACK_FRAMESIZE+PARAMS+64 |
| #define R29_SAVE -MORESTACK_FRAMESIZE+PARAMS+72 |
| #define LINKREG_SAVE -MORESTACK_FRAMESIZE+PARAMS+80 |
| #define NEWSTACKSIZE_SAVE -MORESTACK_FRAMESIZE+PARAMS+88 |
| |
| # Excess space needed to call ld.so resolver for lazy plt |
| # resolution. Go uses sigaltstack so this doesn't need to |
| # also cover signal frame size. |
| #define BACKOFF 4096 |
| # Large excess allocated when calling non-split-stack code. |
| #define NON_SPLIT_STACK 0x100000 |
| |
| |
| #if _CALL_ELF == 2 |
| |
| #define BODY_LABEL(name) name |
| |
| #define ENTRY0(name) \ |
| .global name; \ |
| .hidden name; \ |
| .type name,@function; \ |
| name##: |
| |
| #ifdef __PCREL__ |
| #define ENTRY(name) \ |
| ENTRY0(name); \ |
| .localentry name, 1 |
| #define JUMP_TARGET(name) name##@notoc |
| #else |
| #define ENTRY(name) \ |
| ENTRY0(name); \ |
| 0: addis %r2,%r12,.TOC.-0b@ha; \ |
| addi %r2,%r2,.TOC.-0b@l; \ |
| .localentry name, .-name |
| #endif |
| |
| #else |
| |
| #define BODY_LABEL(name) .L.##name |
| |
| #define ENTRY0(name) \ |
| .global name; \ |
| .hidden name; \ |
| .type name,@function; \ |
| .pushsection ".opd","aw"; \ |
| .p2align 3; \ |
| name##: .quad BODY_LABEL (name), .TOC.@tocbase, 0; \ |
| .popsection; \ |
| BODY_LABEL(name)##: |
| |
| #define ENTRY(name) ENTRY0(name) |
| |
| #endif |
| |
| #define SIZE(name) .size name, .-BODY_LABEL(name) |
| |
| #ifndef JUMP_TARGET |
| #define JUMP_TARGET(name) name |
| #endif |
| |
| .text |
| # Just like __morestack, but with larger excess allocation |
| ENTRY0(__morestack_non_split) |
| .LFB1: |
| .cfi_startproc |
| # We use a cleanup to restore the tcbhead_t.__private_ss if |
| # an exception is thrown through this code. |
| #ifdef __PIC__ |
| .cfi_personality 0x9b,DW.ref.__gcc_personality_v0 |
| .cfi_lsda 0x1b,.LLSDA1 |
| #else |
| .cfi_personality 0x3,__gcc_personality_v0 |
| .cfi_lsda 0x3,.LLSDA1 |
| #endif |
| # LR is already saved by the split-stack prologue code. |
| # We may as well have the unwinder skip over the call in the |
| # prologue too. |
| .cfi_offset %lr,16 |
| |
| addis %r12,%r12,-NON_SPLIT_STACK@h |
| SIZE (__morestack_non_split) |
| # Fall through into __morestack |
| |
| |
| # This function is called with non-standard calling conventions. |
| # On entry, r12 is the requested stack pointer. One version of the |
| # split-stack prologue that calls __morestack looks like |
| # ld %r0,-0x7000-64(%r13) |
| # addis %r12,%r1,-allocate@ha |
| # addi %r12,%r12,-allocate@l |
| # cmpld %r12,%r0 |
| # bge+ enough |
| # mflr %r0 |
| # std %r0,16(%r1) |
| # bl __morestack |
| # ld %r0,16(%r1) |
| # mtlr %r0 |
| # blr |
| # enough: |
| # The normal function prologue follows here, with a small addition at |
| # the end to set up the arg pointer. The arg pointer is set up with: |
| # addi %r12,%r1,offset |
| # bge %cr7,.+8 |
| # mr %r12,%r29 |
| # |
| # Note that the lr save slot 16(%r1) has already been used. |
| # r3 thru r11 possibly contain arguments and a static chain |
| # pointer for the function we're calling, so must be preserved. |
| # cr7 must also be preserved. |
| |
| ENTRY0(__morestack) |
| |
| #if _CALL_ELF == 2 |
| # Functions with localentry bits of zero cannot make calls if those |
| # calls might change r2. This is true generally, and also true for |
| # __morestack with its special calling convention. When __morestack's |
| # caller is non-pcrel but libgcc is pcrel, the functions called here |
| # might modify r2. r2 must be preserved on exit, and also restored |
| # for the call back to our caller. |
| std %r2,R2_SAVE(%r1) |
| #endif |
| |
| # Save parameter passing registers, our arguments, lr, r29 |
| # and use r29 as a frame pointer. |
| std %r3,PARAMREG_SAVE+0(%r1) |
| sub %r3,%r1,%r12 # calculate requested stack size |
| mflr %r12 |
| std %r4,PARAMREG_SAVE+8(%r1) |
| std %r5,PARAMREG_SAVE+16(%r1) |
| std %r6,PARAMREG_SAVE+24(%r1) |
| std %r7,PARAMREG_SAVE+32(%r1) |
| addi %r3,%r3,BACKOFF |
| std %r8,PARAMREG_SAVE+40(%r1) |
| std %r9,PARAMREG_SAVE+48(%r1) |
| std %r10,PARAMREG_SAVE+56(%r1) |
| std %r11,STATIC_CHAIN_SAVE(%r1) |
| std %r29,R29_SAVE(%r1) |
| std %r12,LINKREG_SAVE(%r1) |
| std %r3,NEWSTACKSIZE_SAVE(%r1) # new stack size |
| mr %r29,%r1 |
| #if _CALL_ELF == 2 |
| .cfi_offset %r2,R2_SAVE |
| #endif |
| .cfi_offset %r29,R29_SAVE |
| .cfi_def_cfa_register %r29 |
| stdu %r1,-MORESTACK_FRAMESIZE(%r1) |
| |
| #if _CALL_ELF == 2 && !defined __PCREL__ |
| # If this isn't a pcrel libgcc then the functions we call here will |
| # require r2 to be valid. If __morestack is called from pcrel code r2 |
| # won't be valid. Set it up. |
| bcl 20,31,1f |
| 1: |
| mflr %r12 |
| addis %r2,%r12,.TOC.-1b@ha |
| addi %r2,%r2,.TOC.-1b@l |
| #endif |
| |
| # void __morestack_block_signals (void) |
| bl JUMP_TARGET(__morestack_block_signals) |
| |
| # void *__generic_morestack (size_t *pframe_size, |
| # void *old_stack, |
| # size_t param_size) |
| addi %r3,%r29,NEWSTACKSIZE_SAVE |
| mr %r4,%r29 |
| li %r5,0 # no copying from old stack |
| bl JUMP_TARGET(__generic_morestack) |
| |
| # Start using new stack |
| stdu %r29,-32(%r3) # back-chain |
| mr %r1,%r3 |
| |
| # Set __private_ss stack guard for the new stack. |
| ld %r12,NEWSTACKSIZE_SAVE(%r29) # modified size |
| addi %r3,%r3,BACKOFF-32 |
| sub %r3,%r3,%r12 |
| # Note that a signal frame has $pc pointing at the instruction |
| # where the signal occurred. For something like a timer |
| # interrupt this means the instruction has already executed, |
| # thus the region starts at the instruction modifying |
| # __private_ss, not one instruction after. |
| .LEHB0: |
| std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss |
| |
| # void __morestack_unblock_signals (void) |
| bl JUMP_TARGET(__morestack_unblock_signals) |
| |
| # Set up for a call to the target function, located 3 |
| # instructions after __morestack's return address. |
| # |
| ld %r12,LINKREG_SAVE(%r29) |
| #if _CALL_ELF == 2 |
| ld %r2,R2_SAVE(%r29) |
| #endif |
| ld %r3,PARAMREG_SAVE+0(%r29) # restore arg regs |
| ld %r4,PARAMREG_SAVE+8(%r29) |
| ld %r5,PARAMREG_SAVE+16(%r29) |
| ld %r6,PARAMREG_SAVE+24(%r29) |
| ld %r7,PARAMREG_SAVE+32(%r29) |
| ld %r8,PARAMREG_SAVE+40(%r29) |
| ld %r9,PARAMREG_SAVE+48(%r29) |
| addi %r0,%r12,12 # add 3 instructions |
| ld %r10,PARAMREG_SAVE+56(%r29) |
| ld %r11,STATIC_CHAIN_SAVE(%r29) |
| cmpld %cr7,%r12,%r0 # indicate we were called |
| mtctr %r0 |
| bctrl # call caller! |
| |
| # On return, save regs possibly used to return a value, and |
| # possibly trashed by calls to __morestack_block_signals, |
| # __generic_releasestack and __morestack_unblock_signals. |
| # Assume those calls don't use vector or floating point regs. |
| std %r3,PARAMREG_SAVE+0(%r29) |
| std %r4,PARAMREG_SAVE+8(%r29) |
| std %r5,PARAMREG_SAVE+16(%r29) |
| std %r6,PARAMREG_SAVE+24(%r29) |
| #if _CALL_ELF == 2 |
| std %r7,PARAMREG_SAVE+32(%r29) |
| std %r8,PARAMREG_SAVE+40(%r29) |
| std %r9,PARAMREG_SAVE+48(%r29) |
| std %r10,PARAMREG_SAVE+56(%r29) |
| #endif |
| |
| #if _CALL_ELF == 2 && !defined __PCREL__ |
| # r2 was restored for calling back into our caller. Set it up again. |
| bcl 20,31,1f |
| 1: |
| mflr %r12 |
| addis %r2,%r12,.TOC.-1b@ha |
| addi %r2,%r2,.TOC.-1b@l |
| #endif |
| |
| bl JUMP_TARGET(__morestack_block_signals) |
| |
| # void *__generic_releasestack (size_t *pavailable) |
| addi %r3,%r29,NEWSTACKSIZE_SAVE |
| bl JUMP_TARGET(__generic_releasestack) |
| |
| # Reset __private_ss stack guard to value for old stack |
| ld %r12,NEWSTACKSIZE_SAVE(%r29) |
| addi %r3,%r3,BACKOFF |
| sub %r3,%r3,%r12 |
| .LEHE0: |
| std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss |
| |
| bl JUMP_TARGET(__morestack_unblock_signals) |
| |
| # Use old stack again. |
| mr %r1,%r29 |
| |
| # Restore return value regs, and return. |
| ld %r0,LINKREG_SAVE(%r29) |
| mtlr %r0 |
| #if _CALL_ELF == 2 |
| ld %r2,R2_SAVE(%r29) |
| #endif |
| ld %r3,PARAMREG_SAVE+0(%r29) |
| ld %r4,PARAMREG_SAVE+8(%r29) |
| ld %r5,PARAMREG_SAVE+16(%r29) |
| ld %r6,PARAMREG_SAVE+24(%r29) |
| #if _CALL_ELF == 2 |
| ld %r7,PARAMREG_SAVE+32(%r29) |
| ld %r8,PARAMREG_SAVE+40(%r29) |
| ld %r9,PARAMREG_SAVE+48(%r29) |
| ld %r10,PARAMREG_SAVE+56(%r29) |
| #endif |
| ld %r29,R29_SAVE(%r29) |
| .cfi_def_cfa_register %r1 |
| blr |
| |
| # This is the cleanup code called by the stack unwinder when |
| # unwinding through code between .LEHB0 and .LEHE0 above. |
| cleanup: |
| .cfi_def_cfa_register %r29 |
| std %r3,PARAMREG_SAVE(%r29) # Save exception header |
| # size_t __generic_findstack (void *stack) |
| mr %r3,%r29 |
| bl JUMP_TARGET(__generic_findstack) |
| sub %r3,%r29,%r3 |
| addi %r3,%r3,BACKOFF |
| std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss |
| ld %r3,PARAMREG_SAVE(%r29) |
| bl JUMP_TARGET(_Unwind_Resume) |
| #ifndef __PCREL__ |
| nop |
| #endif |
| .cfi_endproc |
| SIZE (__morestack) |
| |
| |
| .section .gcc_except_table,"a",@progbits |
| .p2align 2 |
| .LLSDA1: |
| .byte 0xff # @LPStart format (omit) |
| .byte 0xff # @TType format (omit) |
| .byte 0x1 # call-site format (uleb128) |
| .uleb128 .LLSDACSE1-.LLSDACSB1 # Call-site table length |
| .LLSDACSB1: |
| .uleb128 .LEHB0-.LFB1 # region 0 start |
| .uleb128 .LEHE0-.LEHB0 # length |
| .uleb128 cleanup-.LFB1 # landing pad |
| .uleb128 0 # no action, ie. a cleanup |
| .LLSDACSE1: |
| |
| |
| #ifdef __PIC__ |
| # Build a position independent reference to the personality function. |
| .hidden DW.ref.__gcc_personality_v0 |
| .weak DW.ref.__gcc_personality_v0 |
| .section .data.DW.ref.__gcc_personality_v0,"awG",@progbits,DW.ref.__gcc_personality_v0,comdat |
| .p2align 3 |
| DW.ref.__gcc_personality_v0: |
| .quad __gcc_personality_v0 |
| .type DW.ref.__gcc_personality_v0, @object |
| .size DW.ref.__gcc_personality_v0, 8 |
| #endif |
| |
| |
| .text |
| # Initialize the stack guard when the program starts or when a |
| # new thread starts. This is called from a constructor. |
| # void __stack_split_initialize (void) |
| ENTRY(__stack_split_initialize) |
| .cfi_startproc |
| addi %r3,%r1,-0x4000 # We should have at least 16K. |
| std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss |
| # void __generic_morestack_set_initial_sp (void *sp, size_t len) |
| mr %r3,%r1 |
| li %r4, 0x4000 |
| b JUMP_TARGET(__generic_morestack_set_initial_sp) |
| # The lack of .cfi_endproc here is deliberate. This function and the |
| # following ones can all use the default FDE. |
| SIZE (__stack_split_initialize) |
| |
| |
| # Return current __private_ss |
| # void *__morestack_get_guard (void) |
| ENTRY0(__morestack_get_guard) |
| ld %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss |
| blr |
| SIZE (__morestack_get_guard) |
| |
| |
| # Set __private_ss |
| # void __morestack_set_guard (void *ptr) |
| ENTRY0(__morestack_set_guard) |
| std %r3,-0x7000-64(%r13) # tcbhead_t.__private_ss |
| blr |
| SIZE (__morestack_set_guard) |
| |
| |
| # Return the stack guard value for given stack |
| # void *__morestack_make_guard (void *stack, size_t size) |
| ENTRY0(__morestack_make_guard) |
| sub %r3,%r3,%r4 |
| addi %r3,%r3,BACKOFF |
| blr |
| .cfi_endproc |
| SIZE (__morestack_make_guard) |
| |
| |
| # Make __stack_split_initialize a high priority constructor. |
| #if HAVE_INITFINI_ARRAY_SUPPORT |
| .section .init_array.00000,"aw",@progbits |
| #else |
| .section .ctors.65535,"aw",@progbits |
| #endif |
| .p2align 3 |
| .quad __stack_split_initialize |
| .quad __morestack_load_mmap |
| |
| .section .note.GNU-stack,"",@progbits |
| .section .note.GNU-split-stack,"",@progbits |
| .section .note.GNU-no-split-stack,"",@progbits |
| #endif /* __powerpc64__ */ |