]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
s390: Do not rewrite insns and their relocs in linker if --no-relax
authorJens Remus <jremus@linux.ibm.com>
Thu, 16 Oct 2025 09:09:06 +0000 (11:09 +0200)
committerJens Remus <jremus@linux.ibm.com>
Thu, 16 Oct 2025 09:09:06 +0000 (11:09 +0200)
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
bfd/elf64-s390.c
ld/testsuite/ld-s390/gotreloc_31-1b.dd [new file with mode: 0644]
ld/testsuite/ld-s390/gotreloc_31-no-pie-1b.dd [new file with mode: 0644]
ld/testsuite/ld-s390/gotreloc_64-no-pie-1b.dd [new file with mode: 0644]
ld/testsuite/ld-s390/gotreloc_64-norelro-1b.dd [new file with mode: 0644]
ld/testsuite/ld-s390/gotreloc_64-relro-1b.dd [new file with mode: 0644]
ld/testsuite/ld-s390/s390.exp
ld/testsuite/ld-s390/weakundef-1b.d [new file with mode: 0644]
ld/testsuite/ld-s390/weakundef-2b.d [new file with mode: 0644]

index ce3faa023f3373af42dcdf26d0ee77aac88cbaea..0d04663756a0fdabb0fe03c604173790ca3bf21c 100644 (file)
@@ -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,
index af36e192f59da82e0ed3844093c0a6e3117de66a..16daf981e1de7b6d3644d6553c00bdf3d3254715 100644 (file)
@@ -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 (file)
index 0000000..9513e16
--- /dev/null
@@ -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 (file)
index 0000000..5688e47
--- /dev/null
@@ -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 (file)
index 0000000..344701c
--- /dev/null
@@ -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 (file)
index 0000000..2dc84f2
--- /dev/null
@@ -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 (file)
index 0000000..b8f7f20
--- /dev/null
@@ -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
index 8da0032eb803ccbe2bd29f0dbf889e3d8b41b193..eaf74c4c2347d6051305b829b8606e53321f029b 100644 (file)
@@ -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 (file)
index 0000000..3cba83d
--- /dev/null
@@ -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 (file)
index 0000000..b61f49d
--- /dev/null
@@ -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?