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.
Committed to mainline. I'll push that also to release branches after
giving it some time in mainline.
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 | 54 +++++++++++++++++++++++++++++
ld/testsuite/ld-s390/8GB.ld | 1 +
ld/testsuite/ld-s390/s390.exp | 3 ++
ld/testsuite/ld-s390/weakundef-1.dd | 15 ++++++++
ld/testsuite/ld-s390/weakundef-1.s | 18 ++++++++++
5 files changed, 91 insertions(+)
create mode 100644 ld/testsuite/ld-s390/8GB.ld
create mode 100644 ld/testsuite/ld-s390/weakundef-1.dd
create mode 100644 ld/testsuite/ld-s390/weakundef-1.s
@@ -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:
new file mode 100644
@@ -0,0 +1 @@
+SECTIONS { . = 0x200000000; }
@@ -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-*-*"] {
new file mode 100644
@@ -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 .*
new file mode 100644
@@ -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