[binutils-gdb] s390: Avoid reloc overflows on undefined weak symbols
Andreas Krebbel
krebbel@sourceware.org
Tue Feb 27 13:07:21 GMT 2024
https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=896a639babe2d883467978abce7a4c55bc9f00ed
commit 896a639babe2d883467978abce7a4c55bc9f00ed
Author: Andreas Krebbel <krebbel@linux.ibm.com>
Date: Tue Feb 27 14:01:41 2024 +0100
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.
Diff:
---
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(+)
diff --git a/bfd/elf64-s390.c b/bfd/elf64-s390.c
index ab9ec3f5b48..74ac0180bf8 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 00000000000..7ab94cb3ea5
--- /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 27bfdeec275..6b97b6c07d9 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 00000000000..e5145245602
--- /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 00000000000..aeaef8d2456
--- /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
More information about the Binutils-cvs
mailing list