This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH v2] gold: Add s390 -fsplit-stack support.
- From: Marcin KoÅcielnicki <koriakin at 0x04 dot net>
- To: ccoutant at gmail dot com
- Cc: binutils at sourceware dot org, Marcin KoÅcielnicki <koriakin at 0x04 dot net>
- Date: Sat, 2 Jan 2016 20:34:15 +0100
- Subject: [PATCH v2] gold: Add s390 -fsplit-stack support.
- Authentication-results: sourceware.org; auth=none
gold/ChangeLog:
* s390.cc (Target_s390::match_view_u): New helper method.
(Target_s390::ss_code_nopmark): New const.
(Target_s390::ss_code_st_r14): New const.
(Target_s390::ss_code_l_r14): New const.
(Target_s390::ss_code_bras_8): New const.
(Target_s390::ss_code_l_basr): New const.
(Target_s390::ss_code_a_basr): New const.
(Target_s390::ss_code_ear): New const.
(Target_s390::ss_code_c): New const.
(Target_s390::ss_code_larl): New const.
(Target_s390::ss_code_brasl): New const.
(Target_s390::ss_code_jg): New const.
(Target_s390::ss_code_jgl): New const.
(Target_s390::ss_code_jl): New const.
(Target_s390::ss_code_jhe): New const.
(Target_s390::ss_code_basr): New const.
(Target_s390::ss_code_basr_2): New const.
(Target_s390::ss_match_mcount): New helper method.
(Target_s390::ss_match_l): New helper method.
(Target_s390::ss_match_ahi): New helper method.
(Target_s390::ss_match_alfi): New helper method.
(Target_s390::ss_match_cr): New helper method.
(Target_s390::do_calls_non_split): New method.
* testsuite/Makefile.am: Added new tests.
* testsuite/split_s390.sh: New test.
* testsuite/split_s390_1_a1.s: New test.
* testsuite/split_s390_1_a2.s: New test.
* testsuite/split_s390_1_e1.s: New test.
* testsuite/split_s390_1_e2.s: New test.
* testsuite/split_s390_1_e3.s: New test.
* testsuite/split_s390_1_e4.s: New test.
* testsuite/split_s390_1_n.s: New test.
* testsuite/split_s390_1_z1.s: New test.
* testsuite/split_s390_1_z2.s: New test.
* testsuite/split_s390_1_z3.s: New test.
* testsuite/split_s390_1_z4.s: New test.
* testsuite/split_s390_2_ns.s: New test.
* testsuite/split_s390_2_s.s: New test.
* testsuite/split_s390x_1_a1.s: New test.
* testsuite/split_s390x_1_a2.s: New test.
* testsuite/split_s390x_1_n.s: New test.
* testsuite/split_s390x_1_z1.s: New test.
* testsuite/split_s390x_1_z2.s: New test.
* testsuite/split_s390x_1_z3.s: New test.
* testsuite/split_s390x_1_z4.s: New test.
* testsuite/split_s390x_2_ns.s: New test.
* testsuite/split_s390x_2_s.s: New test.
---
I found a few problems with v1:
- I used input section offset of param block in .rodata instead of
output section offset. Fixed by subtracting output_section_offset.
- Turns out -frename-registers may cause other registers than %r1
to be used for the stack guard computation. I wrote ss_match_*
functions to recognize them instead of using hardcoded byte sequences.
- When -pg is used together with -fsplit-stack, the call to _mcount is
emitted before split-stack prologue. ss_match_mcount will recognize
and skip it.
It's still waiting for review on the gcc side of things.
Btw, do I qualify for write after approval access to binutils? I already
have push access to the repo due to my gdb work, but I'm not sure if I'm
supposed to use it for my binutils patches (I have a few
-Wmisleading-indentation fixes to push as obvious).
gold/ChangeLog | 50 +++
gold/s390.cc | 649 ++++++++++++++++++++++++++++++++++++++
gold/testsuite/Makefile.am | 204 ++++++++++++
gold/testsuite/split_s390.sh | 149 +++++++++
gold/testsuite/split_s390_1_a1.s | 36 +++
gold/testsuite/split_s390_1_a2.s | 37 +++
gold/testsuite/split_s390_1_e1.s | 45 +++
gold/testsuite/split_s390_1_e2.s | 48 +++
gold/testsuite/split_s390_1_e3.s | 49 +++
gold/testsuite/split_s390_1_e4.s | 51 +++
gold/testsuite/split_s390_1_n.s | 18 ++
gold/testsuite/split_s390_1_z1.s | 37 +++
gold/testsuite/split_s390_1_z2.s | 40 +++
gold/testsuite/split_s390_1_z3.s | 41 +++
gold/testsuite/split_s390_1_z4.s | 41 +++
gold/testsuite/split_s390_2_ns.s | 12 +
gold/testsuite/split_s390_2_s.s | 13 +
gold/testsuite/split_s390x_1_a1.s | 27 ++
gold/testsuite/split_s390x_1_a2.s | 28 ++
gold/testsuite/split_s390x_1_n.s | 17 +
gold/testsuite/split_s390x_1_z1.s | 37 +++
gold/testsuite/split_s390x_1_z2.s | 41 +++
gold/testsuite/split_s390x_1_z3.s | 43 +++
gold/testsuite/split_s390x_1_z4.s | 43 +++
gold/testsuite/split_s390x_2_ns.s | 12 +
gold/testsuite/split_s390x_2_s.s | 13 +
26 files changed, 1781 insertions(+)
create mode 100755 gold/testsuite/split_s390.sh
create mode 100644 gold/testsuite/split_s390_1_a1.s
create mode 100644 gold/testsuite/split_s390_1_a2.s
create mode 100644 gold/testsuite/split_s390_1_e1.s
create mode 100644 gold/testsuite/split_s390_1_e2.s
create mode 100644 gold/testsuite/split_s390_1_e3.s
create mode 100644 gold/testsuite/split_s390_1_e4.s
create mode 100644 gold/testsuite/split_s390_1_n.s
create mode 100644 gold/testsuite/split_s390_1_z1.s
create mode 100644 gold/testsuite/split_s390_1_z2.s
create mode 100644 gold/testsuite/split_s390_1_z3.s
create mode 100644 gold/testsuite/split_s390_1_z4.s
create mode 100644 gold/testsuite/split_s390_2_ns.s
create mode 100644 gold/testsuite/split_s390_2_s.s
create mode 100644 gold/testsuite/split_s390x_1_a1.s
create mode 100644 gold/testsuite/split_s390x_1_a2.s
create mode 100644 gold/testsuite/split_s390x_1_n.s
create mode 100644 gold/testsuite/split_s390x_1_z1.s
create mode 100644 gold/testsuite/split_s390x_1_z2.s
create mode 100644 gold/testsuite/split_s390x_1_z3.s
create mode 100644 gold/testsuite/split_s390x_1_z4.s
create mode 100644 gold/testsuite/split_s390x_2_ns.s
create mode 100644 gold/testsuite/split_s390x_2_s.s
diff --git a/gold/ChangeLog b/gold/ChangeLog
index e48be00..afecc51 100644
--- a/gold/ChangeLog
+++ b/gold/ChangeLog
@@ -1,3 +1,53 @@
+2015-12-22 Marcin KoÅcielnicki <koriakin@0x04.net>
+
+ * s390.cc (Target_s390::match_view_u): New helper method.
+ (Target_s390::ss_code_nopmark): New const.
+ (Target_s390::ss_code_st_r14): New const.
+ (Target_s390::ss_code_l_r14): New const.
+ (Target_s390::ss_code_bras_8): New const.
+ (Target_s390::ss_code_l_basr): New const.
+ (Target_s390::ss_code_a_basr): New const.
+ (Target_s390::ss_code_ear): New const.
+ (Target_s390::ss_code_c): New const.
+ (Target_s390::ss_code_larl): New const.
+ (Target_s390::ss_code_brasl): New const.
+ (Target_s390::ss_code_jg): New const.
+ (Target_s390::ss_code_jgl): New const.
+ (Target_s390::ss_code_jl): New const.
+ (Target_s390::ss_code_jhe): New const.
+ (Target_s390::ss_code_basr): New const.
+ (Target_s390::ss_code_basr_2): New const.
+ (Target_s390::ss_match_mcount): New helper method.
+ (Target_s390::ss_match_l): New helper method.
+ (Target_s390::ss_match_ahi): New helper method.
+ (Target_s390::ss_match_alfi): New helper method.
+ (Target_s390::ss_match_cr): New helper method.
+ (Target_s390::do_calls_non_split): New method.
+ * testsuite/Makefile.am: Added new tests.
+ * testsuite/split_s390.sh: New test.
+ * testsuite/split_s390_1_a1.s: New test.
+ * testsuite/split_s390_1_a2.s: New test.
+ * testsuite/split_s390_1_e1.s: New test.
+ * testsuite/split_s390_1_e2.s: New test.
+ * testsuite/split_s390_1_e3.s: New test.
+ * testsuite/split_s390_1_e4.s: New test.
+ * testsuite/split_s390_1_n.s: New test.
+ * testsuite/split_s390_1_z1.s: New test.
+ * testsuite/split_s390_1_z2.s: New test.
+ * testsuite/split_s390_1_z3.s: New test.
+ * testsuite/split_s390_1_z4.s: New test.
+ * testsuite/split_s390_2_ns.s: New test.
+ * testsuite/split_s390_2_s.s: New test.
+ * testsuite/split_s390x_1_a1.s: New test.
+ * testsuite/split_s390x_1_a2.s: New test.
+ * testsuite/split_s390x_1_n.s: New test.
+ * testsuite/split_s390x_1_z1.s: New test.
+ * testsuite/split_s390x_1_z2.s: New test.
+ * testsuite/split_s390x_1_z3.s: New test.
+ * testsuite/split_s390x_1_z4.s: New test.
+ * testsuite/split_s390x_2_ns.s: New test.
+ * testsuite/split_s390x_2_s.s: New test.
+
2016-01-01 Alan Modra <amodra@gmail.com>
Update year range in copyright notice of all files.
diff --git a/gold/s390.cc b/gold/s390.cc
index eb92fb7..dcf3833 100644
--- a/gold/s390.cc
+++ b/gold/s390.cc
@@ -402,6 +402,14 @@ class Target_s390 : public Sized_target<size, true>
do_can_check_for_function_pointers() const
{ return true; }
+ // Adjust -fsplit-stack code which calls non-split-stack code.
+ void
+ do_calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset, section_size_type fnsize,
+ const unsigned char* prelocs, size_t reloc_count,
+ unsigned char* view, section_size_type view_size,
+ std::string* from, std::string* to) const;
+
// Return the size of the GOT section.
section_size_type
got_size() const
@@ -687,6 +695,17 @@ class Target_s390 : public Sized_target<size, true>
this->rela_dyn_section(layout));
}
+ // A function for targets to call. Return whether BYTES/LEN matches
+ // VIEW/VIEW_SIZE at OFFSET. Like the one in Target, but takes
+ // an unsigned char * parameter.
+ bool
+ match_view_u(const unsigned char* view, section_size_type view_size,
+ section_offset_type offset, const unsigned char* bytes, size_t len) const
+ {
+ return this->match_view(view, view_size, offset,
+ reinterpret_cast<const char*>(bytes), len);
+ }
+
// Information about this specific target which we pass to the
// general Target structure.
static Target::Target_info s390_info;
@@ -724,6 +743,47 @@ 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_st_r14[];
+ static const unsigned char ss_code_l_r14[];
+ static const unsigned char ss_code_bras_8[];
+ static const unsigned char ss_code_l_basr[];
+ static const unsigned char ss_code_a_basr[];
+ static const unsigned char ss_code_ear[];
+ static const unsigned char ss_code_c[];
+ static const unsigned char ss_code_larl[];
+ static const unsigned char ss_code_brasl[];
+ 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[];
+
+ // Variable code sequence matchers for -fsplit-stack.
+ bool ss_match_mcount(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset) const;
+ bool ss_match_l(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int *guard_reg) const;
+ bool ss_match_ahi(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg,
+ uint32_t *arg) const;
+ bool ss_match_alfi(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg,
+ uint32_t *arg) const;
+ bool ss_match_cr(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg) const;
};
template<>
@@ -4243,6 +4303,595 @@ 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_st_r14[] = {
+ 0x50, 0xe0, 0xf0, 0x04, // st %r14, 4(%r15)
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_st_r14[] = {
+ 0xe3, 0xe0, 0xf0, 0x08, 0x00, 0x24 // stg %r14, 8(%r15)
+};
+
+template<>
+const unsigned char
+Target_s390<32>::ss_code_l_r14[] = {
+ 0x58, 0xe0, 0xf0, 0x04, // l %r14, 4(%r15)
+};
+
+template<>
+const unsigned char
+Target_s390<64>::ss_code_l_r14[] = {
+ 0xe3, 0xe0, 0xf0, 0x08, 0x00, 0x04 // lg %r14, 8(%r15)
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_bras_8[] = {
+ 0xa7, 0x15, 0x00, 0x06, // bras %r1, .+0xc
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_l_basr[] = {
+ 0x58, 0xe0, 0x10, 0x00, // l %r14, 0(%r1)
+ 0x58, 0x10, 0x10, 0x04, // l %r1, 4(%r1)
+ 0x0d, 0xee, // basr %r14, %r14
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_a_basr[] = {
+ 0x18, 0xe1, // lr %r14, %r1
+ 0x5a, 0xe0, 0x10, 0x00, // a %r14, 0(%r1)
+ 0x5a, 0x10, 0x10, 0x04, // a %r1, 4(%r1)
+ 0x0d, 0xee, // basr %r14, %r14
+};
+
+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<int size>
+const unsigned char
+Target_s390<size>::ss_code_larl[] = {
+ 0xc0, 0x10, // larl %r1, ...
+};
+
+template<int size>
+const unsigned char
+Target_s390<size>::ss_code_brasl[] = {
+ 0xc0, 0xe5, // brasl %r14, ...
+};
+
+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
+};
+
+template<int size>
+bool
+Target_s390<size>::ss_match_mcount(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset) const
+{
+ // Match the mcount call sequence.
+ section_offset_type myoff = *offset;
+
+ // First, look for the store instruction saving %r14.
+ if (!this->match_view_u(view, view_size, myoff, ss_code_st_r14,
+ sizeof ss_code_st_r14))
+ return false;
+ myoff += sizeof ss_code_st_r14;
+
+ // Now, param load and the actual call.
+ if (this->match_view_u(view, view_size, myoff, ss_code_larl,
+ sizeof ss_code_larl))
+ {
+ myoff += sizeof ss_code_larl + 4;
+
+ // After larl, expect a brasl.
+ if (!this->match_view_u(view, view_size, myoff, ss_code_brasl,
+ sizeof ss_code_brasl))
+ return false;
+ myoff += sizeof ss_code_brasl + 4;
+ }
+ else if (size == 32 &&
+ this->match_view_u(view, view_size, myoff, ss_code_bras_8,
+ sizeof ss_code_bras_8))
+ {
+ // The bras skips over a block of 8 bytes, loading its address
+ // to %r1.
+ myoff += sizeof ss_code_bras_8 + 8;
+
+ // Now, there are two sequences used for actual load and call,
+ // absolute and PIC.
+ if (this->match_view_u(view, view_size, myoff, ss_code_l_basr,
+ sizeof ss_code_l_basr))
+ myoff += sizeof ss_code_l_basr;
+ else if (this->match_view_u(view, view_size, myoff, ss_code_a_basr,
+ sizeof ss_code_a_basr))
+ myoff += sizeof ss_code_a_basr;
+ else
+ return false;
+ }
+ else
+ return false;
+
+ // Finally, a load bringing %r14 back.
+ if (!this->match_view_u(view, view_size, myoff, ss_code_l_r14,
+ sizeof ss_code_l_r14))
+ return false;
+ myoff += sizeof ss_code_l_r14;
+
+ // Found it.
+ *offset = myoff;
+ return true;
+}
+
+template<>
+bool
+Target_s390<32>::ss_match_l(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int *guard_reg) const
+{
+ // l %guard_reg, 0x20(%r1)
+ if (convert_to_section_size_type(*offset + 4) > view_size
+ || view[*offset] != 0x58
+ || (view[*offset + 1] & 0xf) != 0x0
+ || view[*offset + 2] != 0x10
+ || view[*offset + 3] != 0x20)
+ return false;
+ *offset += 4;
+ *guard_reg = view[*offset + 1] >> 4 & 0xf;
+ return true;
+}
+
+template<>
+bool
+Target_s390<64>::ss_match_l(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int *guard_reg) const
+{
+ // lg %guard_reg, 0x38(%r1)
+ if (convert_to_section_size_type(*offset + 6) > view_size
+ || view[*offset] != 0xe3
+ || (view[*offset + 1] & 0xf) != 0x0
+ || view[*offset + 2] != 0x10
+ || view[*offset + 3] != 0x38
+ || view[*offset + 4] != 0x00
+ || view[*offset + 5] != 0x04)
+ return false;
+ *offset += 6;
+ *guard_reg = view[*offset + 1] >> 4 & 0xf;
+ return true;
+}
+
+template<int size>
+bool
+Target_s390<size>::ss_match_ahi(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg,
+ uint32_t *arg) const
+{
+ int op = size == 32 ? 0xa : 0xb;
+ // a[g]hi %guard_reg, <arg>
+ if (convert_to_section_size_type(*offset + 4) > view_size
+ || view[*offset] != 0xa7
+ || view[*offset + 1] != (guard_reg << 4 | op)
+ // Disallow negative size.
+ || view[*offset + 2] & 0x80)
+ return false;
+ *arg = elfcpp::Swap<16, true>::readval(view + *offset + 2);
+ *offset += 4;
+ return true;
+}
+
+template<int size>
+bool
+Target_s390<size>::ss_match_alfi(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg,
+ uint32_t *arg) const
+{
+ int op = size == 32 ? 0xb : 0xa;
+ // al[g]fi %guard_reg, <arg>
+ if (convert_to_section_size_type(*offset + 6) > view_size
+ || view[*offset] != 0xc2
+ || view[*offset + 1] != (guard_reg << 4 | op))
+ return false;
+ *arg = elfcpp::Swap<32, true>::readval(view + *offset + 2);
+ *offset += 6;
+ return true;
+}
+
+template<>
+bool
+Target_s390<32>::ss_match_cr(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg) const
+{
+ // cr %r15, %guard_reg
+ if (convert_to_section_size_type(*offset + 2) > view_size
+ || view[*offset] != 0x19
+ || view[*offset + 1] != (0xf0 | guard_reg))
+ return false;
+ *offset += 2;
+ return true;
+}
+
+template<>
+bool
+Target_s390<64>::ss_match_cr(unsigned char* view,
+ section_size_type view_size,
+ section_offset_type *offset,
+ int guard_reg) const
+{
+ // cgr %r15, %guard_reg
+ if (convert_to_section_size_type(*offset + 4) > view_size
+ || view[*offset] != 0xb9
+ || view[*offset + 1] != 0x20
+ || view[*offset + 2] != 0x00
+ || view[*offset + 3] != (0xf0 | guard_reg))
+ return false;
+ *offset += 4;
+ return true;
+}
+
+
+// FNOFFSET in section SHNDX in OBJECT is the start of a function
+// compiled with -fsplit-stack. The function calls non-split-stack
+// code. We have to change the function so that it always ensures
+// that it has enough stack space to run some random function.
+
+template<int size>
+void
+Target_s390<size>::do_calls_non_split(Relobj* object, unsigned int shndx,
+ section_offset_type fnoffset,
+ section_size_type,
+ const unsigned char *prelocs,
+ size_t reloc_count,
+ unsigned char* view,
+ section_size_type view_size,
+ std::string*,
+ std::string*) const
+{
+ // true if there's a conditional call to __morestack in the function,
+ // false if there's an unconditional one.
+ bool conditional = false;
+ // Offset of the byte after the compare insn, if conditional.
+ section_offset_type cmpend = 0;
+ // Type and immediate offset of the add instruction that adds frame size
+ // to guard.
+ enum {
+ SS_ADD_NONE,
+ SS_ADD_AHI,
+ SS_ADD_ALFI,
+ } fsadd_type = SS_ADD_NONE;
+ section_offset_type fsadd_offset = 0;
+ uint32_t fsadd_frame_size = 0;
+ // Register used for loading guard. Usually r1, but can also be r0 or r2-r5.
+ int guard_reg;
+ // 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;
+ // And the position of split-stack prologue.
+ section_offset_type ssoffset;
+ // 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 was compiled with -pg, the profiling code may come before
+ // the split-stack prologue. Skip it.
+
+ this->ss_match_mcount(view, view_size, &curoffset);
+ ssoffset = curoffset;
+
+ // If the function starts with a nopr %r15, it's a split-stack-compiled
+ // function that doesn't have a stack frame. Ignore it.
+
+ if (this->match_view_u(view, view_size, curoffset, ss_code_nopmark,
+ sizeof ss_code_nopmark))
+ return;
+
+ // First, figure out if there's a conditional call by looking for the
+ // extract-tp, add, cmp sequence.
+
+ if (this->match_view_u(view, view_size, curoffset, ss_code_ear,
+ sizeof ss_code_ear))
+ {
+ // Found extract-tp, now look for an add and compare.
+ curoffset += sizeof ss_code_ear;
+ conditional = true;
+ if (this->match_view_u(view, view_size, curoffset, ss_code_c,
+ sizeof ss_code_c))
+ {
+ // Found a direct compare of stack pointer with the guard,
+ // we're done here.
+ curoffset += sizeof ss_code_c;
+ }
+ else if (this->ss_match_l(view, view_size, &curoffset, &guard_reg))
+ {
+ // Found a load of guard to register, look for an add and compare.
+ if (this->ss_match_ahi(view, view_size, &curoffset, guard_reg,
+ &fsadd_frame_size))
+ {
+ fsadd_offset = curoffset - 2;
+ fsadd_type = SS_ADD_AHI;
+ }
+ else if (this->ss_match_alfi(view, view_size, &curoffset, guard_reg,
+ &fsadd_frame_size))
+ {
+ fsadd_type = SS_ADD_ALFI;
+ fsadd_offset = curoffset - 4;
+ }
+ else
+ {
+ goto bad;
+ }
+ // Now, there has to be a compare.
+ if (!this->ss_match_cr(view, view_size, &curoffset, guard_reg))
+ goto bad;
+ }
+ else
+ {
+ goto bad;
+ }
+ cmpend = curoffset;
+ }
+
+ // Second, look for the call.
+
+ if (this->match_view_u(view, view_size, curoffset, ss_code_larl,
+ sizeof ss_code_larl))
+ {
+ // Found a zarch-style call: larl + jg
+ curoffset += sizeof ss_code_larl;
+
+ // Find out larl's operand. It should be a local symbol in .rodata
+ // section.
+ const unsigned char *pr = prelocs;
+ for (size_t i = 0; i < reloc_count; ++i, pr += reloc_size)
+ {
+ Reltype reloc(pr);
+ if (static_cast<section_offset_type>(reloc.get_r_offset())
+ == curoffset)
+ {
+ typename elfcpp::Elf_types<size>::Elf_WXword r_info
+ = reloc.get_r_info();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(r_info);
+ unsigned int r_type = elfcpp::elf_r_type<size>(r_info);
+ if (r_type != elfcpp::R_390_PC32DBL)
+ goto bad;
+ if (r_sym >= object->local_symbol_count())
+ goto bad;
+ Sized_relobj_file<size, true> *object_sized =
+ static_cast<Sized_relobj_file<size, true> *>(object);
+ const Symbol_value<size>* sym = object_sized->local_symbol(r_sym);
+ bool param_shndx_ordinary;
+ const unsigned int param_shndx =
+ sym->input_shndx(¶m_shndx_ordinary);
+ if (!param_shndx_ordinary)
+ goto bad;
+ param_offset = sym->input_value() + reloc.get_r_addend() - 2
+ - object->output_section(param_shndx)->address()
+ - object->output_section_offset(param_shndx);
+ param_view = object->get_output_view(param_shndx,
+ ¶m_view_size);
+ break;
+ }
+ }
+
+ if (!param_view)
+ goto bad;
+
+ curoffset += 4;
+
+ // Now, there has to be a jump to __morestack.
+ jump_offset = curoffset;
+
+ if (this->match_view_u(view, view_size, curoffset,
+ conditional ? ss_code_jgl : ss_code_jg,
+ sizeof ss_code_jg))
+ curoffset += sizeof ss_code_jg;
+ else
+ goto bad;
+
+ if (conditional)
+ jump_type = SS_JUMP_JL;
+
+ curoffset += 4;
+ }
+ else if (size == 32)
+ {
+ // There'll be an ESA-style call, possibly with a cond jump first.
+ if (conditional)
+ {
+ if (this->match_view_u(view, view_size, curoffset, ss_code_jl,
+ sizeof ss_code_jl))
+ {
+ // Jump if morestack call needed - we need to follow it.
+ int16_t off;
+ jump_type = SS_JUMP_JL;
+ jump_offset = curoffset;
+ curoffset += sizeof ss_code_jl;
+ if (convert_to_section_size_type(curoffset + 2) > view_size)
+ goto bad;
+ off = elfcpp::Swap<16, true>::readval(view + curoffset);
+ curoffset += off * 2 - sizeof ss_code_jl;
+ }
+ else if (this->match_view_u(view, view_size, curoffset, ss_code_jhe,
+ sizeof ss_code_jhe))
+ {
+ jump_type = SS_JUMP_JHE;
+ // Jump if morestack not needed - skip over it. Bump cmpend,
+ // so that jump is nopped out along with the rest if we need
+ // to make the call unconditional.
+ curoffset += sizeof ss_code_jhe;
+ curoffset += 2;
+ cmpend = curoffset;
+ }
+ else
+ {
+ goto bad;
+ }
+ }
+
+ // Match the basr sequence. There are two variants, depending on
+ // whether the start is 4-aligned or not.
+ if (this->match_view_u(view, view_size, curoffset, ss_code_basr,
+ sizeof ss_code_basr))
+ curoffset += sizeof ss_code_basr;
+ else if (this->match_view_u(view, view_size, curoffset, ss_code_basr_2,
+ sizeof ss_code_basr_2))
+ curoffset += sizeof ss_code_basr_2 + 2;
+ else
+ goto bad;
+
+ // We found the param block.
+ param_offset = curoffset;
+ param_view = view;
+ param_view_size = view_size;
+ }
+ else
+ {
+ goto bad;
+ }
+
+ // Read the frame size.
+ if (convert_to_section_size_type(param_offset + size / 8) > param_view_size)
+ goto bad;
+ frame_size = elfcpp::Swap<size, true>::readval(param_view + param_offset);
+
+ // Sanity check.
+ if (fsadd_type != SS_ADD_NONE && fsadd_frame_size != frame_size)
+ goto bad;
+
+ // Bump the frame size.
+ frame_size += parameters->options().split_stack_adjust_size();
+
+ // Store it to the param block.
+ elfcpp::Swap<size, true>::writeval(param_view + param_offset, frame_size);
+
+ if (!conditional)
+ {
+ // If the call was already unconditional, we're done.
+ }
+ else if (frame_size <= 0xffffffff && fsadd_type == SS_ADD_ALFI)
+ {
+ // Using alfi to add the frame size, and it still fits. Adjust it.
+ elfcpp::Swap_unaligned<32, true>::writeval(view + fsadd_offset,
+ frame_size);
+ }
+ else
+ {
+ // We were either relying on the backoff area, or used ahi to load
+ // frame size. This won't fly, as our new frame size is too large.
+ // Convert the sequence to unconditional by nopping out the comparison,
+ // and rewiring the jump.
+ this->set_view_to_nop(view, view_size, ssoffset, cmpend - ssoffset);
+
+ // If jump type was jhe, we already nopped it out above.
+ if (jump_type == SS_JUMP_JL)
+ {
+ // If jump is jl/jgl, we'll mutate it to j/jg.
+ view[jump_offset+1] = 0xf4;
+ }
+ }
+
+ return;
+
+bad:
+ if (!object->has_no_split_stack())
+ object->error(_("failed to match split-stack sequence at "
+ "section %u offset %0zx"),
+ shndx, static_cast<size_t>(fnoffset));
+}
+
// Relocate section data.
template<int size>
diff --git a/gold/testsuite/Makefile.am b/gold/testsuite/Makefile.am
index c8e5f9f..7cc7a2d 100644
--- a/gold/testsuite/Makefile.am
+++ b/gold/testsuite/Makefile.am
@@ -3362,6 +3362,210 @@ MOSTLYCLEANFILES += arm_farcall_thumb_arm arm_farcall_thumb_arm_5t
endif DEFAULT_TARGET_ARM
+if DEFAULT_TARGET_S390
+
+check_SCRIPTS += split_s390.sh
+check_DATA += split_s390_e1.stdout split_s390_e2.stdout \
+ split_s390_e3.stdout split_s390_e4.stdout split_s390_z1.stdout \
+ split_s390_z2.stdout split_s390_z3.stdout split_s390_z4.stdout \
+ split_s390_n.stdout split_s390_a1.stdout split_s390_a2.stdout \
+ split_s390_e1_ns.stdout split_s390_e2_ns.stdout \
+ split_s390_e3_ns.stdout split_s390_e4_ns.stdout \
+ split_s390_z1_ns.stdout split_s390_z2_ns.stdout \
+ split_s390_z3_ns.stdout split_s390_z4_ns.stdout \
+ split_s390_n_ns.stdout split_s390_r.stdout \
+ split_s390x_z1.stdout split_s390x_z2.stdout split_s390x_z3.stdout \
+ split_s390x_z4.stdout split_s390x_n.stdout split_s390x_a1.stdout \
+ split_s390x_a2.stdout split_s390x_z1_ns.stdout \
+ split_s390x_z2_ns.stdout split_s390x_z3_ns.stdout \
+ split_s390x_z4_ns.stdout split_s390x_n_ns.stdout \
+ split_s390x_r.stdout
+SPLIT_DEFSYMS = --defsym __morestack=0x100 --defsym __morestack_non_split=0x200
+split_s390_1_e1.o: split_s390_1_e1.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_e2.o: split_s390_1_e2.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_e3.o: split_s390_1_e3.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_e4.o: split_s390_1_e4.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_z1.o: split_s390_1_z1.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_z2.o: split_s390_1_z2.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_z3.o: split_s390_1_z3.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_z4.o: split_s390_1_z4.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_n.o: split_s390_1_n.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_a1.o: split_s390_1_a1.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_1_a2.o: split_s390_1_a2.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_2_s.o: split_s390_2_s.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_2_ns.o: split_s390_2_ns.s
+ $(TEST_AS) -m31 -o $@ $<
+split_s390_e1: split_s390_1_e1.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e1.o split_s390_2_s.o
+split_s390_e1.stdout: split_s390_e1
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e2: split_s390_1_e2.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e2.o split_s390_2_s.o
+split_s390_e2.stdout: split_s390_e2
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e3: split_s390_1_e3.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e3.o split_s390_2_s.o
+split_s390_e3.stdout: split_s390_e3
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e4: split_s390_1_e4.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e4.o split_s390_2_s.o
+split_s390_e4.stdout: split_s390_e4
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_z1: split_s390_1_z1.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z1.o split_s390_2_s.o
+split_s390_z1.stdout: split_s390_z1
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z2: split_s390_1_z2.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z2.o split_s390_2_s.o
+split_s390_z2.stdout: split_s390_z2
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z3: split_s390_1_z3.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z3.o split_s390_2_s.o
+split_s390_z3.stdout: split_s390_z3
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z4: split_s390_1_z4.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z4.o split_s390_2_s.o
+split_s390_z4.stdout: split_s390_z4
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_n: split_s390_1_n.o split_s390_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_n.o split_s390_2_s.o
+split_s390_n.stdout: split_s390_n
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e1_ns: split_s390_1_e1.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e1.o split_s390_2_ns.o
+split_s390_e1_ns.stdout: split_s390_e1_ns
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e2_ns: split_s390_1_e2.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e2.o split_s390_2_ns.o
+split_s390_e2_ns.stdout: split_s390_e2_ns
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e3_ns: split_s390_1_e3.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e3.o split_s390_2_ns.o
+split_s390_e3_ns.stdout: split_s390_e3_ns
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_e4_ns: split_s390_1_e4.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_e4.o split_s390_2_ns.o
+split_s390_e4_ns.stdout: split_s390_e4_ns
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_z1_ns: split_s390_1_z1.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z1.o split_s390_2_ns.o
+split_s390_z1_ns.stdout: split_s390_z1_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z2_ns: split_s390_1_z2.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z2.o split_s390_2_ns.o
+split_s390_z2_ns.stdout: split_s390_z2_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z3_ns: split_s390_1_z3.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z3.o split_s390_2_ns.o
+split_s390_z3_ns.stdout: split_s390_z3_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_z4_ns: split_s390_1_z4.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_z4.o split_s390_2_ns.o
+split_s390_z4_ns.stdout: split_s390_z4_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390_n_ns: split_s390_1_n.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_n.o split_s390_2_ns.o
+split_s390_n_ns.stdout: split_s390_n_ns
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_a1.stdout: split_s390_1_a1.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o split_s390_a1 split_s390_1_a1.o split_s390_2_ns.o > $@ 2>&1 || exit 0
+split_s390_a2: split_s390_1_a2.o split_s390_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390_1_a2.o split_s390_2_ns.o
+split_s390_a2.stdout: split_s390_a2
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390_r.stdout: split_s390_1_z1.o split_s390_2_ns.o ../ld-new
+ ../ld-new -r split_s390_1_z1.o split_s390_2_ns.o -o split_s390_r > $@ 2>&1 || exit 0
+split_s390x_1_z1.o: split_s390x_1_z1.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_1_z2.o: split_s390x_1_z2.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_1_z3.o: split_s390x_1_z3.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_1_z4.o: split_s390x_1_z4.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_1_n.o: split_s390x_1_n.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_1_a1.o: split_s390x_1_a1.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_1_a2.o: split_s390x_1_a2.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_2_s.o: split_s390x_2_s.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_2_ns.o: split_s390x_2_ns.s
+ $(TEST_AS) -m64 -o $@ $<
+split_s390x_z1: split_s390x_1_z1.o split_s390x_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z1.o split_s390x_2_s.o
+split_s390x_z1.stdout: split_s390x_z1
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z2: split_s390x_1_z2.o split_s390x_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z2.o split_s390x_2_s.o
+split_s390x_z2.stdout: split_s390x_z2
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z3: split_s390x_1_z3.o split_s390x_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z3.o split_s390x_2_s.o
+split_s390x_z3.stdout: split_s390x_z3
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z4: split_s390x_1_z4.o split_s390x_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z4.o split_s390x_2_s.o
+split_s390x_z4.stdout: split_s390x_z4
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_n: split_s390x_1_n.o split_s390x_2_s.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_n.o split_s390x_2_s.o
+split_s390x_n.stdout: split_s390x_n
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390x_z1_ns: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z1.o split_s390x_2_ns.o
+split_s390x_z1_ns.stdout: split_s390x_z1_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z2_ns: split_s390x_1_z2.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z2.o split_s390x_2_ns.o
+split_s390x_z2_ns.stdout: split_s390x_z2_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z3_ns: split_s390x_1_z3.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z3.o split_s390x_2_ns.o
+split_s390x_z3_ns.stdout: split_s390x_z3_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_z4_ns: split_s390x_1_z4.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_z4.o split_s390x_2_ns.o
+split_s390x_z4_ns.stdout: split_s390x_z4_ns
+ $(TEST_OBJDUMP) -j .rodata -j .text -D $< > $@
+split_s390x_n_ns: split_s390x_1_n.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_n.o split_s390x_2_ns.o
+split_s390x_n_ns.stdout: split_s390x_n_ns
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390x_a1.stdout: split_s390x_1_a1.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o split_s390x_a1 split_s390x_1_a1.o split_s390x_2_ns.o > $@ 2>&1 || exit 0
+split_s390x_a2: split_s390x_1_a2.o split_s390x_2_ns.o ../ld-new
+ ../ld-new $(SPLIT_DEFSYMS) -o $@ split_s390x_1_a2.o split_s390x_2_ns.o
+split_s390x_a2.stdout: split_s390x_a2
+ $(TEST_OBJDUMP) -d $< > $@
+split_s390x_r.stdout: split_s390x_1_z1.o split_s390x_2_ns.o ../ld-new
+ ../ld-new -r split_s390x_1_z1.o split_s390x_2_ns.o -o split_s390x_r > $@ 2>&1 || exit 0
+MOSTLYCLEANFILES += split_s390_1_e1 split_s390_1_e2 split_s390_1_e3 \
+ split_s390_1_e4 split_s390_1_z1 split_s390_1_z2 split_s390_1_z3 \
+ split_s390_1_z4 split_s390_1_n split_s390_1_a1 split_s390_1_a2 \
+ split_s390_1_e1_ns split_s390_1_e2_ns split_s390_1_e3_ns \
+ split_s390_1_e4_ns split_s390_1_z1_ns split_s390_1_z2_ns \
+ split_s390_1_z3_ns split_s390_1_z4_ns split_s390_1_n_ns \
+ split_s390_r split_s390x_1_z1 split_s390x_1_z2 split_s390x_1_z3 \
+ split_s390x_1_z4 split_s390x_1_n split_s390x_1_a1 split_s390x_1_a2 \
+ split_s390x_1_z1_ns split_s390x_1_z2_ns split_s390x_1_z3_ns \
+ split_s390x_1_z4_ns split_s390x_1_n_ns split_s390x_r
+
+endif DEFAULT_TARGET_S390
+
endif NATIVE_OR_CROSS_LINKER
# Tests for the dwp tool.
diff --git a/gold/testsuite/split_s390.sh b/gold/testsuite/split_s390.sh
new file mode 100755
index 0000000..96add07
--- /dev/null
+++ b/gold/testsuite/split_s390.sh
@@ -0,0 +1,149 @@
+#!/bin/sh
+
+# split_s390.sh -- test -fstack-split for s390
+
+# Copyright (C) 2009-2015 Free Software Foundation, Inc.
+# Written by Marcin KoÅcielnicki <koriakin@0x04.net>.
+
+# This file is part of gold.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+match()
+{
+ if ! egrep "$1" "$2" >/dev/null 2>&1; then
+ echo 1>&2 "could not find '$1' in $2"
+ exit 1
+ fi
+}
+
+nomatch()
+{
+ if egrep "$1" "$2" >/dev/null 2>&1; then
+ echo 1>&2 "found unexpected '$1' in $2"
+ exit 1
+ fi
+}
+
+match 'basr.*%r1,%r0$' split_s390_e1.stdout
+match 'long.*0x00100000$' split_s390_e1.stdout
+match 'basr.*%r1,%r0$' split_s390_e1_ns.stdout
+match 'long.*0x00104000$' split_s390_e1_ns.stdout
+
+match 'ear.*$' split_s390_e2.stdout
+match 'jhe.*$' split_s390_e2.stdout
+match 'basr.*%r1,%r0$' split_s390_e2.stdout
+match 'long.*0x00000100$' split_s390_e2.stdout
+nomatch 'ear.*$' split_s390_e2_ns.stdout
+nomatch 'jhe.*$' split_s390_e2_ns.stdout
+match 'basr.*%r1,%r0$' split_s390_e2_ns.stdout
+match 'long.*0x00004100$' split_s390_e2_ns.stdout
+
+match 'ear.*$' split_s390_e3.stdout
+match 'jl.*$' split_s390_e3.stdout
+nomatch 'j .*$' split_s390_e3.stdout
+match 'basr.*%r1,%r0$' split_s390_e3.stdout
+match 'long.*0x00000100$' split_s390_e3.stdout
+nomatch 'ear.*$' split_s390_e3_ns.stdout
+nomatch 'jl.*$' split_s390_e3_ns.stdout
+match 'j .*$' split_s390_e3_ns.stdout
+match 'basr.*%r1,%r0$' split_s390_e3_ns.stdout
+match 'long.*0x00004100$' split_s390_e3_ns.stdout
+
+match 'ear.*$' split_s390_e4.stdout
+match 'jl.*$' split_s390_e4.stdout
+nomatch 'j .*$' split_s390_e4.stdout
+match 'basr.*%r1,%r0$' split_s390_e4.stdout
+match 'long.*0x00001000$' split_s390_e4.stdout
+nomatch 'ear.*$' split_s390_e4_ns.stdout
+nomatch 'jl.*$' split_s390_e4_ns.stdout
+match 'j .*$' split_s390_e4_ns.stdout
+match 'basr.*%r1,%r0$' split_s390_e4_ns.stdout
+match 'long.*0x00005000$' split_s390_e4_ns.stdout
+
+match 'jg.*__morestack>?$' split_s390_z1.stdout
+match 'long.*0x00100000$' split_s390_z1.stdout
+match 'jg.*__morestack>?$' split_s390_z1_ns.stdout
+match 'long.*0x00104000$' split_s390_z1_ns.stdout
+
+match 'ear.*$' split_s390_z2.stdout
+match 'jgl.*__morestack>?$' split_s390_z2.stdout
+nomatch 'jg .*__morestack>?$' split_s390_z2.stdout
+match 'long.*0x00000100$' split_s390_z2.stdout
+nomatch 'ear.*$' split_s390_z2_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390_z2_ns.stdout
+match 'jg .*__morestack>?$' split_s390_z2_ns.stdout
+match 'long.*0x00004100$' split_s390_z2_ns.stdout
+
+match 'ear.*$' split_s390_z3.stdout
+match 'jgl.*__morestack>?$' split_s390_z3.stdout
+nomatch 'jg .*__morestack>?$' split_s390_z3.stdout
+match 'long.*0x00001000$' split_s390_z3.stdout
+nomatch 'ear.*$' split_s390_z3_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390_z3_ns.stdout
+match 'jg .*__morestack>?$' split_s390_z3_ns.stdout
+match 'long.*0x00005000$' split_s390_z3_ns.stdout
+
+match 'alfi.*%r1,1048576$' split_s390_z4.stdout
+match 'jgl.*__morestack>?$' split_s390_z4.stdout
+match 'long.*0x00100000$' split_s390_z4.stdout
+match 'alfi.*%r1,1064960$' split_s390_z4_ns.stdout
+match 'jgl.*__morestack>?$' split_s390_z4_ns.stdout
+match 'long.*0x00104000$' split_s390_z4_ns.stdout
+
+match 'jg.*__morestack>?$' split_s390x_z1.stdout
+match 'long.*0x00100000$' split_s390x_z1.stdout
+match 'jg.*__morestack>?$' split_s390x_z1_ns.stdout
+match 'long.*0x00104000$' split_s390x_z1_ns.stdout
+
+match 'ear.*$' split_s390x_z2.stdout
+match 'jgl.*__morestack>?$' split_s390x_z2.stdout
+nomatch 'jg .*__morestack>?$' split_s390x_z2.stdout
+match 'long.*0x00000100$' split_s390x_z2.stdout
+nomatch 'ear.*$' split_s390x_z2_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390x_z2_ns.stdout
+match 'jg .*__morestack>?$' split_s390x_z2_ns.stdout
+match 'long.*0x00004100$' split_s390x_z2_ns.stdout
+
+match 'ear.*$' split_s390x_z3.stdout
+match 'jgl.*__morestack>?$' split_s390x_z3.stdout
+nomatch 'jg .*__morestack>?$' split_s390x_z3.stdout
+match 'long.*0x00001000$' split_s390x_z3.stdout
+nomatch 'ear.*$' split_s390x_z3_ns.stdout
+nomatch 'jgl.*__morestack>?$' split_s390x_z3_ns.stdout
+match 'jg .*__morestack>?$' split_s390x_z3_ns.stdout
+match 'long.*0x00005000$' split_s390x_z3_ns.stdout
+
+match 'algfi.*%r1,1048576$' split_s390x_z4.stdout
+match 'jgl.*__morestack>?$' split_s390x_z4.stdout
+match 'long.*0x00100000$' split_s390x_z4.stdout
+match 'algfi.*%r1,1064960$' split_s390x_z4_ns.stdout
+match 'jgl.*__morestack>?$' split_s390x_z4_ns.stdout
+match 'long.*0x00104000$' split_s390x_z4_ns.stdout
+
+match 'nopr.*r15$' split_s390_n.stdout
+match 'nopr.*r15$' split_s390_n_ns.stdout
+match 'nopr.*r15$' split_s390x_n.stdout
+match 'nopr.*r15$' split_s390x_n_ns.stdout
+
+match 'failed to match' split_s390_a1.stdout
+match 'failed to match' split_s390x_a1.stdout
+
+match 'bas.*$' split_s390_a2.stdout
+match 'brasl.*__morestack>?$' split_s390x_a2.stdout
+
+match 'cannot mix' split_s390_r.stdout
+match 'cannot mix' split_s390x_r.stdout
diff --git a/gold/testsuite/split_s390_1_a1.s b/gold/testsuite/split_s390_1_a1.s
new file mode 100644
index 0000000..86c1997
--- /dev/null
+++ b/gold/testsuite/split_s390_1_a1.s
@@ -0,0 +1,36 @@
+# split_s390_1_a1.s: s390 specific, adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ basr %r13, %r0
+.L1:
+ l %r1, .L2-.L1(%r13)
+ bas %r14, 0(%r13, %r1)
+ l %r1, .L3-.L1(%r13)
+ bas %r14, 0(%r13, %r1)
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .align 4
+.L2:
+ .long __morestack-.L1
+.L3:
+ .long fn2-.L1
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_a2.s b/gold/testsuite/split_s390_1_a2.s
new file mode 100644
index 0000000..026752f
--- /dev/null
+++ b/gold/testsuite/split_s390_1_a2.s
@@ -0,0 +1,37 @@
+# split_s390_1_a2.s: s390 specific, permitted adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ basr %r13, %r0
+.L1:
+ l %r1, .L2-.L1(%r13)
+ bas %r14, 0(%r13, %r1)
+ l %r1, .L3-.L1(%r13)
+ bas %r14, 0(%r13, %r1)
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .align 4
+.L2:
+ .long __morestack-.L1
+.L3:
+ .long fn2-.L1
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
+ .section .note.GNU-no-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e1.s b/gold/testsuite/split_s390_1_e1.s
new file mode 100644
index 0000000..354dc91
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e1.s
@@ -0,0 +1,45 @@
+# split_s390_e1.s: s390 specific test case for -fsplit-stack -
+# esa mode, unconditional call.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ basr %r1, %r0
+.L1:
+ a %r1, .L2-.L1(%r1)
+ basr %r1, %r1
+ .align 4
+.L3:
+ .long 0x100000
+ .long 0
+ .long .L4-.L3
+.L2:
+ .long __morestack-.L1
+.L4:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ basr %r13, %r0
+.L5:
+ l %r1, .L6-.L5(%r13)
+ bas %r14, 0(%r13, %r1)
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .align 4
+.L6:
+ .long fn2-.L5
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e2.s b/gold/testsuite/split_s390_1_e2.s
new file mode 100644
index 0000000..af802fa
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e2.s
@@ -0,0 +1,48 @@
+# split_s390_e2.s: s390 specific test case for -fsplit-stack -
+# esa mode, jhe conditional call, no add.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ c %r15, 0x20(%r1)
+ jhe .L4
+ basr %r1, %r0
+.L1:
+ a %r1, .L2-.L1(%r1)
+ basr %r1, %r1
+ .align 4
+.L3:
+ .long 0x100
+ .long 0
+ .long .L4-.L3
+.L2:
+ .long __morestack-.L1
+.L4:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ basr %r13, %r0
+.L5:
+ l %r1, .L6-.L5(%r13)
+ bas %r14, 0(%r13, %r1)
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .align 4
+.L6:
+ .long fn2-.L5
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e3.s b/gold/testsuite/split_s390_1_e3.s
new file mode 100644
index 0000000..107419b
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e3.s
@@ -0,0 +1,49 @@
+# split_s390_e3.s: s390 specific test case for -fsplit-stack -
+# esa mode, jl conditional call, no add.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ c %r15, 0x20(%r1)
+ jl .L7
+.L4:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ basr %r13, %r0
+.L5:
+ l %r1, .L6-.L5(%r13)
+ bas %r14, 0(%r13, %r1)
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .align 4
+.L6:
+ .long fn2-.L5
+.L7:
+ basr %r1, %r0
+.L1:
+ a %r1, .L2-.L1(%r1)
+ basr %r1, %r1
+ .align 4
+.L3:
+ .long 0x100
+ .long 0
+ .long .L4-.L3
+.L2:
+ .long __morestack-.L1
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_e4.s b/gold/testsuite/split_s390_1_e4.s
new file mode 100644
index 0000000..0687682
--- /dev/null
+++ b/gold/testsuite/split_s390_1_e4.s
@@ -0,0 +1,51 @@
+# split_s390_e4.s: s390 specific test case for -fsplit-stack -
+# esa mode, jl conditional call, ahi.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ l %r1, 0x20(%r1)
+ ahi %r1, 0x1000
+ cr %r15, %r1
+ jl .L7
+.L4:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ basr %r13, %r0
+.L5:
+ l %r1, .L6-.L5(%r13)
+ bas %r14, 0(%r13, %r1)
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .align 4
+.L6:
+ .long fn2-.L5
+.L7:
+ basr %r1, %r0
+.L1:
+ a %r1, .L2-.L1(%r1)
+ basr %r1, %r1
+ .align 4
+.L3:
+ .long 0x1000
+ .long 0
+ .long .L4-.L3
+.L2:
+ .long __morestack-.L1
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_n.s b/gold/testsuite/split_s390_1_n.s
new file mode 100644
index 0000000..ca91262
--- /dev/null
+++ b/gold/testsuite/split_s390_1_n.s
@@ -0,0 +1,18 @@
+# split_s390_n.s: s390 specific test case for -fsplit-stack -
+# no stack frame
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ nopr %r15
+ larl %r2, fn2
+ br %r14
+ .cfi_endproc
+
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_z1.s b/gold/testsuite/split_s390_1_z1.s
new file mode 100644
index 0000000..42adf55
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z1.s
@@ -0,0 +1,37 @@
+# split_s390_z3.s: s390 specific test case for -fsplit-stack -
+# zarch mode, unconditional call
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ larl %r1, .L1
+ jg __morestack
+ .section .rodata
+ .align 4
+.L1:
+ .long 0x100000
+ .long 0
+ .long .L2-.L1
+ .previous
+.L2:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ brasl %r14, fn2
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_z2.s b/gold/testsuite/split_s390_1_z2.s
new file mode 100644
index 0000000..2717a83
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z2.s
@@ -0,0 +1,40 @@
+# split_s390_z2.s: s390 specific test case for -fsplit-stack -
+# zarch mode, conditional call, no add
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ c %r15, 0x20(%r1)
+ larl %r1, .L1
+ jgl __morestack
+ .section .rodata
+ .align 4
+.L1:
+ .long 0x100
+ .long 0
+ .long .L2-.L1
+ .previous
+.L2:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ brasl %r14, fn2
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
+
diff --git a/gold/testsuite/split_s390_1_z3.s b/gold/testsuite/split_s390_1_z3.s
new file mode 100644
index 0000000..8f0cb54
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z3.s
@@ -0,0 +1,41 @@
+# split_s390_z3.s: s390 specific test case for -fsplit-stack -
+# zarch mode, conditional call, ahi.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ l %r1, 0x20(%r1)
+ ahi %r1, 0x1000
+ cr %r15, %r1
+ larl %r1, .L1
+ jgl __morestack
+ .section .rodata
+ .align 4
+.L1:
+ .long 0x1000
+ .long 0
+ .long .L2-.L1
+ .previous
+.L2:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ brasl %r14, fn2
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_1_z4.s b/gold/testsuite/split_s390_1_z4.s
new file mode 100644
index 0000000..b80bf40
--- /dev/null
+++ b/gold/testsuite/split_s390_1_z4.s
@@ -0,0 +1,41 @@
+# split_s390_z4.s: s390 specific test case for -fsplit-stack -
+# zarch mode, conditional call, alfi.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ l %r1, 0x20(%r1)
+ alfi %r1, 0x100000
+ cr %r15, %r1
+ larl %r1, .L1
+ jgl __morestack
+ .section .rodata
+ .align 4
+.L1:
+ .long 0x100000
+ .long 0
+ .long .L2-.L1
+ .previous
+.L2:
+ stm %r13, %r15, 0x34(%r15)
+ .cfi_offset %r13, -0x2c
+ .cfi_offset %r14, -0x28
+ .cfi_offset %r15, -0x24
+ ahi %r15, -0x60
+ .cfi_adjust_cfa_offset 0x60
+ brasl %r14, fn2
+ lm %r13, %r15, 0x94(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0x60
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_2_ns.s b/gold/testsuite/split_s390_2_ns.s
new file mode 100644
index 0000000..fb5a993
--- /dev/null
+++ b/gold/testsuite/split_s390_2_ns.s
@@ -0,0 +1,12 @@
+# split_s390_2_ns.s: s390 specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ br %r14
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/gold/testsuite/split_s390_2_s.s b/gold/testsuite/split_s390_2_s.s
new file mode 100644
index 0000000..3df8009
--- /dev/null
+++ b/gold/testsuite/split_s390_2_s.s
@@ -0,0 +1,13 @@
+# split_s390_2_s.s: s390 specific, -fsplit-stack calling -fsplit-stack
+
+ .text
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ br %r14
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_a1.s b/gold/testsuite/split_s390x_1_a1.s
new file mode 100644
index 0000000..ccc62cb
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_a1.s
@@ -0,0 +1,27 @@
+# split_s390x_1_a1.s: s390x specific, adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ stmg %r13, %r15, 0x68(%r15)
+ .cfi_offset %r13, -0x38
+ .cfi_offset %r14, -0x30
+ .cfi_offset %r15, -0x28
+ aghi %r15, -0xa0
+ .cfi_adjust_cfa_offset 0xa0
+ brasl %r14, __morestack
+ brasl %r14, fn2
+ lmg %r13, %r15, 0x108(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0xa0
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_a2.s b/gold/testsuite/split_s390x_1_a2.s
new file mode 100644
index 0000000..a5c067b
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_a2.s
@@ -0,0 +1,28 @@
+# split_s390x_1_a2.s: s390x specific, permitted adjustment failure
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ stmg %r13, %r15, 0x68(%r15)
+ .cfi_offset %r13, -0x38
+ .cfi_offset %r14, -0x30
+ .cfi_offset %r15, -0x28
+ aghi %r15, -0xa0
+ .cfi_adjust_cfa_offset 0xa0
+ brasl %r14, __morestack
+ brasl %r14, fn2
+ lmg %r13, %r15, 0x108(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0xa0
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
+ .section .note.GNU-no-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_n.s b/gold/testsuite/split_s390x_1_n.s
new file mode 100644
index 0000000..6e434b8
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_n.s
@@ -0,0 +1,17 @@
+# split_s390x_1_n.s: s390x specific test case for -fsplit-stack -
+# no stack frame.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ nopr %r15
+ larl %r2, fn2
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z1.s b/gold/testsuite/split_s390x_1_z1.s
new file mode 100644
index 0000000..4af34cd
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z1.s
@@ -0,0 +1,37 @@
+# split_s390x_1_z1.s: s390x specific test case for -fsplit-stack -
+# unconditional call.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ larl %r1, .L1
+ jg __morestack
+ .section .rodata
+ .align 8
+.L1:
+ .quad 0x100000
+ .quad 0
+ .quad .L2-.L1
+ .previous
+.L2:
+ stmg %r13, %r15, 0x68(%r15)
+ .cfi_offset %r13, -0x38
+ .cfi_offset %r14, -0x30
+ .cfi_offset %r15, -0x28
+ aghi %r15, -0xa0
+ .cfi_adjust_cfa_offset 0xa0
+ brasl %r14, fn2
+ lmg %r13, %r15, 0x108(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0xa0
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z2.s b/gold/testsuite/split_s390x_1_z2.s
new file mode 100644
index 0000000..a184f77
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z2.s
@@ -0,0 +1,41 @@
+# split_s390x_1_z2.s: s390x specific test case for -fsplit-stack -
+# conditional call, no add.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ sllg %r1, %r1, 32
+ ear %r1, %a1
+ cg %r15, 0x38(%r1)
+ larl %r1, .L1
+ jgl __morestack
+ .section .rodata
+ .align 8
+.L1:
+ .quad 0x100
+ .quad 0
+ .quad .L2-.L1
+ .previous
+.L2:
+ stmg %r13, %r15, 0x68(%r15)
+ .cfi_offset %r13, -0x38
+ .cfi_offset %r14, -0x30
+ .cfi_offset %r15, -0x28
+ aghi %r15, -0xa0
+ .cfi_adjust_cfa_offset 0xa0
+ brasl %r14, fn2
+ lmg %r13, %r15, 0x108(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0xa0
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z3.s b/gold/testsuite/split_s390x_1_z3.s
new file mode 100644
index 0000000..b0a4b0b
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z3.s
@@ -0,0 +1,43 @@
+# split_s390x_1_z3.s: s390x specific test case for -fsplit-stack -
+# conditional call, ahi.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ sllg %r1, %r1, 32
+ ear %r1, %a1
+ lg %r1, 0x38(%r1)
+ aghi %r1, 0x1000
+ cgr %r15, %r1
+ larl %r1, .L1
+ jgl __morestack
+ .section .rodata
+ .align 8
+.L1:
+ .quad 0x1000
+ .quad 0
+ .quad .L2-.L1
+ .previous
+.L2:
+ stmg %r13, %r15, 0x68(%r15)
+ .cfi_offset %r13, -0x38
+ .cfi_offset %r14, -0x30
+ .cfi_offset %r15, -0x28
+ aghi %r15, -0xa0
+ .cfi_adjust_cfa_offset 0xa0
+ brasl %r14, fn2
+ lmg %r13, %r15, 0x108(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0xa0
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_1_z4.s b/gold/testsuite/split_s390x_1_z4.s
new file mode 100644
index 0000000..a3b942e
--- /dev/null
+++ b/gold/testsuite/split_s390x_1_z4.s
@@ -0,0 +1,43 @@
+# split_s390x_1_z4.s: s390x specific test case for -fsplit-stack -
+# conditional call, alfi.
+
+ .text
+
+ .global fn1
+ .type fn1,@function
+fn1:
+ .cfi_startproc
+ ear %r1, %a0
+ sllg %r1, %r1, 32
+ ear %r1, %a1
+ lg %r1, 0x38(%r1)
+ algfi %r1, 0x100000
+ cgr %r15, %r1
+ larl %r1, .L1
+ jgl __morestack
+ .section .rodata
+ .align 8
+.L1:
+ .quad 0x100000
+ .quad 0
+ .quad .L2-.L1
+ .previous
+.L2:
+ stmg %r13, %r15, 0x68(%r15)
+ .cfi_offset %r13, -0x38
+ .cfi_offset %r14, -0x30
+ .cfi_offset %r15, -0x28
+ aghi %r15, -0xa0
+ .cfi_adjust_cfa_offset 0xa0
+ brasl %r14, fn2
+ lmg %r13, %r15, 0x108(%r15)
+ .cfi_restore %r13
+ .cfi_restore %r14
+ .cfi_restore %r15
+ .cfi_adjust_cfa_offset -0xa0
+ br %r14
+ .cfi_endproc
+ .size fn1,. - fn1
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_2_ns.s b/gold/testsuite/split_s390x_2_ns.s
new file mode 100644
index 0000000..f073eee
--- /dev/null
+++ b/gold/testsuite/split_s390x_2_ns.s
@@ -0,0 +1,12 @@
+# split_s390x_2_ns.s: s390x specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ br %r14
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
diff --git a/gold/testsuite/split_s390x_2_s.s b/gold/testsuite/split_s390x_2_s.s
new file mode 100644
index 0000000..787d2fe
--- /dev/null
+++ b/gold/testsuite/split_s390x_2_s.s
@@ -0,0 +1,13 @@
+# split_s390x_2_s.s: s390x specific, -fsplit-stack calling non-split
+
+ .text
+
+ .global fn2
+ .type fn2,@function
+fn2:
+ br %r14
+
+ .size fn2,. - fn2
+
+ .section .note.GNU-stack,"",@progbits
+ .section .note.GNU-split-stack,"",@progbits
--
2.6.4