diff options
author | Andreas Krebbel <krebbel@linux.ibm.com> | 2024-02-27 14:01:41 +0100 |
---|---|---|
committer | Andreas Krebbel <krebbel@linux.ibm.com> | 2024-02-27 14:07:17 +0100 |
commit | 896a639babe2d883467978abce7a4c55bc9f00ed (patch) | |
tree | a34555d413cf1725e980564cef66f03bcfda3cfa | |
parent | d6a14e41381d0aa0a99c6796d3bd3677c80dfe06 (diff) | |
download | gdb-896a639babe2d883467978abce7a4c55bc9f00ed.zip gdb-896a639babe2d883467978abce7a4c55bc9f00ed.tar.gz gdb-896a639babe2d883467978abce7a4c55bc9f00ed.tar.bz2 |
s390: Avoid reloc overflows on undefined weak symbols
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.
-rw-r--r-- | bfd/elf64-s390.c | 54 | ||||
-rw-r--r-- | ld/testsuite/ld-s390/8GB.ld | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-s390/s390.exp | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-s390/weakundef-1.dd | 15 | ||||
-rw-r--r-- | ld/testsuite/ld-s390/weakundef-1.s | 18 |
5 files changed, 91 insertions, 0 deletions
diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c index ab9ec3f..74ac018 100644 --- a/bfd/elf64-s390.c +++ b/bfd/elf64-s390.c @@ -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 index 0000000..7ab94cb --- /dev/null +++ b/ld/testsuite/ld-s390/8GB.ld @@ -0,0 +1 @@ +SECTIONS { . = 0x200000000; } diff --git a/ld/testsuite/ld-s390/s390.exp b/ld/testsuite/ld-s390/s390.exp index 27bfdee..6b97b6c 100644 --- a/ld/testsuite/ld-s390/s390.exp +++ b/ld/testsuite/ld-s390/s390.exp @@ -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 index 0000000..e514524 --- /dev/null +++ b/ld/testsuite/ld-s390/weakundef-1.dd @@ -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 index 0000000..aeaef8d --- /dev/null +++ b/ld/testsuite/ld-s390/weakundef-1.s @@ -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 |