# s390 support for -fsplit-stack. # Copyright (C) 2015-2019 Free Software Foundation, Inc. # Contributed by Marcin Koƛcielnicki . # 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 # . # 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 # 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. .section .ctors.65535,"aw",@progbits #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