aboutsummaryrefslogtreecommitdiff
path: root/libgcc/config/s390
diff options
context:
space:
mode:
authorMarcin Koƛcielnicki <koriakin@0x04.net>2016-02-15 10:20:18 +0000
committerAndreas Krebbel <krebbel@gcc.gnu.org>2016-02-15 10:20:18 +0000
commit4cb4721f9371ac318e33cbed99a66a029353e10a (patch)
tree633620a331dce10653b1b110b0531b75f5ee2376 /libgcc/config/s390
parent17a3b967929eb6d344ae73bff4f28efc88c35ca9 (diff)
downloadgcc-4cb4721f9371ac318e33cbed99a66a029353e10a.zip
gcc-4cb4721f9371ac318e33cbed99a66a029353e10a.tar.gz
gcc-4cb4721f9371ac318e33cbed99a66a029353e10a.tar.bz2
S/390: Add -fsplit-stack support
libgcc/ChangeLog: * config.host: Use t-stack and t-stack-s390 for s390*-*-linux. * config/s390/morestack.S: New file. * config/s390/t-stack-s390: New file. * generic-morestack.c (__splitstack_find): Add s390-specific code. gcc/ChangeLog: * common/config/s390/s390-common.c (s390_supports_split_stack): New function. (TARGET_SUPPORTS_SPLIT_STACK): New macro. * config/s390/s390-protos.h: Add s390_expand_split_stack_prologue. * config/s390/s390.c (struct machine_function): New field split_stack_varargs_pointer. (s390_register_info): Mark r12 as clobbered if it'll be used as temp in s390_emit_prologue. (s390_emit_prologue): Use r12 as temp if r1 is taken by split-stack vararg pointer. (morestack_ref): New global. (SPLIT_STACK_AVAILABLE): New macro. (s390_expand_split_stack_prologue): New function. (s390_live_on_entry): New function. (s390_va_start): Use split-stack vararg pointer if appropriate. (s390_asm_file_end): Emit the split-stack note sections. (TARGET_EXTRA_LIVE_ON_ENTRY): New macro. * config/s390/s390.md (UNSPEC_STACK_CHECK): New unspec. (UNSPECV_SPLIT_STACK_CALL): New unspec. (UNSPECV_SPLIT_STACK_DATA): New unspec. (split_stack_prologue): New expand. (split_stack_space_check): New expand. (split_stack_data): New insn. (split_stack_call): New expand. (split_stack_call_*): New insn. (split_stack_cond_call): New expand. (split_stack_cond_call_*): New insn. From-SVN: r233421
Diffstat (limited to 'libgcc/config/s390')
-rw-r--r--libgcc/config/s390/morestack.S611
-rw-r--r--libgcc/config/s390/t-stack-s3902
2 files changed, 613 insertions, 0 deletions
diff --git a/libgcc/config/s390/morestack.S b/libgcc/config/s390/morestack.S
new file mode 100644
index 0000000..fa6951b
--- /dev/null
+++ b/libgcc/config/s390/morestack.S
@@ -0,0 +1,611 @@
+# s390 support for -fsplit-stack.
+# Copyright (C) 2015 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
+
+# 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
diff --git a/libgcc/config/s390/t-stack-s390 b/libgcc/config/s390/t-stack-s390
new file mode 100644
index 0000000..4c959b0
--- /dev/null
+++ b/libgcc/config/s390/t-stack-s390
@@ -0,0 +1,2 @@
+# Makefile fragment to support -fsplit-stack for s390.
+LIB2ADD_ST += $(srcdir)/config/s390/morestack.S