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]

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


This adds split-stack support to gold for s390.  The corresponding gcc
changes are at https://github.com/koriakin/gcc/tree/s390-ss .  Roughly,
the split-stack prologue for s390 works as follows:

- if the stack frame is small enough that its size fits in an add
  instruction (alfi, ahi, algfi, aghi - whichever is supported),
  the stack guard (from TLS) is compared to stack pointer - frame
  size, and if there's enough space, a direct jump is made to the
  function body (skipping the call).  If the stack frame is large,
  __morestack will do the check anyway.
- otherwise, __morestack is called.  Since there's only one easily
  available register (%r1), and the parameters are link-time constants,
  the parameters are gathered in a static memory block, and its address
  is passed in %r1.  One of the parameters is the frame size.  For ESA
  mode, the parameter block resides directly in the function code (like
  a literal pool), while for z/Arch, it resides in .rodata section (for
  cache-related reasons).
- as usual, if a split-stack function is found to call a non-split-stack
  function at link time, it needs to be "fixed" by the linker.  In case
  of s390, it involves bumping the frame size in the parameter block,
  bumping the frame size in the add instruction (if applicable), or
  nopping out the whole comparison if it can no longer fit in the add
  instruction.

The problem here is that I have to get to the proper place in .rodata
(and mutate it), starting from the text section by parsing the
relocation of the larl instruction aiming at it.  The parameters
currently passed into do_calls_non_split unfortunately don't seem to
allow this.

I have managed to get it working, but only by making a lot of private
or protected things public, and changing some types.  In summary:

- the private Views class used in reloc.cc is made public and routed
  to do_calls_non_split.
- Relobj's output_sections method is likewise made public.
- text section's relocation pointer and count are also routed to
  do_calls_non_split.
- since calls_non_split now takes a templated-type parameter (the reloc
  pointer), it's moved to Sized_target class, and a few ugly dynamic
  casts are inserted.

Overall, the changes are pretty horrible.  Is there some better way
to walk through a relocation in the text section to a place in another
section?  The current patch seems way too intrusive to me.

Thanks for any suggestions.

---
 configure                         |   2 +-
 gold/Makefile.in                  |   2 +-
 gold/i386.cc                      |  10 +-
 gold/object.h                     |  54 ++---
 gold/powerpc.cc                   |  15 +-
 gold/reloc.cc                     |  18 +-
 gold/s390.cc                      | 440 ++++++++++++++++++++++++++++++++++++++
 gold/target.cc                    |  43 ++--
 gold/target.h                     |  62 ++++--
 gold/testsuite/Makefile.am        | 204 ++++++++++++++++++
 gold/testsuite/Makefile.in        | 215 ++++++++++++++++++-
 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 ++
 gold/x86_64.cc                    |  10 +-
 35 files changed, 1865 insertions(+), 88 deletions(-)
 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/configure b/configure
index 3bb1c03..91fd098 100755
--- a/configure
+++ b/configure
@@ -2972,7 +2972,7 @@ case "${ENABLE_GOLD}" in
       # Check for target supported by gold.
       case "${target}" in
         i?86-*-* | x86_64-*-* | sparc*-*-* | powerpc*-*-* | arm*-*-* \
-        | aarch64*-*-* | tilegx*-*-*)
+        | aarch64*-*-* | tilegx*-*-* | s390*-*-*)
 	  configdirs="$configdirs gold"
 	  if test x${ENABLE_GOLD} = xdefault; then
 	    default_ld=gold
diff --git a/gold/Makefile.in b/gold/Makefile.in
index dbfde80..aa04f8b 100644
--- a/gold/Makefile.in
+++ b/gold/Makefile.in
@@ -71,7 +71,7 @@ DIST_COMMON = NEWS README ChangeLog $(srcdir)/Makefile.in \
 	$(srcdir)/Makefile.am $(top_srcdir)/configure \
 	$(am__configure_deps) $(srcdir)/config.in \
 	$(srcdir)/../mkinstalldirs $(top_srcdir)/po/Make-in pread.c \
-	ffsll.c ftruncate.c mremap.c yyscript.h yyscript.c \
+	mremap.c ffsll.c ftruncate.c yyscript.h yyscript.c \
 	$(srcdir)/../depcomp $(srcdir)/../ylwrap
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
diff --git a/gold/i386.cc b/gold/i386.cc
index 8cc7244..1d6adf3 100644
--- a/gold/i386.cc
+++ b/gold/i386.cc
@@ -487,12 +487,15 @@ class Target_i386 : public Sized_target<32, false>
   bool
   do_is_call_to_non_split(const Symbol* sym, unsigned int) const;
 
+  typedef typename Sized_relobj_file<32, false>::Views Views;
+
   // 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,
 		     unsigned char* view, section_size_type view_size,
-		     std::string* from, std::string* to) const;
+		     std::string* from, std::string* to,
+		     const unsigned char *, size_t, Views *) const;
 
   // Return the size of the GOT section.
   section_size_type
@@ -3884,7 +3887,10 @@ Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
 				       unsigned char* view,
 				       section_size_type view_size,
 				       std::string* from,
-				       std::string* to) const
+				       std::string* to,
+				       const unsigned char *,
+				       size_t,
+				       Views *) const
 {
   // The function starts with a comparison of the stack pointer and a
   // field in the TCB.  This is followed by a jump.
diff --git a/gold/object.h b/gold/object.h
index f408408..3268fae 100644
--- a/gold/object.h
+++ b/gold/object.h
@@ -1365,12 +1365,21 @@ class Relobj : public Object
   is_big_endian() const
   { return this->do_is_big_endian(); }
 
- protected:
   // The output section to be used for each input section, indexed by
   // the input section number.  The output section is NULL if the
   // input section is to be discarded.
   typedef std::vector<Output_section*> Output_sections;
 
+  // Return the vector mapping input sections to output sections.
+  Output_sections&
+  output_sections()
+  { return this->output_sections_; }
+
+  const Output_sections&
+  output_sections() const
+  { return this->output_sections_; }
+
+ protected:
   // Read the relocs--implemented by child class.
   virtual void
   do_read_relocs(Read_relocs_data*) = 0;
@@ -1466,15 +1475,6 @@ class Relobj : public Object
     return this->output_sections_[shndx];
   }
 
-  // Return the vector mapping input sections to output sections.
-  Output_sections&
-  output_sections()
-  { return this->output_sections_; }
-
-  const Output_sections&
-  output_sections() const
-  { return this->output_sections_; }
-
   // Set the size of the relocatable relocs array.
   void
   size_relocatable_relocs()
@@ -2316,6 +2316,20 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   bool is_deferred_layout() const
   { return this->is_deferred_layout_; }
 
+  // Views and sizes when relocating.
+  struct View_size
+  {
+    unsigned char* view;
+    typename elfcpp::Elf_types<size>::Elf_Addr address;
+    off_t offset;
+    section_size_type view_size;
+    bool is_input_output_view;
+    bool is_postprocessing_view;
+    bool is_ctors_reverse_view;
+  };
+
+  typedef std::vector<View_size> Views;
+
  protected:
   typedef typename Sized_relobj<size, big_endian>::Output_sections
       Output_sections;
@@ -2527,20 +2541,6 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
   local_values()
   { return &this->local_values_; }
 
-  // Views and sizes when relocating.
-  struct View_size
-  {
-    unsigned char* view;
-    typename elfcpp::Elf_types<size>::Elf_Addr address;
-    off_t offset;
-    section_size_type view_size;
-    bool is_input_output_view;
-    bool is_postprocessing_view;
-    bool is_ctors_reverse_view;
-  };
-
-  typedef std::vector<View_size> Views;
-
   // Stash away info for a number of special sections.
   // Return true if any of the sections found require local symbols to be read.
   virtual bool
@@ -2696,7 +2696,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
 		     unsigned int sh_type, unsigned int shndx,
 		     const unsigned char* prelocs, size_t reloc_count,
 		     unsigned char* view, section_size_type view_size,
-		     Reloc_symbol_changes** reloc_map);
+		     Reloc_symbol_changes** reloc_map,
+		     Views *pviews);
 
   template<int sh_type>
   void
@@ -2704,7 +2705,8 @@ class Sized_relobj_file : public Sized_relobj<size, big_endian>
 			     unsigned int shndx, const unsigned char* prelocs,
 			     size_t reloc_count, unsigned char* view,
 			     section_size_type view_size,
-			     Reloc_symbol_changes** reloc_map);
+			     Reloc_symbol_changes** reloc_map,
+			     Views *pviews);
 
   // Find all functions in a section.
   void
diff --git a/gold/powerpc.cc b/gold/powerpc.cc
index 59d04b3..25a7288 100644
--- a/gold/powerpc.cc
+++ b/gold/powerpc.cc
@@ -627,12 +627,15 @@ class Target_powerpc : public Sized_target<size, big_endian>
   do_can_check_for_function_pointers() const
   { return true; }
 
+  typedef typename Sized_relobj_file<size, big_endian>::Views Views;
+
   // 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,
 		     unsigned char* view, section_size_type view_size,
-		     std::string* from, std::string* to) const;
+		     std::string* from, std::string* to,
+		     const unsigned char *, size_t, Views *) const;
 
   // Relocate a section.
   void
@@ -6593,14 +6596,18 @@ Target_powerpc<size, big_endian>::do_calls_non_split(
     unsigned char* view,
     section_size_type view_size,
     std::string* from,
-    std::string* to) const
+    std::string* to,
+    const unsigned char *prelocs,
+    size_t reloc_count,
+    Views *pviews) const
 {
   // 32-bit not supported.
   if (size == 32)
     {
       // warn
-      Target::do_calls_non_split(object, shndx, fnoffset, fnsize,
-				 view, view_size, from, to);
+      Sized_target<size, big_endian>::do_calls_non_split(object, shndx, fnoffset, fnsize,
+				 view, view_size, from, to,
+				 prelocs, reloc_count, pviews);
       return;
     }
 
diff --git a/gold/reloc.cc b/gold/reloc.cc
index f18f432..995b447 100644
--- a/gold/reloc.cc
+++ b/gold/reloc.cc
@@ -1007,7 +1007,7 @@ Sized_relobj_file<size, big_endian>::do_relocate_sections(
 	  if ((data_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0)
 	    this->split_stack_adjust(symtab, pshdrs, sh_type, index,
 				     prelocs, reloc_count, view, view_size,
-				     &reloc_map);
+				     &reloc_map, pviews);
 	}
 
       Relocatable_relocs* rr = NULL;
@@ -1207,20 +1207,21 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust(
     size_t reloc_count,
     unsigned char* view,
     section_size_type view_size,
-    Reloc_symbol_changes** reloc_map)
+    Reloc_symbol_changes** reloc_map,
+    Views *pviews)
 {
   if (sh_type == elfcpp::SHT_REL)
     this->split_stack_adjust_reltype<elfcpp::SHT_REL>(symtab, pshdrs, shndx,
 						      prelocs, reloc_count,
 						      view, view_size,
-						      reloc_map);
+						      reloc_map, pviews);
   else
     {
       gold_assert(sh_type == elfcpp::SHT_RELA);
       this->split_stack_adjust_reltype<elfcpp::SHT_RELA>(symtab, pshdrs, shndx,
 							 prelocs, reloc_count,
 							 view, view_size,
-							 reloc_map);
+							 reloc_map, pviews);
     }
 }
 
@@ -1238,7 +1239,8 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
     size_t reloc_count,
     unsigned char* view,
     section_size_type view_size,
-    Reloc_symbol_changes** reloc_map)
+    Reloc_symbol_changes** reloc_map,
+    Views *pviews)
 {
   typedef typename Reloc_types<sh_type, size, big_endian>::Reloc Reltype;
   const int reloc_size = Reloc_types<sh_type, size, big_endian>::reloc_size;
@@ -1330,8 +1332,10 @@ Sized_relobj_file<size, big_endian>::split_stack_adjust_reltype(
     {
       std::string from;
       std::string to;
-      parameters->target().calls_non_split(this, shndx, p->first, p->second,
-					   view, view_size, &from, &to);
+      dynamic_cast<const Sized_target<size, big_endian> &>(parameters->target())
+			  .calls_non_split(this, shndx, p->first, p->second,
+					   view, view_size, &from, &to,
+					   prelocs, reloc_count, pviews);
       if (!from.empty())
 	{
 	  gold_assert(!to.empty());
diff --git a/gold/s390.cc b/gold/s390.cc
index 45c0ba7..caba543 100644
--- a/gold/s390.cc
+++ b/gold/s390.cc
@@ -402,6 +402,17 @@ class Target_s390 : public Sized_target<size, true>
   do_can_check_for_function_pointers() const
   { return true; }
 
+  typedef typename Sized_relobj_file<size, true>::Views Views;
+
+  // 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,
+		     unsigned char* view, section_size_type view_size,
+		     std::string* from, std::string* to,
+		     const unsigned char *prelocs,
+		     size_t reloc_count, Views *pviews) const;
+
   // Return the size of the GOT section.
   section_size_type
   got_size() const
@@ -724,6 +735,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 +4270,419 @@ 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,
+				      unsigned char* view,
+				      section_size_type view_size,
+				      std::string*,
+				      std::string*,
+				      const unsigned char *prelocs,
+				      size_t reloc_count,
+				      Views *pviews) 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(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(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(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(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(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 (static_cast<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(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 (static_cast<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(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(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;
+              const Symbol_value<size>* sym = dynamic_cast<Sized_relobj_file<size, true> *>(object)->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_sections()[param_shndx]->address();
+	      param_view = (*pviews)[param_shndx].view;
+	      param_view_size = (*pviews)[param_shndx].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(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(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 (static_cast<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(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(view, view_size, curoffset, ss_code_basr,
+			   sizeof ss_code_basr))
+	curoffset += sizeof ss_code_basr;
+      else if (this->match_view(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 (static_cast<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/target.cc b/gold/target.cc
index f558c5e..8e74cb5 100644
--- a/gold/target.cc
+++ b/gold/target.cc
@@ -157,23 +157,6 @@ Target::do_is_call_to_non_split(const Symbol* sym, unsigned int) const
   return sym->type() == elfcpp::STT_FUNC;
 }
 
-// Default conversion for -fsplit-stack is to give an error.
-
-void
-Target::do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
-			   section_size_type, unsigned char*, section_size_type,
-			   std::string*, std::string*) const
-{
-  static bool warned;
-  if (!warned)
-    {
-      gold_error(_("linker does not include stack split support "
-		   "required by %s"),
-		 object->name().c_str());
-      warned = true;
-    }
-}
-
 //  Return whether BYTES/LEN matches VIEW/VIEW_SIZE at OFFSET.
 
 bool
@@ -237,6 +220,32 @@ Sized_target<size, big_endian>::do_adjust_elf_header(unsigned char* view,
     }
 }
 
+// Default conversion for -fsplit-stack is to give an error.
+
+template<int size, bool big_endian>
+void
+Sized_target<size, big_endian>::do_calls_non_split(Relobj* object,
+						   unsigned int,
+						   section_offset_type,
+						   section_size_type,
+						   unsigned char*,
+						   section_size_type,
+						   std::string*,
+						   std::string*,
+						   const unsigned char *,
+						   size_t,
+						   Views *) const
+{
+  static bool warned;
+  if (!warned)
+    {
+      gold_error(_("linker does not include stack split support "
+		   "required by %s"),
+		 object->name().c_str());
+      warned = true;
+    }
+}
+
 #ifdef HAVE_TARGET_32_LITTLE
 template
 class Sized_target<32, false>;
diff --git a/gold/target.h b/gold/target.h
index 6e08f38..04f51b8 100644
--- a/gold/target.h
+++ b/gold/target.h
@@ -38,6 +38,9 @@
 #include "parameters.h"
 #include "stringpool.h"
 #include "debug.h"
+#include "fileread.h"
+#include "reloc.h"
+#include "object.h"
 
 namespace gold
 {
@@ -329,22 +332,6 @@ class Target
   is_call_to_non_split(const Symbol* sym, unsigned int r_type) const
   { return this->do_is_call_to_non_split(sym, r_type); }
 
-  // A function starts at OFFSET in section SHNDX in OBJECT.  That
-  // function was compiled with -fsplit-stack, but it refers to a
-  // function which was compiled without -fsplit-stack.  VIEW is a
-  // modifiable view of the section; VIEW_SIZE is the size of the
-  // view.  The target has to adjust the function so that it allocates
-  // enough stack.
-  void
-  calls_non_split(Relobj* object, unsigned int shndx,
-		  section_offset_type fnoffset, section_size_type fnsize,
-		  unsigned char* view, section_size_type view_size,
-		  std::string* from, std::string* to) const
-  {
-    this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
-			     from, to);
-  }
-
   // Make an ELF object.
   template<int size, bool big_endian>
   Object*
@@ -661,12 +648,6 @@ class Target
   virtual bool
   do_is_call_to_non_split(const Symbol* sym, unsigned int) const;
 
-  // Virtual function which may be overridden by the child class.
-  virtual void
-  do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
-		     section_size_type, unsigned char*, section_size_type,
-		     std::string*, std::string*) const;
-
   // make_elf_object hooks.  There are four versions of these for
   // different address sizes and endianness.
 
@@ -727,6 +708,16 @@ class Target
   match_view(const unsigned char* view, section_size_type view_size,
 	     section_offset_type offset, const char* bytes, size_t len) const;
 
+  // A function for targets to call.  Return whether BYTES/LEN matches
+  // VIEW/VIEW_SIZE at OFFSET.
+  bool
+  match_view(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);
+    }
+
   // Set the contents of a VIEW/VIEW_SIZE to nops starting at OFFSET
   // for LEN bytes.
   void
@@ -823,6 +814,8 @@ template<int size, bool big_endian>
 class Sized_target : public Target
 {
  public:
+  typedef typename Sized_relobj_file<size, big_endian>::Views Views;
+
   // Make a new symbol table entry for the target.  This should be
   // overridden by a target which needs additional information in the
   // symbol table.  This will only be called if has_make_symbol()
@@ -1081,6 +1074,24 @@ class Sized_target : public Target
 			      dst_obj, dst_shndx, dst_off);
   }
 
+  // A function starts at OFFSET in section SHNDX in OBJECT.  That
+  // function was compiled with -fsplit-stack, but it refers to a
+  // function which was compiled without -fsplit-stack.  VIEW is a
+  // modifiable view of the section; VIEW_SIZE is the size of the
+  // view.  The target has to adjust the function so that it allocates
+  // enough stack.
+  void
+  calls_non_split(Relobj* object, unsigned int shndx,
+		  section_offset_type fnoffset, section_size_type fnsize,
+		  unsigned char* view, section_size_type view_size,
+		  std::string* from, std::string* to,
+		  const unsigned char *prelocs, size_t reloc_count,
+		  Views *pviews) const
+  {
+    this->do_calls_non_split(object, shndx, fnoffset, fnsize, view, view_size,
+			     from, to, prelocs, reloc_count, pviews);
+  }
+
  protected:
   Sized_target(const Target::Target_info* pti)
     : Target(pti)
@@ -1100,6 +1111,13 @@ class Sized_target : public Target
 		      typename elfcpp::Elf_types<size>::Elf_Addr) const
   { }
 
+  // Virtual function which may be overridden by the child class.
+  virtual void
+  do_calls_non_split(Relobj* object, unsigned int, section_offset_type,
+		     section_size_type, unsigned char*, section_size_type,
+		     std::string*, std::string*, const unsigned char *,
+		     size_t, Views *) const;
+
   virtual void
   do_function_location(Symbol_location*) const
   { }
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/Makefile.in b/gold/testsuite/Makefile.in
index 31c9951..f7f8e09 100644
--- a/gold/testsuite/Makefile.in
+++ b/gold/testsuite/Makefile.in
@@ -816,10 +816,38 @@ check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
 @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	arm_farcall_thumb_thumb_6m \
 @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	arm_farcall_thumb_arm \
 @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	arm_farcall_thumb_arm_5t
-@DEFAULT_TARGET_X86_64_TRUE@am__append_88 = *.dwo *.dwp
-@DEFAULT_TARGET_X86_64_TRUE@am__append_89 = dwp_test_1.sh \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_88 = split_s390.sh
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_89 = split_s390_e1.stdout split_s390_e2.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_e3.stdout split_s390_e4.stdout split_s390_z1.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_z2.stdout split_s390_z3.stdout split_s390_z4.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_n.stdout split_s390_a1.stdout split_s390_a2.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_e1_ns.stdout split_s390_e2_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_e3_ns.stdout split_s390_e4_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_z1_ns.stdout split_s390_z2_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_z3_ns.stdout split_s390_z4_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_n_ns.stdout split_s390_r.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_z1.stdout split_s390x_z2.stdout split_s390x_z3.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_z4.stdout split_s390x_n.stdout split_s390x_a1.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_a2.stdout split_s390x_z1_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_z2_ns.stdout split_s390x_z3_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_z4_ns.stdout split_s390x_n_ns.stdout \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_r.stdout
+
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@am__append_90 = split_s390_1_e1 split_s390_1_e2 split_s390_1_e3 \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_1_e4 split_s390_1_z1 split_s390_1_z2 split_s390_1_z3 \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_1_z4 split_s390_1_n split_s390_1_a1 split_s390_1_a2 \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_1_e1_ns split_s390_1_e2_ns split_s390_1_e3_ns \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_1_e4_ns split_s390_1_z1_ns split_s390_1_z2_ns \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_1_z3_ns split_s390_1_z4_ns split_s390_1_n_ns \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390_r split_s390x_1_z1 split_s390x_1_z2 split_s390x_1_z3 \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_1_z4 split_s390x_1_n split_s390x_1_a1 split_s390x_1_a2 \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_1_z1_ns split_s390x_1_z2_ns split_s390x_1_z3_ns \
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	split_s390x_1_z4_ns split_s390x_1_n_ns split_s390x_r
+
+@DEFAULT_TARGET_X86_64_TRUE@am__append_91 = *.dwo *.dwp
+@DEFAULT_TARGET_X86_64_TRUE@am__append_92 = dwp_test_1.sh \
 @DEFAULT_TARGET_X86_64_TRUE@	dwp_test_2.sh
-@DEFAULT_TARGET_X86_64_TRUE@am__append_90 = dwp_test_1.stdout \
+@DEFAULT_TARGET_X86_64_TRUE@am__append_93 = dwp_test_1.stdout \
 @DEFAULT_TARGET_X86_64_TRUE@	dwp_test_2.stdout
 subdir = testsuite
 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
@@ -2461,7 +2489,7 @@ MOSTLYCLEANFILES = *.so *.syms *.stdout $(am__append_4) \
 	$(am__append_45) $(am__append_51) $(am__append_67) \
 	$(am__append_70) $(am__append_72) $(am__append_75) \
 	$(am__append_78) $(am__append_81) $(am__append_84) \
-	$(am__append_87) $(am__append_88)
+	$(am__append_87) $(am__append_90) $(am__append_91)
 
 # We will add to these later, for each individual test.  Note
 # that we add each test under check_SCRIPTS or check_PROGRAMS;
@@ -2471,13 +2499,13 @@ check_SCRIPTS = $(am__append_2) $(am__append_20) $(am__append_26) \
 	$(am__append_42) $(am__append_46) $(am__append_49) \
 	$(am__append_65) $(am__append_68) $(am__append_73) \
 	$(am__append_76) $(am__append_79) $(am__append_82) \
-	$(am__append_85) $(am__append_89)
+	$(am__append_85) $(am__append_88) $(am__append_92)
 check_DATA = $(am__append_3) $(am__append_21) $(am__append_27) \
 	$(am__append_30) $(am__append_36) $(am__append_39) \
 	$(am__append_43) $(am__append_47) $(am__append_50) \
 	$(am__append_66) $(am__append_69) $(am__append_74) \
 	$(am__append_77) $(am__append_80) $(am__append_83) \
-	$(am__append_86) $(am__append_90)
+	$(am__append_86) $(am__append_89) $(am__append_93)
 BUILT_SOURCES = $(am__append_33)
 TESTS = $(check_SCRIPTS) $(check_PROGRAMS)
 
@@ -2979,6 +3007,7 @@ LDADD = libgoldtest.a ../libgold.a ../../libiberty/libiberty.a $(LIBINTL) \
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_x86_64_bnd_test_LDFLAGS = $(exception_test_LDFLAGS)
 @DEFAULT_TARGET_X86_64_TRUE@@GCC_TRUE@@NATIVE_LINKER_TRUE@exception_x86_64_bnd_test_LDADD = exception_x86_64_bnd_1.o exception_x86_64_bnd_2.o
 @DEFAULT_TARGET_I386_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
 @DEFAULT_TARGET_X32_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
 @DEFAULT_TARGET_X86_64_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
 all: $(BUILT_SOURCES)
@@ -4540,6 +4569,8 @@ arm_farcall_thumb_thumb.sh.log: arm_farcall_thumb_thumb.sh
 	@p='arm_farcall_thumb_thumb.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 arm_farcall_thumb_arm.sh.log: arm_farcall_thumb_arm.sh
 	@p='arm_farcall_thumb_arm.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
+split_s390.sh.log: split_s390.sh
+	@p='split_s390.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 dwp_test_1.sh.log: dwp_test_1.sh
 	@p='dwp_test_1.sh'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post)
 dwp_test_2.sh.log: dwp_test_2.sh
@@ -6830,6 +6861,178 @@ uninstall-am:
 
 @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@arm_farcall_thumb_arm_5t.o: arm_farcall_thumb_arm.s
 @DEFAULT_TARGET_ARM_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -march=armv5t -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_e1.o: split_s390_1_e1.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_e2.o: split_s390_1_e2.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_e3.o: split_s390_1_e3.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_e4.o: split_s390_1_e4.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_z1.o: split_s390_1_z1.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_z2.o: split_s390_1_z2.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_z3.o: split_s390_1_z3.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_z4.o: split_s390_1_z4.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_n.o: split_s390_1_n.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_a1.o: split_s390_1_a1.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_1_a2.o: split_s390_1_a2.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_2_s.o: split_s390_2_s.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_2_ns.o: split_s390_2_ns.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m31 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e1: split_s390_1_e1.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e1.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e1.stdout: split_s390_e1
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e2: split_s390_1_e2.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e2.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e2.stdout: split_s390_e2
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e3: split_s390_1_e3.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e3.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e3.stdout: split_s390_e3
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e4: split_s390_1_e4.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e4.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e4.stdout: split_s390_e4
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z1: split_s390_1_z1.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z1.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z1.stdout: split_s390_z1
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z2: split_s390_1_z2.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z2.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z2.stdout: split_s390_z2
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z3: split_s390_1_z3.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z3.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z3.stdout: split_s390_z3
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z4: split_s390_1_z4.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z4.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z4.stdout: split_s390_z4
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_n: split_s390_1_n.o split_s390_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_n.o split_s390_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_n.stdout: split_s390_n
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e1_ns: split_s390_1_e1.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e1.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e1_ns.stdout: split_s390_e1_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e2_ns: split_s390_1_e2.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e2.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e2_ns.stdout: split_s390_e2_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e3_ns: split_s390_1_e3.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e3.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e3_ns.stdout: split_s390_e3_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e4_ns: split_s390_1_e4.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e4.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_e4_ns.stdout: split_s390_e4_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z1_ns: split_s390_1_z1.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z1.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z1_ns.stdout: split_s390_z1_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z2_ns: split_s390_1_z2.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z2.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z2_ns.stdout: split_s390_z2_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z3_ns: split_s390_1_z3.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z3.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z3_ns.stdout: split_s390_z3_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z4_ns: split_s390_1_z4.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z4.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_z4_ns.stdout: split_s390_z4_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_n_ns: split_s390_1_n.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_n.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_n_ns.stdout: split_s390_n_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_a1.stdout: split_s390_1_a1.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o split_s390_a1 split_s390_1_a1.o split_s390_2_ns.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_a2: split_s390_1_a2.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_a2.o split_s390_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_a2.stdout: split_s390_a2
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390_r.stdout: split_s390_1_z1.o split_s390_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new -r split_s390_1_z1.o split_s390_2_ns.o -o split_s390_r > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_z1.o: split_s390x_1_z1.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_z2.o: split_s390x_1_z2.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_z3.o: split_s390x_1_z3.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_z4.o: split_s390x_1_z4.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_n.o: split_s390x_1_n.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_a1.o: split_s390x_1_a1.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_1_a2.o: split_s390x_1_a2.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_2_s.o: split_s390x_2_s.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_2_ns.o: split_s390x_2_ns.s
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_AS) -m64 -o $@ $<
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z1: split_s390x_1_z1.o split_s390x_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z1.o split_s390x_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z1.stdout: split_s390x_z1
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z2: split_s390x_1_z2.o split_s390x_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z2.o split_s390x_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z2.stdout: split_s390x_z2
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z3: split_s390x_1_z3.o split_s390x_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z3.o split_s390x_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z3.stdout: split_s390x_z3
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z4: split_s390x_1_z4.o split_s390x_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z4.o split_s390x_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z4.stdout: split_s390x_z4
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_n: split_s390x_1_n.o split_s390x_2_s.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_n.o split_s390x_2_s.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_n.stdout: split_s390x_n
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z1_ns: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z1.o split_s390x_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z1_ns.stdout: split_s390x_z1_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z2_ns: split_s390x_1_z2.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z2.o split_s390x_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z2_ns.stdout: split_s390x_z2_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z3_ns: split_s390x_1_z3.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z3.o split_s390x_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z3_ns.stdout: split_s390x_z3_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z4_ns: split_s390x_1_z4.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z4.o split_s390x_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_z4_ns.stdout: split_s390x_z4_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_n_ns: split_s390x_1_n.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_n.o split_s390x_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_n_ns.stdout: split_s390x_n_ns
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_a1.stdout: split_s390x_1_a1.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o split_s390x_a1 split_s390x_1_a1.o split_s390x_2_ns.o > $@ 2>&1 || exit 0
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_a2: split_s390x_1_a2.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_a2.o split_s390x_2_ns.o
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_a2.stdout: split_s390x_a2
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	$(TEST_OBJDUMP) -d $< > $@
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@split_s390x_r.stdout: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
+@DEFAULT_TARGET_S390_TRUE@@NATIVE_OR_CROSS_LINKER_TRUE@	../ld-new -r split_s390x_1_z1.o split_s390x_2_ns.o -o split_s390x_r > $@ 2>&1 || exit 0
 
 # Tests for the dwp tool.
 # We don't want to rely yet on GCC support for -gsplit-dwarf,
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
diff --git a/gold/x86_64.cc b/gold/x86_64.cc
index 12c6552..1ae3cb6 100644
--- a/gold/x86_64.cc
+++ b/gold/x86_64.cc
@@ -557,12 +557,15 @@ class Target_x86_64 : public Sized_target<size, false>
   uint64_t
   do_ehframe_datarel_base() const;
 
+  typedef typename Sized_relobj_file<size, false>::Views Views;
+
   // 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,
 		     unsigned char* view, section_size_type view_size,
-		     std::string* from, std::string* to) const;
+		     std::string* from, std::string* to,
+		     const unsigned char *, size_t, Views *) const;
 
   // Return the size of the GOT section.
   section_size_type
@@ -4600,7 +4603,10 @@ Target_x86_64<size>::do_calls_non_split(Relobj* object, unsigned int shndx,
 					unsigned char* view,
 					section_size_type view_size,
 					std::string* from,
-					std::string* to) const
+					std::string* to,
+					const unsigned char *,
+					size_t,
+					Views *) const
 {
   const char* const cmp_insn = reinterpret_cast<const char*>
       (size == 32 ? cmp_insn_32 : cmp_insn_64);
-- 
2.6.3


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