This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] [RFC] [GOLD] s390 -fsplit-stack support.


On 11/12/15 23:27, Cary Coutant wrote:
I think it's reasonable to expect that a target implementation of
do_calls_non_split may need prelocs, reloc_count, and Output_file*, so
I don't have a problem adding those to the signatures of
Sized_relobj_file::split_stack_adjust,
Sized_relobj_file::split_stack_adjust_reltype,
Target::calls_non_split, and Target::do_calls_non_split.

With this patch, we won't have to add the Output_file pointer to these
function signatures.

I've also committed the attached patch to add prelocs and reloc_count
parameters to Target::calls_non_split and Target::do_calls_non_split.

-cary

Thanks for the patches! I've updated mine, and the changes are now limitted to s390-specific code. The output_view patch has a minor problem: it returns a const unsigned char *, but I need a read-write view (I have to bump the frame size in the parameter block). I've just const_casted around it for now, but I suppose we should change the return type instead?

Also, I still have an icky static_cast in the "find parameter block" sequence. but I suppose it's here to stay:

+             Sized_relobj_file<size, true> *object_sized =
+               static_cast<Sized_relobj_file<size, true> *>(object);
+ const Symbol_value<size>* sym = object_sized->local_symbol(r_sym);
+             bool param_shndx_ordinary;
+             const unsigned int param_shndx =
+               sym->input_shndx(&param_shndx_ordinary);
+             if (!param_shndx_ordinary)
+               goto bad;
+             param_offset = sym->input_value() + reloc.get_r_addend() - 2
+ - object->output_section(param_shndx)->address();
+             param_view = const_cast<unsigned char*>(
+                             object->get_output_view(param_shndx,
+                                                     &param_view_size));

I have also fixed the line lengths and added the ChangeLog.

Btw, this patch shouldn't be landing yet, I still have to finish the gcc side.

Marcin KoÅcielnicki
>From 451e886bf9c95312d0aaeb35d3f7d9ae2062482b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marcin=20Ko=C5=9Bcielnicki?= <koriakin@0x04.net>
Date: Sun, 13 Dec 2015 02:53:09 +0100
Subject: [PATCH] gold: Add s390 -fsplit-stack support.

gold/ChangeLog:

	* s390.cc (Target_s390::match_view_u): New helper method.
	(Target_s390::ss_code_nopmark): New const.
	(Target_s390::ss_code_ear): New const.
	(Target_s390::ss_code_c): New const.
	(Target_s390::ss_code_l): New const.
	(Target_s390::ss_code_ahi): New const.
	(Target_s390::ss_code_alfi): New const.
	(Target_s390::ss_code_cr): New const.
	(Target_s390::ss_code_larl): New const.
	(Target_s390::ss_code_jg): New const.
	(Target_s390::ss_code_jgl): New const.
	(Target_s390::ss_code_jl): New const.
	(Target_s390::ss_code_jhe): New const.
	(Target_s390::ss_code_basr): New const.
	(Target_s390::ss_code_basr_2): New const.
	(Target_s390::do_calls_non_split): New method.
	* testsuite/Makefile.am: Added new tests.
	* testsuite/split_s390.sh: New test.
	* testsuite/split_s390_1_a1.s: New test.
	* testsuite/split_s390_1_a2.s: New test.
	* testsuite/split_s390_1_e1.s: New test.
	* testsuite/split_s390_1_e2.s: New test.
	* testsuite/split_s390_1_e3.s: New test.
	* testsuite/split_s390_1_e4.s: New test.
	* testsuite/split_s390_1_n.s: New test.
	* testsuite/split_s390_1_z1.s: New test.
	* testsuite/split_s390_1_z2.s: New test.
	* testsuite/split_s390_1_z3.s: New test.
	* testsuite/split_s390_1_z4.s: New test.
	* testsuite/split_s390_2_ns.s: New test.
	* testsuite/split_s390_2_s.s: New test.
	* testsuite/split_s390x_1_a1.s: New test.
	* testsuite/split_s390x_1_a2.s: New test.
	* testsuite/split_s390x_1_n.s: New test.
	* testsuite/split_s390x_1_z1.s: New test.
	* testsuite/split_s390x_1_z2.s: New test.
	* testsuite/split_s390x_1_z3.s: New test.
	* testsuite/split_s390x_1_z4.s: New test.
	* testsuite/split_s390x_2_ns.s: New test.
	* testsuite/split_s390x_2_s.s: New test.
---
 gold/ChangeLog                    |  43 ++++
 gold/s390.cc                      | 453 ++++++++++++++++++++++++++++++++++++++
 gold/testsuite/Makefile.am        | 204 +++++++++++++++++
 gold/testsuite/split_s390.sh      | 149 +++++++++++++
 gold/testsuite/split_s390_1_a1.s  |  36 +++
 gold/testsuite/split_s390_1_a2.s  |  37 ++++
 gold/testsuite/split_s390_1_e1.s  |  45 ++++
 gold/testsuite/split_s390_1_e2.s  |  48 ++++
 gold/testsuite/split_s390_1_e3.s  |  49 +++++
 gold/testsuite/split_s390_1_e4.s  |  51 +++++
 gold/testsuite/split_s390_1_n.s   |  18 ++
 gold/testsuite/split_s390_1_z1.s  |  37 ++++
 gold/testsuite/split_s390_1_z2.s  |  40 ++++
 gold/testsuite/split_s390_1_z3.s  |  41 ++++
 gold/testsuite/split_s390_1_z4.s  |  41 ++++
 gold/testsuite/split_s390_2_ns.s  |  12 +
 gold/testsuite/split_s390_2_s.s   |  13 ++
 gold/testsuite/split_s390x_1_a1.s |  27 +++
 gold/testsuite/split_s390x_1_a2.s |  28 +++
 gold/testsuite/split_s390x_1_n.s  |  17 ++
 gold/testsuite/split_s390x_1_z1.s |  37 ++++
 gold/testsuite/split_s390x_1_z2.s |  41 ++++
 gold/testsuite/split_s390x_1_z3.s |  43 ++++
 gold/testsuite/split_s390x_1_z4.s |  43 ++++
 gold/testsuite/split_s390x_2_ns.s |  12 +
 gold/testsuite/split_s390x_2_s.s  |  13 ++
 26 files changed, 1578 insertions(+)
 create mode 100755 gold/testsuite/split_s390.sh
 create mode 100644 gold/testsuite/split_s390_1_a1.s
 create mode 100644 gold/testsuite/split_s390_1_a2.s
 create mode 100644 gold/testsuite/split_s390_1_e1.s
 create mode 100644 gold/testsuite/split_s390_1_e2.s
 create mode 100644 gold/testsuite/split_s390_1_e3.s
 create mode 100644 gold/testsuite/split_s390_1_e4.s
 create mode 100644 gold/testsuite/split_s390_1_n.s
 create mode 100644 gold/testsuite/split_s390_1_z1.s
 create mode 100644 gold/testsuite/split_s390_1_z2.s
 create mode 100644 gold/testsuite/split_s390_1_z3.s
 create mode 100644 gold/testsuite/split_s390_1_z4.s
 create mode 100644 gold/testsuite/split_s390_2_ns.s
 create mode 100644 gold/testsuite/split_s390_2_s.s
 create mode 100644 gold/testsuite/split_s390x_1_a1.s
 create mode 100644 gold/testsuite/split_s390x_1_a2.s
 create mode 100644 gold/testsuite/split_s390x_1_n.s
 create mode 100644 gold/testsuite/split_s390x_1_z1.s
 create mode 100644 gold/testsuite/split_s390x_1_z2.s
 create mode 100644 gold/testsuite/split_s390x_1_z3.s
 create mode 100644 gold/testsuite/split_s390x_1_z4.s
 create mode 100644 gold/testsuite/split_s390x_2_ns.s
 create mode 100644 gold/testsuite/split_s390x_2_s.s

diff --git a/gold/ChangeLog b/gold/ChangeLog
index e039ab1..3c8f992 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,46 @@
+2015-12-13  Marcin KoÅ?cielnicki  <koriakin@0x04.net>
+
+	* s390.cc (Target_s390::match_view_u): New helper method.
+	(Target_s390::ss_code_nopmark): New const.
+	(Target_s390::ss_code_ear): New const.
+	(Target_s390::ss_code_c): New const.
+	(Target_s390::ss_code_l): New const.
+	(Target_s390::ss_code_ahi): New const.
+	(Target_s390::ss_code_alfi): New const.
+	(Target_s390::ss_code_cr): New const.
+	(Target_s390::ss_code_larl): New const.
+	(Target_s390::ss_code_jg): New const.
+	(Target_s390::ss_code_jgl): New const.
+	(Target_s390::ss_code_jl): New const.
+	(Target_s390::ss_code_jhe): New const.
+	(Target_s390::ss_code_basr): New const.
+	(Target_s390::ss_code_basr_2): New const.
+	(Target_s390::do_calls_non_split): New method.
+	* testsuite/Makefile.am: Added new tests.
+	* testsuite/split_s390.sh: New test.
+	* testsuite/split_s390_1_a1.s: New test.
+	* testsuite/split_s390_1_a2.s: New test.
+	* testsuite/split_s390_1_e1.s: New test.
+	* testsuite/split_s390_1_e2.s: New test.
+	* testsuite/split_s390_1_e3.s: New test.
+	* testsuite/split_s390_1_e4.s: New test.
+	* testsuite/split_s390_1_n.s: New test.
+	* testsuite/split_s390_1_z1.s: New test.
+	* testsuite/split_s390_1_z2.s: New test.
+	* testsuite/split_s390_1_z3.s: New test.
+	* testsuite/split_s390_1_z4.s: New test.
+	* testsuite/split_s390_2_ns.s: New test.
+	* testsuite/split_s390_2_s.s: New test.
+	* testsuite/split_s390x_1_a1.s: New test.
+	* testsuite/split_s390x_1_a2.s: New test.
+	* testsuite/split_s390x_1_n.s: New test.
+	* testsuite/split_s390x_1_z1.s: New test.
+	* testsuite/split_s390x_1_z2.s: New test.
+	* testsuite/split_s390x_1_z3.s: New test.
+	* testsuite/split_s390x_1_z4.s: New test.
+	* testsuite/split_s390x_2_ns.s: New test.
+	* testsuite/split_s390x_2_s.s: New test.
+
 2015-12-11  Cary Coutant  <ccoutant@gmail.com>
 
 	* target.h (Target::calls_non_split): Add prelocs, reloc_count
diff --git a/gold/s390.cc b/gold/s390.cc
index 45c0ba7..91cb880 100644
--- a/gold/s390.cc
+++ b/gold/s390.cc
@@ -402,6 +402,14 @@ class Target_s390 : public Sized_target<size, true>
   do_can_check_for_function_pointers() const
   { return true; }
 
+  // Adjust -fsplit-stack code which calls non-split-stack code.
+  void
+  do_calls_non_split(Relobj* object, unsigned int shndx,
+		     section_offset_type fnoffset, section_size_type fnsize,
+		     const unsigned char* prelocs, size_t reloc_count,
+		     unsigned char* view, section_size_type view_size,
+		     std::string* from, std::string* to) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size() const
@@ -687,6 +695,17 @@ class Target_s390 : public Sized_target<size, true>
 				  this->rela_dyn_section(layout));
   }
 
+  // A function for targets to call.  Return whether BYTES/LEN matches
+  // VIEW/VIEW_SIZE at OFFSET.  Like the one in Target, but takes
+  // an unsigned char * parameter.
+  bool
+  match_view_u(const unsigned char* view, section_size_type view_size,
+     section_offset_type offset, const unsigned char* bytes, size_t len) const
+    {
+      return this->match_view(view, view_size, offset,
+			      reinterpret_cast<const char*>(bytes), len);
+    }
+
   // Information about this specific target which we pass to the
   // general Target structure.
   static Target::Target_info s390_info;
@@ -724,6 +743,22 @@ class Target_s390 : public Sized_target<size, true>
   bool tls_base_symbol_defined_;
   // For use in do_tls_offset_for_*
   Layout *layout_;
+
+  // Code sequences for -fsplit-stack matching.
+  static const unsigned char ss_code_nopmark[];
+  static const unsigned char ss_code_ear[];
+  static const unsigned char ss_code_c[];
+  static const unsigned char ss_code_l[];
+  static const unsigned char ss_code_ahi[];
+  static const unsigned char ss_code_alfi[];
+  static const unsigned char ss_code_cr[];
+  static const unsigned char ss_code_larl[];
+  static const unsigned char ss_code_jg[];
+  static const unsigned char ss_code_jgl[];
+  static const unsigned char ss_code_jl[];
+  static const unsigned char ss_code_jhe[];
+  static const unsigned char ss_code_basr[];
+  static const unsigned char ss_code_basr_2[];
 };
 
 template<>
@@ -4243,6 +4278,424 @@ Target_s390<size>::do_code_fill(section_size_type length) const
   return std::string(length, static_cast<char>(0x07));
 }
 
+// Code sequences to match below.
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_nopmark[] = {
+  0x07, 0x0f,				// nopr %r15
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_ear[] = {
+  0xb2, 0x4f, 0x00, 0x10,		// ear %r1, %a0
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_ear[] = {
+  0xb2, 0x4f, 0x00, 0x10,		// ear %r1, %a0
+  0xeb, 0x11, 0x00, 0x20, 0x00, 0x0d,	// sllg %r1,%r1,32
+  0xb2, 0x4f, 0x00, 0x11,		// ear %r1, %a1
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_c[] = {
+  0x59, 0xf0, 0x10, 0x20,		// c %r15, 0x20(%r1)
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_c[] = {
+  0xe3, 0xf0, 0x10, 0x38, 0x00, 0x20,	// cg %r15, 0x38(%r1)
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_l[] = {
+  0x58, 0x10, 0x10, 0x20,		// l %r1, 0x20(%r1)
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_l[] = {
+  0xe3, 0x10, 0x10, 0x38, 0x00, 0x04,	// lg %r1, 0x38(%r1)
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_ahi[] = {
+  0xa7, 0x1a,				// ahi %r1, ...
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_ahi[] = {
+  0xa7, 0x1b,				// aghi %r1, ...
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_alfi[] = {
+  0xc2, 0x1b,				// alfi %r1, ...
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_alfi[] = {
+  0xc2, 0x1a,				// algfi %r1, ...
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_cr[] = {
+  0x19, 0xf1,				// cr %r15, %r1
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_cr[] = {
+  0xb9, 0x20, 0x00, 0xf1,		// cgr %r15, %r1
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_larl[] = {
+  0xc0, 0x10		,		// larl ...
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_jg[] = {
+  0xc0, 0xf4		,		// jg ...
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_jgl[] = {
+  0xc0, 0x44,				// jgl ...
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_jl[] = {
+  0xa7, 0x44,				// jl ...
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_jhe[] = {
+  0xa7, 0xa4,				// jhe ...
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_basr[] = {
+  0x0d, 0x10,				// basr %r1, 0
+  0x5a, 0x10, 0x10, 0x12,		// a %r1, 0x12(%r1)
+  0x0d, 0x11,				// basr %r1, %r1
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_basr_2[] = {
+  0x0d, 0x10,				// basr %r1, 0
+  0x5a, 0x10, 0x10, 0x14,		// a %r1, 0x14(%r1)
+  0x0d, 0x11,				// basr %r1, %r1
+};
+
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fsplit-stack.  The function calls non-split-stack
+// code.  We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+template<int size>
+void
+Target_s390<size>::do_calls_non_split(Relobj* object, unsigned int shndx,
+				      section_offset_type fnoffset,
+				      section_size_type,
+				      const unsigned char *prelocs,
+				      size_t reloc_count,
+				      unsigned char* view,
+				      section_size_type view_size,
+				      std::string*,
+				      std::string*) const
+{
+  // true if there's a conditional call to __morestack in the function,
+  // false if there's an unconditional one.
+  bool conditional = false;
+  // Offset of the byte after the compare insn, if conditional.
+  section_offset_type cmpend = 0;
+  // Type and immediate offset of the add instruction that adds frame size
+  // to guard.
+  enum {
+    SS_ADD_NONE,
+    SS_ADD_AHI,
+    SS_ADD_ALFI,
+  } fsadd_type = SS_ADD_NONE;
+  section_offset_type fsadd_offset = 0;
+  uint32_t fsadd_frame_size = 0;
+  // Type and offset of the conditional jump.
+  enum {
+    SS_JUMP_NONE,
+    SS_JUMP_JL,
+    SS_JUMP_JHE,
+  } jump_type = SS_JUMP_NONE;
+  section_offset_type jump_offset = 0;
+  // Section view and offset of param block.
+  section_offset_type param_offset = 0;
+  unsigned char *param_view = 0;
+  section_size_type param_view_size = 0;
+  // Current position in function.
+  section_offset_type curoffset = fnoffset;
+  // Frame size.
+  typename elfcpp::Elf_types<size>::Elf_Addr frame_size;
+  // Relocation parsing.
+  typedef typename Reloc_types<elfcpp::SHT_RELA, size, true>::Reloc Reltype;
+  const int reloc_size = Reloc_types<elfcpp::SHT_RELA, size, true>::reloc_size;
+
+  // If the function starts with a nopr %r15, it's a split-stack-compiled
+  // function that doesn't have a stack frame.  Ignore it.
+
+  if (this->match_view_u(view, view_size, curoffset, ss_code_nopmark,
+		       sizeof ss_code_nopmark))
+    return;
+
+  // First, figure out if there's a conditional call by looking for the
+  // extract-tp, add, cmp sequence.
+
+  if (this->match_view_u(view, view_size, curoffset, ss_code_ear,
+		       sizeof ss_code_ear))
+    {
+      // Found extract-tp, now look for an add and compare.
+      curoffset += sizeof ss_code_ear;
+      conditional = true;
+      if (this->match_view_u(view, view_size, curoffset, ss_code_c,
+			   sizeof ss_code_c))
+	{
+	  // Found a direct compare of stack pointer with the guard,
+	  // we're done here.
+	  curoffset += sizeof ss_code_c;
+	}
+      else if (this->match_view_u(view, view_size, curoffset, ss_code_l,
+			   sizeof ss_code_l))
+	{
+	  // Found a load of guard to r1, look for an add and compare.
+	  curoffset += sizeof ss_code_l;
+          if (this->match_view_u(view, view_size, curoffset, ss_code_ahi,
+			       sizeof ss_code_ahi))
+	    {
+	      curoffset += sizeof ss_code_ahi;
+	      // Found an ahi, extract its immediate
+	      fsadd_offset = curoffset;
+	      fsadd_type = SS_ADD_AHI;
+	      if (convert_to_section_size_type(curoffset + 2) > view_size)
+	        goto bad;
+	      fsadd_frame_size
+	        = elfcpp::Swap<16, true>::readval(view + curoffset);
+	      curoffset += 2;
+	    }
+	  else if (this->match_view_u(view, view_size, curoffset,
+		    ss_code_alfi, sizeof ss_code_alfi))
+	    {
+	      curoffset += sizeof ss_code_alfi;
+	      // Found an alfi, extract its immediate
+	      fsadd_offset = curoffset;
+	      fsadd_type = SS_ADD_ALFI;
+	      if (convert_to_section_size_type(curoffset + 4) > view_size)
+	        goto bad;
+	      fsadd_frame_size
+	        = elfcpp::Swap_unaligned<32, true>::readval(view + curoffset);
+	      curoffset += 4;
+	    }
+	  else
+            {
+	      goto bad;
+            }
+	  // Now, there has to be a compare.
+          if (this->match_view_u(view, view_size, curoffset, ss_code_cr,
+			       sizeof ss_code_cr))
+	    curoffset += sizeof ss_code_cr;
+	  else
+	    goto bad;
+	}
+      else
+        {
+	  goto bad;
+        }
+      cmpend = curoffset;
+    }
+
+  // Second, look for the call.
+
+  if (this->match_view_u(view, view_size, curoffset, ss_code_larl,
+		       sizeof ss_code_larl))
+    {
+      // Found a zarch-style call: larl + jg
+      curoffset += sizeof ss_code_larl;
+
+      // Find out larl's operand.  It should be a local symbol in .rodata
+      // section.
+      const unsigned char *pr = prelocs;
+      for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+        {
+          Reltype reloc(pr);
+	  if (static_cast<section_offset_type>(reloc.get_r_offset())
+	      == curoffset)
+	    {
+              typename elfcpp::Elf_types<size>::Elf_WXword r_info
+	        = reloc.get_r_info();
+              unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+              unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+	      if (r_type != elfcpp::R_390_PC32DBL)
+	        goto bad;
+	      if (r_sym >= object->local_symbol_count())
+		goto bad;
+	      Sized_relobj_file<size, true> *object_sized =
+		static_cast<Sized_relobj_file<size, true> *>(object);
+              const Symbol_value<size>* sym = object_sized->local_symbol(r_sym);
+	      bool param_shndx_ordinary;
+	      const unsigned int param_shndx =
+		sym->input_shndx(&param_shndx_ordinary);
+	      if (!param_shndx_ordinary)
+		goto bad;
+	      param_offset = sym->input_value() + reloc.get_r_addend() - 2
+			     - object->output_section(param_shndx)->address();
+	      param_view = const_cast<unsigned char*>(
+			      object->get_output_view(param_shndx,
+						      &param_view_size));
+	      break;
+	    }
+	}
+
+      if (!param_view)
+	goto bad;
+
+      curoffset += 4;
+
+      // Now, there has to be a jump to __morestack.
+      jump_offset = curoffset;
+
+      if (this->match_view_u(view, view_size, curoffset,
+			   conditional ? ss_code_jgl : ss_code_jg,
+			   sizeof ss_code_jg))
+	curoffset += sizeof ss_code_jg;
+      else
+	goto bad;
+
+      if (conditional)
+        jump_type = SS_JUMP_JL;
+
+      curoffset += 4;
+    }
+  else if (size == 32)
+    {
+      // There'll be an ESA-style call, possibly with a cond jump first.
+      if (conditional)
+	{
+	  if (this->match_view_u(view, view_size, curoffset, ss_code_jl,
+			       sizeof ss_code_jl))
+	    {
+	      // Jump if morestack call needed - we need to follow it.
+	      int16_t off;
+	      jump_type = SS_JUMP_JL;
+	      jump_offset = curoffset;
+	      curoffset += sizeof ss_code_jl;
+	      if (convert_to_section_size_type(curoffset + 2) > view_size)
+	        goto bad;
+	      off = elfcpp::Swap<16, true>::readval(view + curoffset);
+	      curoffset += off * 2 - sizeof ss_code_jl;
+	    }
+	  else if (this->match_view_u(view, view_size, curoffset, ss_code_jhe,
+				    sizeof ss_code_jhe))
+	    {
+	      jump_type = SS_JUMP_JHE;
+	      // Jump if morestack not needed - skip over it.  Bump cmpend,
+	      // so that jump is nopped out along with the rest if we need
+	      // to make the call unconditional.
+	      curoffset += sizeof ss_code_jhe;
+	      curoffset += 2;
+	      cmpend = curoffset;
+	    }
+	  else
+	    {
+	      goto bad;
+	    }
+	}
+
+      // Match the basr sequence. There are two variants, depending on
+      // whether the start is 4-aligned or not.
+      if (this->match_view_u(view, view_size, curoffset, ss_code_basr,
+			   sizeof ss_code_basr))
+	curoffset += sizeof ss_code_basr;
+      else if (this->match_view_u(view, view_size, curoffset, ss_code_basr_2,
+			   sizeof ss_code_basr_2))
+	curoffset += sizeof ss_code_basr_2 + 2;
+      else
+        goto bad;
+
+      // We found the param block.
+      param_offset = curoffset;
+      param_view = view;
+      param_view_size = view_size;
+    }
+  else
+    {
+      goto bad;
+    }
+
+  // Read the frame size.
+  if (convert_to_section_size_type(param_offset + size / 8) > param_view_size)
+    goto bad;
+  frame_size = elfcpp::Swap<size, true>::readval(param_view + param_offset);
+
+  // Sanity check.
+  if (fsadd_type != SS_ADD_NONE && fsadd_frame_size != frame_size)
+    goto bad;
+
+  // Bump the frame size.
+  frame_size += parameters->options().split_stack_adjust_size();
+
+  // Store it to the param block.
+  elfcpp::Swap<size, true>::writeval(param_view + param_offset, frame_size);
+
+  if (!conditional)
+    {
+      // If the call was already unconditional, we're done.
+    }
+  else if (frame_size <= 0xffffffff && fsadd_type == SS_ADD_ALFI)
+    {
+      // Using alfi to add the frame size, and it still fits.  Adjust it.
+      elfcpp::Swap_unaligned<32, true>::writeval(view + fsadd_offset,
+						 frame_size);
+    }
+  else
+    {
+      // We were either relying on the backoff area, or used ahi to load
+      // frame size.  This won't fly, as our new frame size is too large.
+      // Convert the sequence to unconditional by nopping out the comparison,
+      // and rewiring the jump.
+      this->set_view_to_nop(view, view_size, fnoffset, cmpend - fnoffset);
+
+      // If jump type was jhe, we already nopped it out above.
+      if (jump_type == SS_JUMP_JL)
+        {
+	  // If jump is jl/jgl, we'll mutate it to j/jg.
+	  view[jump_offset+1] = 0xf4;
+	}
+    }
+
+  return;
+
+bad:
+  if (!object->has_no_split_stack())
+      object->error(_("failed to match split-stack sequence at "
+		      "section %u offset %0zx"),
+		    shndx, static_cast<size_t>(fnoffset));
+}
+
 // Relocate section data.
 
 template<int size>
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index c8e5f9f..7cc7a2d 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -3362,6 +3362,210 @@ MOSTLYCLEANFILES += arm_farcall_thumb_arm arm_farcall_thumb_arm_5t
 
 endif DEFAULT_TARGET_ARM
 
+if DEFAULT_TARGET_S390
+
+check_SCRIPTS += split_s390.sh
+check_DATA += split_s390_e1.stdout split_s390_e2.stdout \
+	split_s390_e3.stdout split_s390_e4.stdout split_s390_z1.stdout \
+	split_s390_z2.stdout split_s390_z3.stdout split_s390_z4.stdout \
+	split_s390_n.stdout split_s390_a1.stdout split_s390_a2.stdout \
+	split_s390_e1_ns.stdout split_s390_e2_ns.stdout \
+	split_s390_e3_ns.stdout split_s390_e4_ns.stdout \
+	split_s390_z1_ns.stdout split_s390_z2_ns.stdout \
+	split_s390_z3_ns.stdout split_s390_z4_ns.stdout \
+	split_s390_n_ns.stdout split_s390_r.stdout \
+	split_s390x_z1.stdout split_s390x_z2.stdout split_s390x_z3.stdout \
+	split_s390x_z4.stdout split_s390x_n.stdout split_s390x_a1.stdout \
+	split_s390x_a2.stdout split_s390x_z1_ns.stdout \
+	split_s390x_z2_ns.stdout split_s390x_z3_ns.stdout \
+	split_s390x_z4_ns.stdout split_s390x_n_ns.stdout \
+	split_s390x_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_s390_1_e1.o: split_s390_1_e1.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_e2.o: split_s390_1_e2.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_e3.o: split_s390_1_e3.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_e4.o: split_s390_1_e4.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_z1.o: split_s390_1_z1.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_z2.o: split_s390_1_z2.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_z3.o: split_s390_1_z3.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_z4.o: split_s390_1_z4.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_n.o: split_s390_1_n.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_a1.o: split_s390_1_a1.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_1_a2.o: split_s390_1_a2.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_2_s.o: split_s390_2_s.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_2_ns.o: split_s390_2_ns.s
+	$(TEST_AS) -m31 -o $@ $<
+split_s390_e1: split_s390_1_e1.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e1.o split_s390_2_s.o
+split_s390_e1.stdout: split_s390_e1
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e2: split_s390_1_e2.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e2.o split_s390_2_s.o
+split_s390_e2.stdout: split_s390_e2
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e3: split_s390_1_e3.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e3.o split_s390_2_s.o
+split_s390_e3.stdout: split_s390_e3
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e4: split_s390_1_e4.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e4.o split_s390_2_s.o
+split_s390_e4.stdout: split_s390_e4
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_z1: split_s390_1_z1.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z1.o split_s390_2_s.o
+split_s390_z1.stdout: split_s390_z1
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z2: split_s390_1_z2.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z2.o split_s390_2_s.o
+split_s390_z2.stdout: split_s390_z2
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z3: split_s390_1_z3.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z3.o split_s390_2_s.o
+split_s390_z3.stdout: split_s390_z3
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z4: split_s390_1_z4.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z4.o split_s390_2_s.o
+split_s390_z4.stdout: split_s390_z4
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_n: split_s390_1_n.o split_s390_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_n.o split_s390_2_s.o
+split_s390_n.stdout: split_s390_n
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e1_ns: split_s390_1_e1.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e1.o split_s390_2_ns.o
+split_s390_e1_ns.stdout: split_s390_e1_ns
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e2_ns: split_s390_1_e2.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e2.o split_s390_2_ns.o
+split_s390_e2_ns.stdout: split_s390_e2_ns
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e3_ns: split_s390_1_e3.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e3.o split_s390_2_ns.o
+split_s390_e3_ns.stdout: split_s390_e3_ns
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_e4_ns: split_s390_1_e4.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e4.o split_s390_2_ns.o
+split_s390_e4_ns.stdout: split_s390_e4_ns
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_z1_ns: split_s390_1_z1.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z1.o split_s390_2_ns.o
+split_s390_z1_ns.stdout: split_s390_z1_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z2_ns: split_s390_1_z2.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z2.o split_s390_2_ns.o
+split_s390_z2_ns.stdout: split_s390_z2_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z3_ns: split_s390_1_z3.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z3.o split_s390_2_ns.o
+split_s390_z3_ns.stdout: split_s390_z3_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z4_ns: split_s390_1_z4.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z4.o split_s390_2_ns.o
+split_s390_z4_ns.stdout: split_s390_z4_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_n_ns: split_s390_1_n.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_n.o split_s390_2_ns.o
+split_s390_n_ns.stdout: split_s390_n_ns
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_a1.stdout: split_s390_1_a1.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o split_s390_a1 split_s390_1_a1.o split_s390_2_ns.o > $@ 2>&1 || exit 0
+split_s390_a2: split_s390_1_a2.o split_s390_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_a2.o split_s390_2_ns.o
+split_s390_a2.stdout: split_s390_a2
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390_r.stdout: split_s390_1_z1.o split_s390_2_ns.o ../ld-new
+	../ld-new -r split_s390_1_z1.o split_s390_2_ns.o -o split_s390_r > $@ 2>&1 || exit 0
+split_s390x_1_z1.o: split_s390x_1_z1.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_1_z2.o: split_s390x_1_z2.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_1_z3.o: split_s390x_1_z3.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_1_z4.o: split_s390x_1_z4.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_1_n.o: split_s390x_1_n.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_1_a1.o: split_s390x_1_a1.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_1_a2.o: split_s390x_1_a2.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_2_s.o: split_s390x_2_s.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_2_ns.o: split_s390x_2_ns.s
+	$(TEST_AS) -m64 -o $@ $<
+split_s390x_z1: split_s390x_1_z1.o split_s390x_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z1.o split_s390x_2_s.o
+split_s390x_z1.stdout: split_s390x_z1
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z2: split_s390x_1_z2.o split_s390x_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z2.o split_s390x_2_s.o
+split_s390x_z2.stdout: split_s390x_z2
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z3: split_s390x_1_z3.o split_s390x_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z3.o split_s390x_2_s.o
+split_s390x_z3.stdout: split_s390x_z3
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z4: split_s390x_1_z4.o split_s390x_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z4.o split_s390x_2_s.o
+split_s390x_z4.stdout: split_s390x_z4
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_n: split_s390x_1_n.o split_s390x_2_s.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_n.o split_s390x_2_s.o
+split_s390x_n.stdout: split_s390x_n
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390x_z1_ns: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z1.o split_s390x_2_ns.o
+split_s390x_z1_ns.stdout: split_s390x_z1_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z2_ns: split_s390x_1_z2.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z2.o split_s390x_2_ns.o
+split_s390x_z2_ns.stdout: split_s390x_z2_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z3_ns: split_s390x_1_z3.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z3.o split_s390x_2_ns.o
+split_s390x_z3_ns.stdout: split_s390x_z3_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z4_ns: split_s390x_1_z4.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z4.o split_s390x_2_ns.o
+split_s390x_z4_ns.stdout: split_s390x_z4_ns
+	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_n_ns: split_s390x_1_n.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_n.o split_s390x_2_ns.o
+split_s390x_n_ns.stdout: split_s390x_n_ns
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390x_a1.stdout: split_s390x_1_a1.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o split_s390x_a1 split_s390x_1_a1.o split_s390x_2_ns.o > $@ 2>&1 || exit 0
+split_s390x_a2: split_s390x_1_a2.o split_s390x_2_ns.o ../ld-new
+	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_a2.o split_s390x_2_ns.o
+split_s390x_a2.stdout: split_s390x_a2
+	$(TEST_OBJDUMP) -d $< > $@
+split_s390x_r.stdout: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
+	../ld-new -r split_s390x_1_z1.o split_s390x_2_ns.o -o split_s390x_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_s390_1_e1 split_s390_1_e2 split_s390_1_e3 \
+	split_s390_1_e4 split_s390_1_z1 split_s390_1_z2 split_s390_1_z3 \
+	split_s390_1_z4 split_s390_1_n split_s390_1_a1 split_s390_1_a2 \
+	split_s390_1_e1_ns split_s390_1_e2_ns split_s390_1_e3_ns \
+	split_s390_1_e4_ns split_s390_1_z1_ns split_s390_1_z2_ns \
+	split_s390_1_z3_ns split_s390_1_z4_ns split_s390_1_n_ns \
+	split_s390_r split_s390x_1_z1 split_s390x_1_z2 split_s390x_1_z3 \
+	split_s390x_1_z4 split_s390x_1_n split_s390x_1_a1 split_s390x_1_a2 \
+	split_s390x_1_z1_ns split_s390x_1_z2_ns split_s390x_1_z3_ns \
+	split_s390x_1_z4_ns split_s390x_1_n_ns split_s390x_r
+
+endif DEFAULT_TARGET_S390
+
 endif NATIVE_OR_CROSS_LINKER
 
 # Tests for the dwp tool.
diff --git a/gold/testsuite/split_s390.sh b/gold/testsuite/split_s390.sh
new file mode 100755
index 0000000..96add07
--- /dev/null
+++ b/gold/testsuite/split_s390.sh
@@ -0,0 +1,149 @@
+#!/bin/sh
+
+# split_s390.sh -- test -fstack-split for s390
+
+# Copyright (C) 2009-2015 Free Software Foundation, Inc.
+# Written by Marcin KoÅ?cielnicki <koriakin@0x04.net>.
+
+# This file is part of gold.
+
+# This program 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 of the License, or
+# (at your option) any later version.
+
+# This program 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.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+match()
+{
+  if ! egrep "$1" "$2" >/dev/null 2>&1; then
+    echo 1>&2 "could not find '$1' in $2"
+    exit 1
+  fi
+}
+
+nomatch()
+{
+  if egrep "$1" "$2" >/dev/null 2>&1; then
+    echo 1>&2 "found unexpected '$1' in $2"
+    exit 1
+  fi
+}
+
+match 'basr.*%r1,%r0$' split_s390_e1.stdout
+match 'long.*0x00100000$' split_s390_e1.stdout
+match 'basr.*%r1,%r0$' split_s390_e1_ns.stdout
+match 'long.*0x00104000$' split_s390_e1_ns.stdout
+
+match 'ear.*$' split_s390_e2.stdout
+match 'jhe.*$' split_s390_e2.stdout
+match 'basr.*%r1,%r0$' split_s390_e2.stdout
+match 'long.*0x00000100$' split_s390_e2.stdout
+nomatch 'ear.*$' split_s390_e2_ns.stdout
+nomatch 'jhe.*$' split_s390_e2_ns.stdout
+match 'basr.*%r1,%r0$' split_s390_e2_ns.stdout
+match 'long.*0x00004100$' split_s390_e2_ns.stdout
+
+match 'ear.*$' split_s390_e3.stdout
+match 'jl.*$' split_s390_e3.stdout
+nomatch 'j	.*$' split_s390_e3.stdout
+match 'basr.*%r1,%r0$' split_s390_e3.stdout
+match 'long.*0x00000100$' split_s390_e3.stdout
+nomatch 'ear.*$' split_s390_e3_ns.stdout
+nomatch 'jl.*$' split_s390_e3_ns.stdout
+match 'j	.*$' split_s390_e3_ns.stdout
+match 'basr.*%r1,%r0$' split_s390_e3_ns.stdout
+match 'long.*0x00004100$' split_s390_e3_ns.stdout
+
+match 'ear.*$' split_s390_e4.stdout
+match 'jl.*$' split_s390_e4.stdout
+nomatch 'j	.*$' split_s390_e4.stdout
+match 'basr.*%r1,%r0$' split_s390_e4.stdout
+match 'long.*0x00001000$' split_s390_e4.stdout
+nomatch 'ear.*$' split_s390_e4_ns.stdout
+nomatch 'jl.*$' split_s390_e4_ns.stdout
+match 'j	.*$' split_s390_e4_ns.stdout
+match 'basr.*%r1,%r0$' split_s390_e4_ns.stdout
+match 'long.*0x00005000$' split_s390_e4_ns.stdout
+
+match 'jg.*__morestack>?$' split_s390_z1.stdout
+match 'long.*0x00100000$' split_s390_z1.stdout
+match 'jg.*__morestack>?$' split_s390_z1_ns.stdout
+match 'long.*0x00104000$' split_s390_z1_ns.stdout
+
+match 'ear.*$' split_s390_z2.stdout
+match 'jgl.*__morestack>?$' split_s390_z2.stdout
+nomatch 'jg	.*__morestack>?$' split_s390_z2.stdout
+match 'long.*0x00000100$' split_s390_z2.stdout
+nomatch 'ear.*$' split_s390_z2_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390_z2_ns.stdout
+match 'jg	.*__morestack>?$' split_s390_z2_ns.stdout
+match 'long.*0x00004100$' split_s390_z2_ns.stdout
+
+match 'ear.*$' split_s390_z3.stdout
+match 'jgl.*__morestack>?$' split_s390_z3.stdout
+nomatch 'jg	.*__morestack>?$' split_s390_z3.stdout
+match 'long.*0x00001000$' split_s390_z3.stdout
+nomatch 'ear.*$' split_s390_z3_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390_z3_ns.stdout
+match 'jg	.*__morestack>?$' split_s390_z3_ns.stdout
+match 'long.*0x00005000$' split_s390_z3_ns.stdout
+
+match 'alfi.*%r1,1048576$' split_s390_z4.stdout
+match 'jgl.*__morestack>?$' split_s390_z4.stdout
+match 'long.*0x00100000$' split_s390_z4.stdout
+match 'alfi.*%r1,1064960$' split_s390_z4_ns.stdout
+match 'jgl.*__morestack>?$' split_s390_z4_ns.stdout
+match 'long.*0x00104000$' split_s390_z4_ns.stdout
+
+match 'jg.*__morestack>?$' split_s390x_z1.stdout
+match 'long.*0x00100000$' split_s390x_z1.stdout
+match 'jg.*__morestack>?$' split_s390x_z1_ns.stdout
+match 'long.*0x00104000$' split_s390x_z1_ns.stdout
+
+match 'ear.*$' split_s390x_z2.stdout
+match 'jgl.*__morestack>?$' split_s390x_z2.stdout
+nomatch 'jg	.*__morestack>?$' split_s390x_z2.stdout
+match 'long.*0x00000100$' split_s390x_z2.stdout
+nomatch 'ear.*$' split_s390x_z2_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390x_z2_ns.stdout
+match 'jg	.*__morestack>?$' split_s390x_z2_ns.stdout
+match 'long.*0x00004100$' split_s390x_z2_ns.stdout
+
+match 'ear.*$' split_s390x_z3.stdout
+match 'jgl.*__morestack>?$' split_s390x_z3.stdout
+nomatch 'jg	.*__morestack>?$' split_s390x_z3.stdout
+match 'long.*0x00001000$' split_s390x_z3.stdout
+nomatch 'ear.*$' split_s390x_z3_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390x_z3_ns.stdout
+match 'jg	.*__morestack>?$' split_s390x_z3_ns.stdout
+match 'long.*0x00005000$' split_s390x_z3_ns.stdout
+
+match 'algfi.*%r1,1048576$' split_s390x_z4.stdout
+match 'jgl.*__morestack>?$' split_s390x_z4.stdout
+match 'long.*0x00100000$' split_s390x_z4.stdout
+match 'algfi.*%r1,1064960$' split_s390x_z4_ns.stdout
+match 'jgl.*__morestack>?$' split_s390x_z4_ns.stdout
+match 'long.*0x00104000$' split_s390x_z4_ns.stdout
+
+match 'nopr.*r15$' split_s390_n.stdout
+match 'nopr.*r15$' split_s390_n_ns.stdout
+match 'nopr.*r15$' split_s390x_n.stdout
+match 'nopr.*r15$' split_s390x_n_ns.stdout
+
+match 'failed to match' split_s390_a1.stdout
+match 'failed to match' split_s390x_a1.stdout
+
+match 'bas.*$' split_s390_a2.stdout
+match 'brasl.*__morestack>?$' split_s390x_a2.stdout
+
+match 'cannot mix' split_s390_r.stdout
+match 'cannot mix' split_s390x_r.stdout
diff --git a/gold/testsuite/split_s390_1_a1.s b/gold/testsuite/split_s390_1_a1.s
new file mode 100644
index 0000000..86c1997
--- /dev/null
+++ b/gold/testsuite/split_s390_1_a1.s
@@ -0,0 +1,36 @@
+# split_s390_1_a1.s: s390 specific, adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	basr	%r13, %r0
+.L1:
+	l	%r1, .L2-.L1(%r13)
+	bas	%r14, 0(%r13, %r1)
+	l	%r1, .L3-.L1(%r13)
+	bas	%r14, 0(%r13, %r1)
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.align	4
+.L2:
+	.long	__morestack-.L1
+.L3:
+	.long	fn2-.L1
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_a2.s b/gold/testsuite/split_s390_1_a2.s
new file mode 100644
index 0000000..026752f
--- /dev/null
+++ b/gold/testsuite/split_s390_1_a2.s
@@ -0,0 +1,37 @@
+# split_s390_1_a2.s: s390 specific, permitted adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	basr	%r13, %r0
+.L1:
+	l	%r1, .L2-.L1(%r13)
+	bas	%r14, 0(%r13, %r1)
+	l	%r1, .L3-.L1(%r13)
+	bas	%r14, 0(%r13, %r1)
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.align	4
+.L2:
+	.long	__morestack-.L1
+.L3:
+	.long	fn2-.L1
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
+	.section	.note.GNU-no-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e1.s b/gold/testsuite/split_s390_1_e1.s
new file mode 100644
index 0000000..354dc91
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e1.s
@@ -0,0 +1,45 @@
+# split_s390_e1.s: s390 specific test case for -fsplit-stack -
+# esa mode, unconditional call.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	basr	%r1, %r0
+.L1:
+	a	%r1, .L2-.L1(%r1)
+	basr	%r1, %r1
+	.align	4
+.L3:
+	.long	0x100000
+	.long	0
+	.long	.L4-.L3
+.L2:
+	.long	__morestack-.L1
+.L4:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	basr	%r13, %r0
+.L5:
+	l	%r1, .L6-.L5(%r13)
+	bas	%r14, 0(%r13, %r1)
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.align	4
+.L6:
+	.long	fn2-.L5
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e2.s b/gold/testsuite/split_s390_1_e2.s
new file mode 100644
index 0000000..af802fa
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e2.s
@@ -0,0 +1,48 @@
+# split_s390_e2.s: s390 specific test case for -fsplit-stack -
+# esa mode, jhe conditional call, no add.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	c	%r15, 0x20(%r1)
+	jhe	.L4
+	basr	%r1, %r0
+.L1:
+	a	%r1, .L2-.L1(%r1)
+	basr	%r1, %r1
+	.align	4
+.L3:
+	.long	0x100
+	.long	0
+	.long	.L4-.L3
+.L2:
+	.long	__morestack-.L1
+.L4:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	basr	%r13, %r0
+.L5:
+	l	%r1, .L6-.L5(%r13)
+	bas	%r14, 0(%r13, %r1)
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.align	4
+.L6:
+	.long	fn2-.L5
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e3.s b/gold/testsuite/split_s390_1_e3.s
new file mode 100644
index 0000000..107419b
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e3.s
@@ -0,0 +1,49 @@
+# split_s390_e3.s: s390 specific test case for -fsplit-stack -
+# esa mode, jl conditional call, no add.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	c	%r15, 0x20(%r1)
+	jl	.L7
+.L4:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	basr	%r13, %r0
+.L5:
+	l	%r1, .L6-.L5(%r13)
+	bas	%r14, 0(%r13, %r1)
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.align	4
+.L6:
+	.long	fn2-.L5
+.L7:
+	basr	%r1, %r0
+.L1:
+	a	%r1, .L2-.L1(%r1)
+	basr	%r1, %r1
+	.align	4
+.L3:
+	.long	0x100
+	.long	0
+	.long	.L4-.L3
+.L2:
+	.long	__morestack-.L1
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e4.s b/gold/testsuite/split_s390_1_e4.s
new file mode 100644
index 0000000..0687682
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e4.s
@@ -0,0 +1,51 @@
+# split_s390_e4.s: s390 specific test case for -fsplit-stack -
+# esa mode, jl conditional call, ahi.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	l	%r1, 0x20(%r1)
+	ahi	%r1, 0x1000
+	cr	%r15, %r1
+	jl	.L7
+.L4:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	basr	%r13, %r0
+.L5:
+	l	%r1, .L6-.L5(%r13)
+	bas	%r14, 0(%r13, %r1)
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.align	4
+.L6:
+	.long	fn2-.L5
+.L7:
+	basr	%r1, %r0
+.L1:
+	a	%r1, .L2-.L1(%r1)
+	basr	%r1, %r1
+	.align	4
+.L3:
+	.long	0x1000
+	.long	0
+	.long	.L4-.L3
+.L2:
+	.long	__morestack-.L1
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_n.s b/gold/testsuite/split_s390_1_n.s
new file mode 100644
index 0000000..ca91262
--- /dev/null
+++ b/gold/testsuite/split_s390_1_n.s
@@ -0,0 +1,18 @@
+# split_s390_n.s: s390 specific test case for -fsplit-stack -
+# no stack frame
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	nopr	%r15
+	larl	%r2, fn2
+	br	%r14
+	.cfi_endproc
+
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_z1.s b/gold/testsuite/split_s390_1_z1.s
new file mode 100644
index 0000000..42adf55
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z1.s
@@ -0,0 +1,37 @@
+# split_s390_z3.s: s390 specific test case for -fsplit-stack -
+# zarch mode, unconditional call
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	larl	%r1, .L1
+	jg	__morestack
+	.section .rodata
+	.align 4
+.L1:
+	.long	0x100000
+	.long	0
+	.long	.L2-.L1
+	.previous
+.L2:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	brasl	%r14, fn2
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_z2.s b/gold/testsuite/split_s390_1_z2.s
new file mode 100644
index 0000000..2717a83
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z2.s
@@ -0,0 +1,40 @@
+# split_s390_z2.s: s390 specific test case for -fsplit-stack -
+# zarch mode, conditional call, no add
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	c	%r15, 0x20(%r1)
+	larl	%r1, .L1
+	jgl	__morestack
+	.section .rodata
+	.align 4
+.L1:
+	.long	0x100
+	.long	0
+	.long	.L2-.L1
+	.previous
+.L2:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	brasl	%r14, fn2
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
+
diff --git a/gold/testsuite/split_s390_1_z3.s b/gold/testsuite/split_s390_1_z3.s
new file mode 100644
index 0000000..8f0cb54
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z3.s
@@ -0,0 +1,41 @@
+# split_s390_z3.s: s390 specific test case for -fsplit-stack -
+# zarch mode, conditional call, ahi.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	l	%r1, 0x20(%r1)
+	ahi	%r1, 0x1000
+	cr	%r15, %r1
+	larl	%r1, .L1
+	jgl	__morestack
+	.section .rodata
+	.align 4
+.L1:
+	.long	0x1000
+	.long	0
+	.long	.L2-.L1
+	.previous
+.L2:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	brasl	%r14, fn2
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_z4.s b/gold/testsuite/split_s390_1_z4.s
new file mode 100644
index 0000000..b80bf40
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z4.s
@@ -0,0 +1,41 @@
+# split_s390_z4.s: s390 specific test case for -fsplit-stack -
+# zarch mode, conditional call, alfi.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	l	%r1, 0x20(%r1)
+	alfi	%r1, 0x100000
+	cr	%r15, %r1
+	larl	%r1, .L1
+	jgl	__morestack
+	.section .rodata
+	.align 4
+.L1:
+	.long	0x100000
+	.long	0
+	.long	.L2-.L1
+	.previous
+.L2:
+	stm	%r13, %r15, 0x34(%r15)
+	.cfi_offset	%r13, -0x2c
+	.cfi_offset	%r14, -0x28
+	.cfi_offset	%r15, -0x24
+	ahi	%r15, -0x60
+	.cfi_adjust_cfa_offset	0x60
+	brasl	%r14, fn2
+	lm	%r13, %r15, 0x94(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0x60
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_2_ns.s b/gold/testsuite/split_s390_2_ns.s
new file mode 100644
index 0000000..fb5a993
--- /dev/null
+++ b/gold/testsuite/split_s390_2_ns.s
@@ -0,0 +1,12 @@
+# split_s390_2_ns.s: s390 specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	br	%r14
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_2_s.s b/gold/testsuite/split_s390_2_s.s
new file mode 100644
index 0000000..3df8009
--- /dev/null
+++ b/gold/testsuite/split_s390_2_s.s
@@ -0,0 +1,13 @@
+# split_s390_2_s.s: s390 specific, -fsplit-stack calling -fsplit-stack
+
+	.text
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	br	%r14
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_a1.s b/gold/testsuite/split_s390x_1_a1.s
new file mode 100644
index 0000000..ccc62cb
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_a1.s
@@ -0,0 +1,27 @@
+# split_s390x_1_a1.s: s390x specific, adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	stmg	%r13, %r15, 0x68(%r15)
+	.cfi_offset	%r13, -0x38
+	.cfi_offset	%r14, -0x30
+	.cfi_offset	%r15, -0x28
+	aghi	%r15, -0xa0
+	.cfi_adjust_cfa_offset	0xa0
+	brasl	%r14, __morestack
+	brasl	%r14, fn2
+	lmg	%r13, %r15, 0x108(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0xa0
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_a2.s b/gold/testsuite/split_s390x_1_a2.s
new file mode 100644
index 0000000..a5c067b
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_a2.s
@@ -0,0 +1,28 @@
+# split_s390x_1_a2.s: s390x specific, permitted adjustment failure
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	stmg	%r13, %r15, 0x68(%r15)
+	.cfi_offset	%r13, -0x38
+	.cfi_offset	%r14, -0x30
+	.cfi_offset	%r15, -0x28
+	aghi	%r15, -0xa0
+	.cfi_adjust_cfa_offset	0xa0
+	brasl	%r14, __morestack
+	brasl	%r14, fn2
+	lmg	%r13, %r15, 0x108(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0xa0
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
+	.section	.note.GNU-no-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_n.s b/gold/testsuite/split_s390x_1_n.s
new file mode 100644
index 0000000..6e434b8
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_n.s
@@ -0,0 +1,17 @@
+# split_s390x_1_n.s: s390x specific test case for -fsplit-stack -
+# no stack frame.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	nopr	%r15
+	larl	%r2, fn2
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z1.s b/gold/testsuite/split_s390x_1_z1.s
new file mode 100644
index 0000000..4af34cd
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z1.s
@@ -0,0 +1,37 @@
+# split_s390x_1_z1.s: s390x specific test case for -fsplit-stack -
+# unconditional call.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	larl	%r1, .L1
+	jg	__morestack
+	.section .rodata
+	.align 8
+.L1:
+	.quad	0x100000
+	.quad	0
+	.quad	.L2-.L1
+	.previous
+.L2:
+	stmg	%r13, %r15, 0x68(%r15)
+	.cfi_offset	%r13, -0x38
+	.cfi_offset	%r14, -0x30
+	.cfi_offset	%r15, -0x28
+	aghi	%r15, -0xa0
+	.cfi_adjust_cfa_offset	0xa0
+	brasl	%r14, fn2
+	lmg	%r13, %r15, 0x108(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0xa0
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z2.s b/gold/testsuite/split_s390x_1_z2.s
new file mode 100644
index 0000000..a184f77
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z2.s
@@ -0,0 +1,41 @@
+# split_s390x_1_z2.s: s390x specific test case for -fsplit-stack -
+# conditional call, no add.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1
+	cg	%r15, 0x38(%r1)
+	larl	%r1, .L1
+	jgl	__morestack
+	.section .rodata
+	.align 8
+.L1:
+	.quad	0x100
+	.quad	0
+	.quad	.L2-.L1
+	.previous
+.L2:
+	stmg	%r13, %r15, 0x68(%r15)
+	.cfi_offset	%r13, -0x38
+	.cfi_offset	%r14, -0x30
+	.cfi_offset	%r15, -0x28
+	aghi	%r15, -0xa0
+	.cfi_adjust_cfa_offset	0xa0
+	brasl	%r14, fn2
+	lmg	%r13, %r15, 0x108(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0xa0
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z3.s b/gold/testsuite/split_s390x_1_z3.s
new file mode 100644
index 0000000..b0a4b0b
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z3.s
@@ -0,0 +1,43 @@
+# split_s390x_1_z3.s: s390x specific test case for -fsplit-stack -
+# conditional call, ahi.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1
+	lg	%r1, 0x38(%r1)
+	aghi	%r1, 0x1000
+	cgr	%r15, %r1
+	larl	%r1, .L1
+	jgl	__morestack
+	.section .rodata
+	.align 8
+.L1:
+	.quad	0x1000
+	.quad	0
+	.quad	.L2-.L1
+	.previous
+.L2:
+	stmg	%r13, %r15, 0x68(%r15)
+	.cfi_offset	%r13, -0x38
+	.cfi_offset	%r14, -0x30
+	.cfi_offset	%r15, -0x28
+	aghi	%r15, -0xa0
+	.cfi_adjust_cfa_offset	0xa0
+	brasl	%r14, fn2
+	lmg	%r13, %r15, 0x108(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0xa0
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z4.s b/gold/testsuite/split_s390x_1_z4.s
new file mode 100644
index 0000000..a3b942e
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z4.s
@@ -0,0 +1,43 @@
+# split_s390x_1_z4.s: s390x specific test case for -fsplit-stack -
+# conditional call, alfi.
+
+	.text
+
+	.global	fn1
+	.type	fn1,@function
+fn1:
+	.cfi_startproc
+	ear	%r1, %a0
+	sllg	%r1, %r1, 32
+	ear	%r1, %a1
+	lg	%r1, 0x38(%r1)
+	algfi	%r1, 0x100000
+	cgr	%r15, %r1
+	larl	%r1, .L1
+	jgl	__morestack
+	.section .rodata
+	.align 8
+.L1:
+	.quad	0x100000
+	.quad	0
+	.quad	.L2-.L1
+	.previous
+.L2:
+	stmg	%r13, %r15, 0x68(%r15)
+	.cfi_offset	%r13, -0x38
+	.cfi_offset	%r14, -0x30
+	.cfi_offset	%r15, -0x28
+	aghi	%r15, -0xa0
+	.cfi_adjust_cfa_offset	0xa0
+	brasl	%r14, fn2
+	lmg	%r13, %r15, 0x108(%r15)
+	.cfi_restore	%r13
+	.cfi_restore	%r14
+	.cfi_restore	%r15
+	.cfi_adjust_cfa_offset	-0xa0
+	br	%r14
+	.cfi_endproc
+	.size	fn1,. - fn1
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_2_ns.s b/gold/testsuite/split_s390x_2_ns.s
new file mode 100644
index 0000000..f073eee
--- /dev/null
+++ b/gold/testsuite/split_s390x_2_ns.s
@@ -0,0 +1,12 @@
+# split_s390x_2_ns.s: s390x specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	br	%r14
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_2_s.s b/gold/testsuite/split_s390x_2_s.s
new file mode 100644
index 0000000..787d2fe
--- /dev/null
+++ b/gold/testsuite/split_s390x_2_s.s
@@ -0,0 +1,13 @@
+# split_s390x_2_s.s: s390x specific, -fsplit-stack calling non-split
+
+	.text
+
+	.global	fn2
+	.type	fn2,@function
+fn2:
+	br	%r14
+
+	.size	fn2,. - fn2
+
+	.section	.note.GNU-stack,"",@progbits
+	.section	.note.GNU-split-stack,"",@progbits
-- 
2.6.3


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]