| # s390 support for -fsplit-stack. |
| # Copyright (C) 2015-2021 Free Software Foundation, Inc. |
| # Contributed by Marcin KoĆcielnicki <koriakin@0x04.net>. |
| |
| # 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/>. |
| |
| # 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 0x1000 |
| |
| #include <auto-host.h> |
| |
| # The __morestack function. |
| |
| .global __morestack |
| .hidden __morestack |
| |
| .type __morestack,@function |
| |
| __morestack: |
| .LFB1: |
| .cfi_startproc |
| |
| |
| #ifndef __s390x__ |
| |
| |
| # The 31-bit __morestack function. |
| |
| # We use a cleanup to restore the stack guard if an exception |
| # is thrown through this code. |
| #ifndef __PIC__ |
| .cfi_personality 0,__gcc_personality_v0 |
| .cfi_lsda 0,.LLSDA1 |
| #else |
| .cfi_personality 0x9b,DW.ref.__gcc_personality_v0 |
| .cfi_lsda 0x1b,.LLSDA1 |
| #endif |
| |
| stm %r2, %r15, 0x8(%r15) # Save %r2-%r15. |
| .cfi_offset %r6, -0x48 |
| .cfi_offset %r7, -0x44 |
| .cfi_offset %r8, -0x40 |
| .cfi_offset %r9, -0x3c |
| .cfi_offset %r10, -0x38 |
| .cfi_offset %r11, -0x34 |
| .cfi_offset %r12, -0x30 |
| .cfi_offset %r13, -0x2c |
| .cfi_offset %r14, -0x28 |
| .cfi_offset %r15, -0x24 |
| lr %r11, %r15 # Make frame pointer for vararg. |
| .cfi_def_cfa_register %r11 |
| ahi %r15, -0x60 # 0x60 for standard frame. |
| st %r11, 0(%r15) # Save back chain. |
| lr %r8, %r0 # Save %r0 (static chain). |
| lr %r10, %r1 # Save %r1 (address of parameter block). |
| |
| l %r7, 0(%r10) # Required frame size to %r7 |
| ear %r1, %a0 # Extract thread pointer. |
| l %r1, 0x20(%r1) # Get stack bounduary |
| ar %r1, %r7 # Stack bounduary + frame size |
| a %r1, 4(%r10) # + stack param size |
| clr %r1, %r15 # Compare with current stack pointer |
| jle .Lnoalloc # guard > sp - frame-size: need alloc |
| |
| brasl %r14, __morestack_block_signals |
| |
| # We abuse one of caller's fpr save slots (which we don't use for fprs) |
| # as a local variable. Not needed here, but done to be consistent with |
| # the below use. |
| ahi %r7, BACKOFF # Bump requested size a bit. |
| st %r7, 0x40(%r11) # Stuff frame size on stack. |
| la %r2, 0x40(%r11) # Pass its address as parameter. |
| la %r3, 0x60(%r11) # Caller's stack parameters. |
| l %r4, 4(%r10) # Size of stack parameters. |
| brasl %r14, __generic_morestack |
| |
| lr %r15, %r2 # Switch to the new stack. |
| ahi %r15, -0x60 # Make a stack frame on it. |
| st %r11, 0(%r15) # Save back chain. |
| |
| s %r2, 0x40(%r11) # The end of stack space. |
| ahi %r2, BACKOFF # Back off a bit. |
| ear %r1, %a0 # Extract thread pointer. |
| .LEHB0: |
| st %r2, 0x20(%r1) # Save the new stack boundary. |
| |
| brasl %r14, __morestack_unblock_signals |
| |
| lr %r0, %r8 # Static chain. |
| lm %r2, %r6, 0x8(%r11) # Paremeter registers. |
| |
| # Third parameter is address of function meat - address of parameter |
| # block. |
| a %r10, 0x8(%r10) |
| |
| # Leave vararg pointer in %r1, in case function uses it |
| la %r1, 0x60(%r11) |
| |
| # State of registers: |
| # %r0: Static chain from entry. |
| # %r1: Vararg pointer. |
| # %r2-%r6: Parameters from entry. |
| # %r7-%r10: Indeterminate. |
| # %r11: Frame pointer (%r15 from entry). |
| # %r12-%r13: Indeterminate. |
| # %r14: Return address. |
| # %r15: Stack pointer. |
| basr %r14, %r10 # Call our caller. |
| |
| stm %r2, %r3, 0x8(%r11) # Save return registers. |
| |
| brasl %r14, __morestack_block_signals |
| |
| # We need a stack slot now, but have no good way to get it - the frame |
| # on new stack had to be exactly 0x60 bytes, or stack parameters would |
| # be passed wrong. Abuse fpr save area in caller's frame (we don't |
| # save actual fprs). |
| la %r2, 0x40(%r11) |
| brasl %r14, __generic_releasestack |
| |
| s %r2, 0x40(%r11) # Subtract available space. |
| ahi %r2, BACKOFF # Back off a bit. |
| ear %r1, %a0 # Extract thread pointer. |
| .LEHE0: |
| st %r2, 0x20(%r1) # Save the new stack boundary. |
| |
| # We need to restore the old stack pointer before unblocking signals. |
| # We also need 0x60 bytes for a stack frame. Since we had a stack |
| # frame at this place before the stack switch, there's no need to |
| # write the back chain again. |
| lr %r15, %r11 |
| ahi %r15, -0x60 |
| |
| brasl %r14, __morestack_unblock_signals |
| |
| lm %r2, %r15, 0x8(%r11) # Restore all registers. |
| .cfi_remember_state |
| .cfi_restore %r15 |
| .cfi_restore %r14 |
| .cfi_restore %r13 |
| .cfi_restore %r12 |
| .cfi_restore %r11 |
| .cfi_restore %r10 |
| .cfi_restore %r9 |
| .cfi_restore %r8 |
| .cfi_restore %r7 |
| .cfi_restore %r6 |
| .cfi_def_cfa_register %r15 |
| br %r14 # Return to caller's caller. |
| |
| # Executed if no new stack allocation is needed. |
| |
| .Lnoalloc: |
| .cfi_restore_state |
| # We may need to copy stack parameters. |
| l %r9, 0x4(%r10) # Load stack parameter size. |
| ltr %r9, %r9 # And check if it's 0. |
| je .Lnostackparm # Skip the copy if not needed. |
| sr %r15, %r9 # Make space on the stack. |
| la %r8, 0x60(%r15) # Destination. |
| la %r12, 0x60(%r11) # Source. |
| lr %r13, %r9 # Source size. |
| .Lcopy: |
| mvcle %r8, %r12, 0 # Copy. |
| jo .Lcopy |
| |
| .Lnostackparm: |
| # Third parameter is address of function meat - address of parameter |
| # block. |
| a %r10, 0x8(%r10) |
| |
| # Leave vararg pointer in %r1, in case function uses it |
| la %r1, 0x60(%r11) |
| |
| # OK, no stack allocation needed. We still follow the protocol and |
| # call our caller - it doesn't cost much and makes sure vararg works. |
| # No need to set any registers here - %r0 and %r2-%r6 weren't modified. |
| basr %r14, %r10 # Call our caller. |
| |
| lm %r6, %r15, 0x18(%r11) # Restore all callee-saved registers. |
| .cfi_remember_state |
| .cfi_restore %r15 |
| .cfi_restore %r14 |
| .cfi_restore %r13 |
| .cfi_restore %r12 |
| .cfi_restore %r11 |
| .cfi_restore %r10 |
| .cfi_restore %r9 |
| .cfi_restore %r8 |
| .cfi_restore %r7 |
| .cfi_restore %r6 |
| .cfi_def_cfa_register %r15 |
| br %r14 # Return to caller's caller. |
| |
| # This is the cleanup code called by the stack unwinder when unwinding |
| # through the code between .LEHB0 and .LEHE0 above. |
| |
| .L1: |
| .cfi_restore_state |
| lr %r2, %r11 # Stack pointer after resume. |
| brasl %r14, __generic_findstack |
| lr %r3, %r11 # Get the stack pointer. |
| sr %r3, %r2 # Subtract available space. |
| ahi %r3, BACKOFF # Back off a bit. |
| ear %r1, %a0 # Extract thread pointer. |
| st %r3, 0x20(%r1) # Save the new stack boundary. |
| |
| # We need GOT pointer in %r12 for PLT entry. |
| larl %r12,_GLOBAL_OFFSET_TABLE_ |
| lr %r2, %r6 # Exception header. |
| #ifdef __PIC__ |
| brasl %r14, _Unwind_Resume@PLT |
| #else |
| brasl %r14, _Unwind_Resume |
| #endif |
| |
| #else /* defined(__s390x__) */ |
| |
| |
| # The 64-bit __morestack function. |
| |
| # We use a cleanup to restore the stack guard if an exception |
| # is thrown through this code. |
| #ifndef __PIC__ |
| .cfi_personality 0x3,__gcc_personality_v0 |
| .cfi_lsda 0x3,.LLSDA1 |
| #else |
| .cfi_personality 0x9b,DW.ref.__gcc_personality_v0 |
| .cfi_lsda 0x1b,.LLSDA1 |
| #endif |
| |
| stmg %r2, %r15, 0x10(%r15) # Save %r2-%r15. |
| .cfi_offset %r6, -0x70 |
| .cfi_offset %r7, -0x68 |
| .cfi_offset %r8, -0x60 |
| .cfi_offset %r9, -0x58 |
| .cfi_offset %r10, -0x50 |
| .cfi_offset %r11, -0x48 |
| .cfi_offset %r12, -0x40 |
| .cfi_offset %r13, -0x38 |
| .cfi_offset %r14, -0x30 |
| .cfi_offset %r15, -0x28 |
| lgr %r11, %r15 # Make frame pointer for vararg. |
| .cfi_def_cfa_register %r11 |
| aghi %r15, -0xa0 # 0xa0 for standard frame. |
| stg %r11, 0(%r15) # Save back chain. |
| lgr %r8, %r0 # Save %r0 (static chain). |
| lgr %r10, %r1 # Save %r1 (address of parameter block). |
| |
| lg %r7, 0(%r10) # Required frame size to %r7 |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 # Extract thread pointer. |
| lg %r1, 0x38(%r1) # Get stack bounduary |
| agr %r1, %r7 # Stack bounduary + frame size |
| ag %r1, 8(%r10) # + stack param size |
| clgr %r1, %r15 # Compare with current stack pointer |
| jle .Lnoalloc # guard > sp - frame-size: need alloc |
| |
| brasl %r14, __morestack_block_signals |
| |
| # We abuse one of caller's fpr save slots (which we don't use for fprs) |
| # as a local variable. Not needed here, but done to be consistent with |
| # the below use. |
| aghi %r7, BACKOFF # Bump requested size a bit. |
| stg %r7, 0x80(%r11) # Stuff frame size on stack. |
| la %r2, 0x80(%r11) # Pass its address as parameter. |
| la %r3, 0xa0(%r11) # Caller's stack parameters. |
| lg %r4, 8(%r10) # Size of stack parameters. |
| brasl %r14, __generic_morestack |
| |
| lgr %r15, %r2 # Switch to the new stack. |
| aghi %r15, -0xa0 # Make a stack frame on it. |
| stg %r11, 0(%r15) # Save back chain. |
| |
| sg %r2, 0x80(%r11) # The end of stack space. |
| aghi %r2, BACKOFF # Back off a bit. |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 # Extract thread pointer. |
| .LEHB0: |
| stg %r2, 0x38(%r1) # Save the new stack boundary. |
| |
| brasl %r14, __morestack_unblock_signals |
| |
| lgr %r0, %r8 # Static chain. |
| lmg %r2, %r6, 0x10(%r11) # Paremeter registers. |
| |
| # Third parameter is address of function meat - address of parameter |
| # block. |
| ag %r10, 0x10(%r10) |
| |
| # Leave vararg pointer in %r1, in case function uses it |
| la %r1, 0xa0(%r11) |
| |
| # State of registers: |
| # %r0: Static chain from entry. |
| # %r1: Vararg pointer. |
| # %r2-%r6: Parameters from entry. |
| # %r7-%r10: Indeterminate. |
| # %r11: Frame pointer (%r15 from entry). |
| # %r12-%r13: Indeterminate. |
| # %r14: Return address. |
| # %r15: Stack pointer. |
| basr %r14, %r10 # Call our caller. |
| |
| stg %r2, 0x10(%r11) # Save return register. |
| |
| brasl %r14, __morestack_block_signals |
| |
| # We need a stack slot now, but have no good way to get it - the frame |
| # on new stack had to be exactly 0xa0 bytes, or stack parameters would |
| # be passed wrong. Abuse fpr save area in caller's frame (we don't |
| # save actual fprs). |
| la %r2, 0x80(%r11) |
| brasl %r14, __generic_releasestack |
| |
| sg %r2, 0x80(%r11) # Subtract available space. |
| aghi %r2, BACKOFF # Back off a bit. |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 # Extract thread pointer. |
| .LEHE0: |
| stg %r2, 0x38(%r1) # Save the new stack boundary. |
| |
| # We need to restore the old stack pointer before unblocking signals. |
| # We also need 0xa0 bytes for a stack frame. Since we had a stack |
| # frame at this place before the stack switch, there's no need to |
| # write the back chain again. |
| lgr %r15, %r11 |
| aghi %r15, -0xa0 |
| |
| brasl %r14, __morestack_unblock_signals |
| |
| lmg %r2, %r15, 0x10(%r11) # Restore all registers. |
| .cfi_remember_state |
| .cfi_restore %r15 |
| .cfi_restore %r14 |
| .cfi_restore %r13 |
| .cfi_restore %r12 |
| .cfi_restore %r11 |
| .cfi_restore %r10 |
| .cfi_restore %r9 |
| .cfi_restore %r8 |
| .cfi_restore %r7 |
| .cfi_restore %r6 |
| .cfi_def_cfa_register %r15 |
| br %r14 # Return to caller's caller. |
| |
| # Executed if no new stack allocation is needed. |
| |
| .Lnoalloc: |
| .cfi_restore_state |
| # We may need to copy stack parameters. |
| lg %r9, 0x8(%r10) # Load stack parameter size. |
| ltgr %r9, %r9 # Check if it's 0. |
| je .Lnostackparm # Skip the copy if not needed. |
| sgr %r15, %r9 # Make space on the stack. |
| la %r8, 0xa0(%r15) # Destination. |
| la %r12, 0xa0(%r11) # Source. |
| lgr %r13, %r9 # Source size. |
| .Lcopy: |
| mvcle %r8, %r12, 0 # Copy. |
| jo .Lcopy |
| |
| .Lnostackparm: |
| # Third parameter is address of function meat - address of parameter |
| # block. |
| ag %r10, 0x10(%r10) |
| |
| # Leave vararg pointer in %r1, in case function uses it |
| la %r1, 0xa0(%r11) |
| |
| # OK, no stack allocation needed. We still follow the protocol and |
| # call our caller - it doesn't cost much and makes sure vararg works. |
| # No need to set any registers here - %r0 and %r2-%r6 weren't modified. |
| basr %r14, %r10 # Call our caller. |
| |
| lmg %r6, %r15, 0x30(%r11) # Restore all callee-saved registers. |
| .cfi_remember_state |
| .cfi_restore %r15 |
| .cfi_restore %r14 |
| .cfi_restore %r13 |
| .cfi_restore %r12 |
| .cfi_restore %r11 |
| .cfi_restore %r10 |
| .cfi_restore %r9 |
| .cfi_restore %r8 |
| .cfi_restore %r7 |
| .cfi_restore %r6 |
| .cfi_def_cfa_register %r15 |
| br %r14 # Return to caller's caller. |
| |
| # This is the cleanup code called by the stack unwinder when unwinding |
| # through the code between .LEHB0 and .LEHE0 above. |
| |
| .L1: |
| .cfi_restore_state |
| lgr %r2, %r11 # Stack pointer after resume. |
| brasl %r14, __generic_findstack |
| lgr %r3, %r11 # Get the stack pointer. |
| sgr %r3, %r2 # Subtract available space. |
| aghi %r3, BACKOFF # Back off a bit. |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 # Extract thread pointer. |
| stg %r3, 0x38(%r1) # Save the new stack boundary. |
| |
| lgr %r2, %r6 # Exception header. |
| #ifdef __PIC__ |
| brasl %r14, _Unwind_Resume@PLT |
| #else |
| brasl %r14, _Unwind_Resume |
| #endif |
| |
| #endif /* defined(__s390x__) */ |
| |
| .cfi_endproc |
| .size __morestack, . - __morestack |
| |
| |
| # The exception table. This tells the personality routine to execute |
| # the exception handler. |
| |
| .section .gcc_except_table,"a",@progbits |
| .align 4 |
| .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 .L1-.LFB1 # landing pad |
| .uleb128 0 # action |
| .LLSDACSE1: |
| |
| |
| .global __gcc_personality_v0 |
| #ifdef __PIC__ |
| # Build a position independent reference to the basic |
| # 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 |
| .type DW.ref.__gcc_personality_v0, @object |
| DW.ref.__gcc_personality_v0: |
| #ifndef __LP64__ |
| .align 4 |
| .size DW.ref.__gcc_personality_v0, 4 |
| .long __gcc_personality_v0 |
| #else |
| .align 8 |
| .size DW.ref.__gcc_personality_v0, 8 |
| .quad __gcc_personality_v0 |
| #endif |
| #endif |
| |
| |
| |
| # Initialize the stack test value when the program starts or when a |
| # new thread starts. We don't know how large the main stack is, so we |
| # guess conservatively. We might be able to use getrlimit here. |
| |
| .text |
| .global __stack_split_initialize |
| .hidden __stack_split_initialize |
| |
| .type __stack_split_initialize, @function |
| |
| __stack_split_initialize: |
| |
| #ifndef __s390x__ |
| |
| ear %r1, %a0 |
| lr %r0, %r15 |
| ahi %r0, -0x4000 # We should have at least 16K. |
| st %r0, 0x20(%r1) |
| |
| lr %r2, %r15 |
| lhi %r3, 0x4000 |
| #ifdef __PIC__ |
| jg __generic_morestack_set_initial_sp@PLT # Tail call |
| #else |
| jg __generic_morestack_set_initial_sp # Tail call |
| #endif |
| |
| #else /* defined(__s390x__) */ |
| |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 |
| lgr %r0, %r15 |
| aghi %r0, -0x4000 # We should have at least 16K. |
| stg %r0, 0x38(%r1) |
| |
| lgr %r2, %r15 |
| lghi %r3, 0x4000 |
| #ifdef __PIC__ |
| jg __generic_morestack_set_initial_sp@PLT # Tail call |
| #else |
| jg __generic_morestack_set_initial_sp # Tail call |
| #endif |
| |
| #endif /* defined(__s390x__) */ |
| |
| .size __stack_split_initialize, . - __stack_split_initialize |
| |
| # Routines to get and set the guard, for __splitstack_getcontext, |
| # __splitstack_setcontext, and __splitstack_makecontext. |
| |
| # void *__morestack_get_guard (void) returns the current stack guard. |
| .text |
| .global __morestack_get_guard |
| .hidden __morestack_get_guard |
| |
| .type __morestack_get_guard,@function |
| |
| __morestack_get_guard: |
| |
| #ifndef __s390x__ |
| ear %r1, %a0 |
| l %r2, 0x20(%r1) |
| #else |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 |
| lg %r2, 0x38(%r1) |
| #endif |
| br %r14 |
| |
| .size __morestack_get_guard, . - __morestack_get_guard |
| |
| # void __morestack_set_guard (void *) sets the stack guard. |
| .global __morestack_set_guard |
| .hidden __morestack_set_guard |
| |
| .type __morestack_set_guard,@function |
| |
| __morestack_set_guard: |
| |
| #ifndef __s390x__ |
| ear %r1, %a0 |
| st %r2, 0x20(%r1) |
| #else |
| ear %r1, %a0 |
| sllg %r1, %r1, 32 |
| ear %r1, %a1 |
| stg %r2, 0x38(%r1) |
| #endif |
| br %r14 |
| |
| .size __morestack_set_guard, . - __morestack_set_guard |
| |
| # void *__morestack_make_guard (void *, size_t) returns the stack |
| # guard value for a stack. |
| .global __morestack_make_guard |
| .hidden __morestack_make_guard |
| |
| .type __morestack_make_guard,@function |
| |
| __morestack_make_guard: |
| |
| #ifndef __s390x__ |
| sr %r2, %r3 |
| ahi %r2, BACKOFF |
| #else |
| sgr %r2, %r3 |
| aghi %r2, BACKOFF |
| #endif |
| br %r14 |
| |
| .size __morestack_make_guard, . - __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 |
| |
| #ifndef __LP64__ |
| .align 4 |
| .long __stack_split_initialize |
| .long __morestack_load_mmap |
| #else |
| .align 8 |
| .quad __stack_split_initialize |
| .quad __morestack_load_mmap |
| #endif |
| |
| .section .note.GNU-stack,"",@progbits |
| .section .note.GNU-split-stack,"",@progbits |
| .section .note.GNU-no-split-stack,"",@progbits |