[Committed] s390: Avoid reloc overflows on undefined weak symbols

Message ID 20240227130936.54206-1-krebbel@linux.ibm.com
State Accepted
Headers
Series [Committed] s390: Avoid reloc overflows on undefined weak symbols |

Checks

Context Check Description
snail/binutils-gdb-check success Github commit url

Commit Message

Andreas Krebbel Feb. 27, 2024, 1:09 p.m. UTC
  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
  

Patch

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