[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