diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index 2f35da4a627..f9d9902651b 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -2399,6 +2399,43 @@ elf_s390_relocate_section (bfd *output_bfd, /* We didn't make a PLT entry for this symbol. This happens when statically linking PIC code, or when using -Bsymbolic. */ + + /* Replace relative long addressing instructions of weak + symbols, which will definitely resolve to zero, with + 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 + && !h->root.linker_def + && (bfd_link_executable (info) + || ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) + && r_type == R_390_PLT32DBL + && rel->r_offset >= 2) + { + 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, -> lay rX,0(0) */ + bfd_put_16 (output_bfd, 0xe300 | reg, insn_start); + bfd_put_32 (output_bfd, 0x71, insn_start + 2); + continue; + } + /* Replace branch relative and save long (brasl) with a trap. */ + else if (op == 0xc005) + { + /* brasl rX, -> jg .+2 (6-byte trap) */ + bfd_put_16 (output_bfd, 0xc0f4, insn_start); + bfd_put_32 (output_bfd, 0x1, insn_start + 2); + continue; + } + } + break; } if (s390_is_ifunc_symbol_p (h)) diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp index eb9ea35400b..ac62d7a8a1a 100644 --- a/ld/testsuite/ld-s390/s390.exp +++ b/ld/testsuite/ld-s390/s390.exp @@ -95,9 +95,12 @@ set s390xtests { "-m64" {pltoffset-1.s} {{objdump "-dzrj.text --stop-address=16" pltoffset-1.dd}} "pltoffset-1"} - {"WEAKUNDEF1: overflow test" + {"WEAKUNDEF1: overflow test (PC32DBL)" "-m elf64_s390 -dT 8GB.ld --no-error-rwx-segments" "" "-m64" {weakundef-1.s} {{objdump "-dzrj.text" weakundef-1.dd}} "weakundef-1"} + {"WEAKUNDEF2: overflow test (PLT32DBL)" + "-m elf64_s390 -dT 8GB.ld --no-error-rwx-segments -no-pie" "" "-m64" {weakundef-2.s} + {{objdump "-dzrj.text" weakundef-2.dd}} "weakundef-2"} } if [istarget "s390-*-*"] { diff --git a/ld/testsuite/ld-s390/weakundef-2.dd b/ld/testsuite/ld-s390/weakundef-2.dd new file mode 100644 index 00000000000..e7f0e2239b6 --- /dev/null +++ b/ld/testsuite/ld-s390/weakundef-2.dd @@ -0,0 +1,17 @@ +tmpdir/weakundef-2: file format elf64-s390 + +Disassembly of section .text: + +0+200000000 : +.*: c0 10 00 00 00 12 [ ]*larl %r1,200000024 +.*: c0 10 00 00 00 10 [ ]*larl %r1,200000026 +.*: e3 10 00 00 00 71 [ ]*lay %r1,0 +.*: c0 e5 00 00 00 09 [ ]*brasl %r14,200000024 +.*: c0 e5 00 00 00 07 [ ]*brasl %r14,200000026 +.*: c0 f4 00 00 00 01 [ ]*jg .* + +0+200000024 : +.*: 07 fe [ ]*br %r14 + +0+200000026 : +.*: 07 fe [ ]*br %r14 diff --git a/ld/testsuite/ld-s390/weakundef-2.s b/ld/testsuite/ld-s390/weakundef-2.s new file mode 100644 index 00000000000..d147b53d6dc --- /dev/null +++ b/ld/testsuite/ld-s390/weakundef-2.s @@ -0,0 +1,17 @@ +.text + .globl foo +foo: + larl %r1,d@PLT + larl %r1,wd@PLT + larl %r1,wu@PLT + brasl %r14,d@PLT + brasl %r14,wd@PLT + brasl %r14,wu@PLT + .weak wu + .type d,@function +d: + br %r14 + .weak wd + .type wd,@function +wd: + br %r14