[PATCH 2/2] s390: Do not rewrite insns and their relocs in linker if --no-relax

Jens Remus jremus@linux.ibm.com
Wed Oct 15 16:17:31 GMT 2025


Under certain conditions the linker rewrites:
- GOT access using lgrl to larl, changing the GOTENT to a PC32DBL reloc
- GOT access using lg to larl, changing the GOT20 to a PC32DBL reloc
- Relative long addressing instructions of weak symbols, which
  definitively resolve to zero to either (1) load address of zero,
  (2) a NOP, or (3) a trapping instruction, changing the relocation to
  a NONE reloc.

Suppress rewriting of non-TLS instructions and related relocations in
linker if option --no-relax is specified.  This aligns with LLVM linker
behavior on s390.

Like x86-64 do not actually enable the linker relaxation option by
default, as other targets would do using ENABLE_RELAXATION or
TARGET_ENABLE_RELAXATION in their linker emulation scripts.  Instead
perform linker instruction/relocation rewrites by default unless linker
option --no-relax is explicitly specified by the user.  This ensures no
functional change unless --no-relax is used.

bfd/
	* elf64-s390.c (elf_s390_relocate_section): Do not rewrite
	non-TLS instructions and related relocations if --no-relax.
	* elf32-s390.c (elf_s390_relocate_section): Likewise.

ld/testsuite/
	* ld-s390/s390.exp: New tests.  Same as gotreloc_*-1a and
	weakundef-*a, but with linker option --no-relax, to verify
	suppression of linker non-TLS insn and reloc rewrites.
	* ld-s390/gotreloc_31-1b.dd: Likewise.
	* ld-s390/gotreloc_31-no-pie-1b.dd: Likewise.
	* ld-s390/gotreloc_64-no-pie-1b.dd: Likewise.
	* ld-s390/gotreloc_64-norelro-1b.dd: Likewise.
	* ld-s390/gotreloc_64-relro-1b.dd: Likewise.
	* ld-s390/weakundef-1b.d: Likewise.  Check for expected reloc
	overflows.
	* ld-s390/weakundef-2b.d: Likewise.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 bfd/elf32-s390.c                              | 11 ++++++--
 bfd/elf64-s390.c                              | 15 ++++++++--
 ld/testsuite/ld-s390/gotreloc_31-1b.dd        | 20 +++++++++++++
 ld/testsuite/ld-s390/gotreloc_31-no-pie-1b.dd | 20 +++++++++++++
 ld/testsuite/ld-s390/gotreloc_64-no-pie-1b.dd | 19 +++++++++++++
 .../ld-s390/gotreloc_64-norelro-1b.dd         | 19 +++++++++++++
 ld/testsuite/ld-s390/gotreloc_64-relro-1b.dd  | 19 +++++++++++++
 ld/testsuite/ld-s390/s390.exp                 | 28 +++++++++++++++++++
 ld/testsuite/ld-s390/weakundef-1b.d           | 12 ++++++++
 ld/testsuite/ld-s390/weakundef-2b.d           |  7 +++++
 10 files changed, 165 insertions(+), 5 deletions(-)
 create mode 100644 ld/testsuite/ld-s390/gotreloc_31-1b.dd
 create mode 100644 ld/testsuite/ld-s390/gotreloc_31-no-pie-1b.dd
 create mode 100644 ld/testsuite/ld-s390/gotreloc_64-no-pie-1b.dd
 create mode 100644 ld/testsuite/ld-s390/gotreloc_64-norelro-1b.dd
 create mode 100644 ld/testsuite/ld-s390/gotreloc_64-relro-1b.dd
 create mode 100644 ld/testsuite/ld-s390/weakundef-1b.d
 create mode 100644 ld/testsuite/ld-s390/weakundef-2b.d

diff --git a/bfd/elf32-s390.c b/bfd/elf32-s390.c
index ce3faa023f33..0d04663756a0 100644
--- a/bfd/elf32-s390.c
+++ b/bfd/elf32-s390.c
@@ -2059,6 +2059,7 @@ elf_s390_relocate_section (bfd *output_bfd,
       int tls_type;
       asection *base_got = htab->elf.sgot;
       bool resolved_to_zero;
+      bool relax;
 
       r_type = ELF32_R_TYPE (rel->r_info);
       if (r_type == (int) R_390_GNU_VTINHERIT
@@ -2154,6 +2155,11 @@ elf_s390_relocate_section (bfd *output_bfd,
       resolved_to_zero = (h != NULL
 			  && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
 
+      /* Rewrite instructions and related relocations if (1) relaxation
+	 disabled by default, (2) enabled by target, or (3) enabled by
+	 user.  Suppress rewriting if linker option --no-relax is used.  */
+      relax = info->disable_target_specific_optimizations <= 1;
+
       switch (r_type)
 	{
 	case R_390_GOTPLT12:
@@ -2261,8 +2267,9 @@ elf_s390_relocate_section (bfd *output_bfd,
 		      h->got.offset |= 1;
 		    }
 
-		  if ((h->def_regular
-		       && SYMBOL_REFERENCES_LOCAL (info, h))
+		  if (relax
+		      && h->def_regular
+		      && SYMBOL_REFERENCES_LOCAL (info, h)
 		      /* lrl rx,sym@GOTENT -> larl rx, sym */
 		      && ((r_type == R_390_GOTENT
 			   && (bfd_get_16 (input_bfd,
diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
index af36e192f59d..16daf981e1de 100644
--- a/bfd/elf64-s390.c
+++ b/bfd/elf64-s390.c
@@ -2296,6 +2296,7 @@ elf_s390_relocate_section (bfd *output_bfd,
       bfd_reloc_status_type r;
       int tls_type;
       bool resolved_to_zero;
+      bool relax;
 
       r_type = ELF64_R_TYPE (rel->r_info);
       if (r_type == (int) R_390_GNU_VTINHERIT
@@ -2395,6 +2396,11 @@ elf_s390_relocate_section (bfd *output_bfd,
       resolved_to_zero = (h != NULL
 			  && UNDEFWEAK_NO_DYNAMIC_RELOC (info, h));
 
+      /* Rewrite instructions and related relocations if (1) relaxation
+	 disabled by default, (2) enabled by target, or (3) enabled by
+	 user.  Suppress rewriting if linker option --no-relax is used.  */
+      relax = info->disable_target_specific_optimizations <= 1;
+
       switch (r_type)
 	{
 	case R_390_GOTPLT12:
@@ -2517,7 +2523,8 @@ elf_s390_relocate_section (bfd *output_bfd,
 		     reference using larl we have to make sure that
 		     the symbol is 1. properly aligned and 2. it is no
 		     ABS symbol or will become one.  */
-		  if (h->def_regular
+		  if (relax
+		      && h->def_regular
 		      && SYMBOL_REFERENCES_LOCAL (info, h)
 		      /* lgrl rx,sym@GOTENT -> larl rx, sym */
 		      && ((r_type == R_390_GOTENT
@@ -2667,7 +2674,8 @@ elf_s390_relocate_section (bfd *output_bfd,
 		 either a load address of 0 or a trapping insn.
 		 This prevents the PLT32DBL relocation from overflowing in
 		 case the binary will be loaded at 4GB or more.  */
-	      if (h->root.type == bfd_link_hash_undefweak
+	      if (relax
+		  && h->root.type == bfd_link_hash_undefweak
 		  && !h->root.linker_def
 		  && (bfd_link_executable (info)
 		      || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
@@ -2782,7 +2790,8 @@ elf_s390_relocate_section (bfd *output_bfd,
 	     either a load address of 0, a NOP, or a trapping insn.
 	     This prevents the PC32DBL relocation from overflowing in
 	     case the binary will be loaded at 4GB or more.  */
-	  if (h != NULL
+	  if (relax
+	      && h != NULL
 	      && h->root.type == bfd_link_hash_undefweak
 	      && !h->root.linker_def
 	      && (bfd_link_executable (info)
diff --git a/ld/testsuite/ld-s390/gotreloc_31-1b.dd b/ld/testsuite/ld-s390/gotreloc_31-1b.dd
new file mode 100644
index 000000000000..9513e16e113e
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_31-1b.dd
@@ -0,0 +1,20 @@
+
+tmpdir/gotreloc_31-1b:     file format elf32-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:	c4 18 00 00 08 56 [	 ]*lgrl	%r1,11b4 <_GLOBAL_OFFSET_TABLE_\+0x14>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	e3 10 c0 14 00 04 [	 ]*lg	%r1,20\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 1d 00 00 08 50 [	 ]*lrl	%r1,11b4 <_GLOBAL_OFFSET_TABLE_\+0x14>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	58 10 c0 14 [	 ]*l	%r1,20\(%r12\)
+[	 ]*.*: R_390_GOT12	bar
+.*:	e3 10 c0 14 00 58 [	 ]*ly	%r1,20\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 18 00 00 08 46 [	 ]*lgrl	%r1,11b0 <_GLOBAL_OFFSET_TABLE_\+0x10>
+[	 ]*.*: R_390_GOTENT	_GLOBAL_OFFSET_TABLE_\+0x2
+.*:	c4 18 00 00 08 41 [	 ]*lgrl	%r1,11ac <_GLOBAL_OFFSET_TABLE_\+0xc>
+[	 ]*.*: R_390_GOTENT	misaligned_sym\+0x2
diff --git a/ld/testsuite/ld-s390/gotreloc_31-no-pie-1b.dd b/ld/testsuite/ld-s390/gotreloc_31-no-pie-1b.dd
new file mode 100644
index 000000000000..5688e4740b7a
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_31-no-pie-1b.dd
@@ -0,0 +1,20 @@
+
+tmpdir/gotreloc_31-1b:     file format elf32-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:	c4 18 00 00 08 1e [	 ]*lgrl	%r1,4010b0 <_GLOBAL_OFFSET_TABLE_\+0x14>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	e3 10 c0 14 00 04 [	 ]*lg	%r1,20\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 1d 00 00 08 18 [	 ]*lrl	%r1,4010b0 <_GLOBAL_OFFSET_TABLE_\+0x14>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	58 10 c0 14 [	 ]*l	%r1,20\(%r12\)
+[	 ]*.*: R_390_GOT12	bar
+.*:	e3 10 c0 14 00 58 [	 ]*ly	%r1,20\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 18 00 00 08 0e [	 ]*lgrl	%r1,4010ac <_GLOBAL_OFFSET_TABLE_\+0x10>
+[	 ]*.*: R_390_GOTENT	_GLOBAL_OFFSET_TABLE_\+0x2
+.*:	c4 18 00 00 08 09 [	 ]*lgrl	%r1,4010a8 <_GLOBAL_OFFSET_TABLE_\+0xc>
+[	 ]*.*: R_390_GOTENT	misaligned_sym\+0x2
diff --git a/ld/testsuite/ld-s390/gotreloc_64-no-pie-1b.dd b/ld/testsuite/ld-s390/gotreloc_64-no-pie-1b.dd
new file mode 100644
index 000000000000..344701c0ee17
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_64-no-pie-1b.dd
@@ -0,0 +1,19 @@
+tmpdir/gotreloc_64-1b:     file format elf64-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:	c4 18 00 00 08 28 [	 ]*lgrl	%r1,1001100 <_GLOBAL_OFFSET_TABLE_\+0x28>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	e3 10 c0 28 00 04 [	 ]*lg	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 1d 00 00 08 22 [	 ]*lrl	%r1,1001100 <_GLOBAL_OFFSET_TABLE_\+0x28>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	58 10 c0 28 [	 ]*l	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT12	bar
+.*:	e3 10 c0 28 00 58 [	 ]*ly	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 18 00 00 08 16 [	 ]*lgrl	%r1,10010f8 <_GLOBAL_OFFSET_TABLE_\+0x20>
+[	 ]*.*: R_390_GOTENT	_GLOBAL_OFFSET_TABLE_\+0x2
+.*:	c4 18 00 00 08 0f [	 ]*lgrl	%r1,10010f0 <_GLOBAL_OFFSET_TABLE_\+0x18>
+[	 ]*.*: R_390_GOTENT	misaligned_sym\+0x2
diff --git a/ld/testsuite/ld-s390/gotreloc_64-norelro-1b.dd b/ld/testsuite/ld-s390/gotreloc_64-norelro-1b.dd
new file mode 100644
index 000000000000..2dc84f2efc0f
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_64-norelro-1b.dd
@@ -0,0 +1,19 @@
+tmpdir/gotreloc_64-1b:     file format elf64-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:	c4 18 00 00 08 98 [	 ]*lgrl	%r1,12e0 <_GLOBAL_OFFSET_TABLE_\+0x28>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	e3 10 c0 28 00 04 [	 ]*lg	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 1d 00 00 08 92 [	 ]*lrl	%r1,12e0 <_GLOBAL_OFFSET_TABLE_\+0x28>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	58 10 c0 28 [	 ]*l	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT12	bar
+.*:	e3 10 c0 28 00 58 [	 ]*ly	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 18 00 00 08 86 [	 ]*lgrl	%r1,12d8 <_GLOBAL_OFFSET_TABLE_\+0x20>
+[	 ]*.*: R_390_GOTENT	_GLOBAL_OFFSET_TABLE_\+0x2
+.*:	c4 18 00 00 08 7f [	 ]*lgrl	%r1,12d0 <_GLOBAL_OFFSET_TABLE_\+0x18>
+[	 ]*.*: R_390_GOTENT	misaligned_sym\+0x2
diff --git a/ld/testsuite/ld-s390/gotreloc_64-relro-1b.dd b/ld/testsuite/ld-s390/gotreloc_64-relro-1b.dd
new file mode 100644
index 000000000000..b8f7f20da7d2
--- /dev/null
+++ b/ld/testsuite/ld-s390/gotreloc_64-relro-1b.dd
@@ -0,0 +1,19 @@
+tmpdir/gotreloc_64-1b:     file format elf64-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:	c4 18 00 00 0f 08 [	 ]*lgrl	%r1,1ff8 <_GLOBAL_OFFSET_TABLE_\+0x28>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	e3 10 c0 28 00 04 [	 ]*lg	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 1d 00 00 0f 02 [	 ]*lrl	%r1,1ff8 <_GLOBAL_OFFSET_TABLE_\+0x28>
+[	 ]*.*: R_390_GOTENT	bar\+0x2
+.*:	58 10 c0 28 [	 ]*l	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT12	bar
+.*:	e3 10 c0 28 00 58 [	 ]*ly	%r1,40\(%r12\)
+[	 ]*.*: R_390_GOT20	bar
+.*:	c4 18 00 00 0e f6 [	 ]*lgrl	%r1,1ff0 <_GLOBAL_OFFSET_TABLE_\+0x20>
+[	 ]*.*: R_390_GOTENT	_GLOBAL_OFFSET_TABLE_\+0x2
+.*:	c4 18 00 00 0e ef [	 ]*lgrl	%r1,1fe8 <_GLOBAL_OFFSET_TABLE_\+0x18>
+[	 ]*.*: R_390_GOTENT	misaligned_sym\+0x2
diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp
index 8da0032eb803..eaf74c4c2347 100644
--- a/ld/testsuite/ld-s390/s390.exp
+++ b/ld/testsuite/ld-s390/s390.exp
@@ -54,11 +54,21 @@ set s390tests {
      "-m31" {gotreloc-1.s}
      {{objdump -dzrj.text gotreloc_31-1a.dd}}
      "gotreloc_31-1a"}
+    {"GOT: no symbol address load from got to larl (--no-relax)"
+     "-shared -melf_s390 --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs --no-relax" ""
+     "-m31" {gotreloc-1.s}
+     {{objdump -dzrj.text gotreloc_31-1b.dd}}
+     "gotreloc_31-1b"}
     {"GOT: no-pie symbol address load from got to larl"
      "-shared -melf_s390 --no-pie --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs" ""
      "-m31" {gotreloc-1.s}
      {{objdump -dzrj.text gotreloc_31-no-pie-1a.dd}}
      "gotreloc_31-1a"}
+    {"GOT: no no-pie symbol address load from got to larl (--no-relax)"
+     "-shared -melf_s390 --no-pie --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs --no-relax" ""
+     "-m31" {gotreloc-1.s}
+     {{objdump -dzrj.text gotreloc_31-no-pie-1b.dd}}
+     "gotreloc_31-1b"}
     {"Helper shared library (PLT test)"
      "-shared -m elf_s390" "" "-m31" {pltlib.s}
      {}
@@ -92,16 +102,31 @@ set s390xtests {
      "-m64" {gotreloc-1.s}
      {{objdump -dzrj.text gotreloc_64-norelro-1a.dd}}
      "gotreloc_64-1a"}
+    {"GOT: no norelro symbol address load from got (--no-relax)"
+     "-shared -melf64_s390 -z norelro --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs --no-relax" ""
+     "-m64" {gotreloc-1.s}
+     {{objdump -dzrj.text gotreloc_64-norelro-1b.dd}}
+     "gotreloc_64-1b"}
     {"GOT: relro symbol address load from got to larl"
      "-shared -melf64_s390 -z relro --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs" ""
      "-m64" {gotreloc-1.s}
      {{objdump -dzrj.text gotreloc_64-relro-1a.dd}}
      "gotreloc_64-1a"}
+    {"GOT: relro symbol address load from got (--no-relax)"
+     "-shared -melf64_s390 -z relro --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs --no-relax" ""
+     "-m64" {gotreloc-1.s}
+     {{objdump -dzrj.text gotreloc_64-relro-1b.dd}}
+     "gotreloc_64-1b"}
     {"GOT: no-pie symbol address load from got to larl"
      "-shared -melf64_s390 --no-pie --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs" ""
      "-m64" {gotreloc-1.s}
      {{objdump -dzrj.text gotreloc_64-no-pie-1a.dd}}
      "gotreloc_64-1a"}
+    {"GOT: no-pie symbol address load from got (--no-relax)"
+     "-shared -melf64_s390 --no-pie --hash-style=sysv --version-script=gotreloc-1.ver --emit-relocs --no-relax" ""
+     "-m64" {gotreloc-1.s}
+     {{objdump -dzrj.text gotreloc_64-no-pie-1b.dd}}
+     "gotreloc_64-1b"}
     {"PLT: offset test"
      "-shared -m elf64_s390 -dT pltoffset-1.ld --no-error-rwx-segments" ""
      "-m64" {pltoffset-1.s}
@@ -147,6 +172,9 @@ if { [istarget "s390-*-*"] || [istarget "s390x-*-*"] } {
 if [istarget "s390x-*-*"] {
     run_ld_link_tests $s390xtests
 
+    run_dump_test "weakundef-1b"
+    run_dump_test "weakundef-2b"
+
     if { ![skip_sframe_tests] } {
 	run_dump_test "sframe-simple-1"
 	run_dump_test "sframe-plt-1"
diff --git a/ld/testsuite/ld-s390/weakundef-1b.d b/ld/testsuite/ld-s390/weakundef-1b.d
new file mode 100644
index 000000000000..3cba83d45101
--- /dev/null
+++ b/ld/testsuite/ld-s390/weakundef-1b.d
@@ -0,0 +1,12 @@
+#source: weakundef-1.s
+#as: -m64
+#ld: -m elf64_s390 -dT 8GB.ld --emit-relocs --no-error-rwx-segments --no-relax
+#objdump: -dzrj.text
+#error: tmpdir/weakundef-1.o: in function `foo':\n
+#error: \(\.text\+0xe\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x14\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x1a\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x20\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x26\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x2c\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x32\): relocation truncated to fit: R_390_PC32DBL against undefined symbol `wu'\n?
diff --git a/ld/testsuite/ld-s390/weakundef-2b.d b/ld/testsuite/ld-s390/weakundef-2b.d
new file mode 100644
index 000000000000..b61f49dd5127
--- /dev/null
+++ b/ld/testsuite/ld-s390/weakundef-2b.d
@@ -0,0 +1,7 @@
+#source: weakundef-2.s
+#as: -m64
+#ld: -m elf64_s390 -dT 8GB.ld --no-pie --emit-relocs --no-error-rwx-segments --no-relax
+#objdump: -dzrj.text
+#error: tmpdir/weakundef-2.o: in function `foo':\n
+#error: \(\.text\+0xe\): relocation truncated to fit: R_390_PLT32DBL against undefined symbol `wu'\n?
+#error: \(\.text\+0x20\): relocation truncated to fit: R_390_PLT32DBL against undefined symbol `wu'\n?
-- 
2.48.1



More information about the Binutils mailing list