]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
s390: Avoid reloc overflows on undefined weak symbols
authorAndreas Krebbel <krebbel@linux.ibm.com>
Tue, 27 Feb 2024 13:01:41 +0000 (14:01 +0100)
committerAndreas Krebbel <krebbel@linux.ibm.com>
Tue, 27 Feb 2024 13:07:17 +0000 (14:07 +0100)
Replace relative long addressing instructions of weak symbols, which
will definitely resolve to zero, with 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.

bfd/ChangeLog:

* bfd/elf64-s390.c (elf_s390_relocate_section): Replace
instructions using undefined weak symbols with relative addressing
to avoid relocation overflows.

ld/ChangeLog:
* ld/testsuite/ld-s390/s390.exp:
* ld/testsuite/ld-s390/8GB.ld: New test.
* ld/testsuite/ld-s390/weakundef-1.dd: New test.
* ld/testsuite/ld-s390/weakundef-1.s: New test.

bfd/elf64-s390.c
ld/testsuite/ld-s390/8GB.ld [new file with mode: 0644]
ld/testsuite/ld-s390/s390.exp
ld/testsuite/ld-s390/weakundef-1.dd [new file with mode: 0644]
ld/testsuite/ld-s390/weakundef-1.s [new file with mode: 0644]

index ab9ec3f5b487630542635bc8c224e1dde971c222..74ac0180bf8eb526240a9760b5e87637b72978e5 100644 (file)
@@ -2475,6 +2475,60 @@ elf_s390_relocate_section (bfd *output_bfd,
                            + h->plt.offset);
              goto do_relocation;
            }
+
+         /* Replace relative long addressing instructions of weak
+            symbols, which will definitely resolve to zero, with
+            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
+             && h->root.type == bfd_link_hash_undefweak
+             && !h->root.linker_def
+             && (bfd_link_executable (info)
+                 || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
+             && r_type == R_390_PC32DBL)
+           {
+             void *insn_start = contents + rel->r_offset - 2;
+             uint16_t op = bfd_get_16 (input_bfd, insn_start) & 0xff0f;
+             uint8_t reg = bfd_get_8 (input_bfd, insn_start + 1) & 0xf0;
+
+             /* NOTE: The order of the if's is important!  */
+             /* Replace load address relative long (larl) with load
+                address (lay) */
+             if (op == 0xc000)
+               {
+                 /* larl rX,<weak sym> -> lay rX,0(0)  */
+                 bfd_put_16 (output_bfd, 0xe300 | reg, insn_start);
+                 bfd_put_32 (output_bfd, 0x71, insn_start + 2);
+                 continue;
+               }
+             /* Replace prefetch data relative long (pfdrl) with a NOP  */
+             else if (op == 0xc602)
+               {
+                 /* Emit a 6-byte NOP: jgnop .  */
+                 bfd_put_16 (output_bfd, 0xc004, insn_start);
+                 bfd_put_32 (output_bfd, 0x0, insn_start + 2);
+                 continue;
+               }
+             /* Replace the following instructions with a trap:
+                - branch relative and save long (brasl)
+                - load (logical) relative long (lrl, lgrl, lgfrl, llgfrl)
+                - load (logical) halfword relative long (lhrl, lghrl, llhrl, llghrl)
+                - store relative long (strl, stgrl)
+                - store halfword relative long (sthrl)
+                - execute relative long (exrl)
+                - compare (logical) relative long (crl, clrl, cgrl, clgrl, cgfrl, clgfrl)
+                - compare (logical) halfword relative long (chrl, cghrl, clhrl, clghrl)
+                - branch relative on count high (brcth)  */
+             else if (op == 0xc005 || (op & 0xff00) == 0xc400
+                      || (op & 0xff00) == 0xc600 || op == 0xcc06)
+               {
+                 /* Emit a 6-byte trap: jg .+2  */
+                 bfd_put_16 (output_bfd, 0xc0f4, insn_start);
+                 bfd_put_32 (output_bfd, 0x1, insn_start + 2);
+                 continue;
+               }
+           }
          /* Fall through.  */
 
        case R_390_8:
diff --git a/ld/testsuite/ld-s390/8GB.ld b/ld/testsuite/ld-s390/8GB.ld
new file mode 100644 (file)
index 0000000..7ab94cb
--- /dev/null
@@ -0,0 +1 @@
+SECTIONS { . = 0x200000000; }
index 27bfdeec2751e21e23b93a65c7b6433cfb5c82a1..6b97b6c07d989f9c8429f8e4960568e950e82516 100644 (file)
@@ -85,6 +85,9 @@ set s390xtests {
      "-m64" {pltoffset-1.s}
      {{objdump "-dzrj.text --stop-address=16" pltoffset-1.dd}}
      "pltoffset-1"}
+    {"WEAKUNDEF1: overflow test"
+     "-m elf64_s390 -dT 8GB.ld --no-error-rwx-segments" "" "-m64" {weakundef-1.s}
+     {{objdump "-dzrj.text" weakundef-1.dd}} "weakundef-1"}
 }
 
 if [istarget "s390-*-*"] {
diff --git a/ld/testsuite/ld-s390/weakundef-1.dd b/ld/testsuite/ld-s390/weakundef-1.dd
new file mode 100644 (file)
index 0000000..e514524
--- /dev/null
@@ -0,0 +1,15 @@
+tmpdir/weakundef-1:     file format elf64-s390
+
+Disassembly of section .text:
+
+.* <foo>:
+.*:    c0 10 00 00 00 1e [      ]*larl %r1,20000003c <d>
+.*:    c0 10 00 00 00 1f [      ]*larl %r1,200000044 <wd>
+.*:    e3 10 00 00 00 71 [      ]*lay  %r1,0
+.*:    c0 f4 00 00 00 01 [      ]*jg   .*
+.*:    c0 f4 00 00 00 01 [      ]*jg   .*
+.*:    c0 f4 00 00 00 01 [      ]*jg   .*
+.*:    c0 f4 00 00 00 01 [      ]*jg   .*
+.*:    c0 f4 00 00 00 01 [      ]*jg   .*
+.*:    c0 f4 00 00 00 01 [      ]*jg   .*
+.*:    c0 04 00 00 00 00 [      ]*jgnop        .*
diff --git a/ld/testsuite/ld-s390/weakundef-1.s b/ld/testsuite/ld-s390/weakundef-1.s
new file mode 100644 (file)
index 0000000..aeaef8d
--- /dev/null
@@ -0,0 +1,18 @@
+.text
+       .globl foo
+foo:
+       larl    %r1,d
+       larl    %r1,wd
+       larl    %r1,wu
+       brasl   %r1,wu
+       crl     %r1,wu
+       lrl     %r1,wu
+       strl    %r1,wu
+       exrl    %r1,wu
+       brcth   %r1,wu
+       pfdrl   %r1,wu
+       .weak   wd
+       .weak   wu
+.data
+d:     .quad 0x123
+wd:    .quad 0x123