[PATCH 09/11] alpha: diagnose a reference to an IFUNC whose place is deleted

Matt Turner <[email protected]>
Newsgroups gmane.comp.gnu.binutils
Message-ID <[email protected]>
Every entry of .rela.iplt is applied by libc's startup code, so it must
not contain the R_ALPHA_NONE that elf64_alpha_emit_dynrel writes for a
relocation whose place in the output has been removed.

Sizing .rela.iplt skips the sections that do not make it into the
output, but .eh_frame editing deletes the place of a relocation later
still, long after the section has been sized and given an address, so
there is nothing left to shrink it by. Report the reference rather than
write an executable that faults at startup, naming the symbol, the
relocation and the section it was in.

Have final_link count the slots too, as a consistency check on the
sizing: every way to reserve a slot and then not fill it is now
diagnosed where it happens, so a mismatch here means the sizing itself
is wrong. Report both counts, since either can be the larger one.
---
 bfd/elf64-alpha.c                       | 47 +++++++++++++++++++++++++
 ld/testsuite/ld-alpha/ifunc-ehframe-a.s | 19 ++++++++++
 ld/testsuite/ld-alpha/ifunc-ehframe-b.s | 10 ++++++
 ld/testsuite/ld-alpha/ifunc-ehframe.d   |  4 +++
 4 files changed, 80 insertions(+)
 create mode 100644 ld/testsuite/ld-alpha/ifunc-ehframe-a.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-ehframe-b.s
 create mode 100644 ld/testsuite/ld-alpha/ifunc-ehframe.d

diff --git ./bfd/elf64-alpha.c ./bfd/elf64-alpha.c
index 687f4134d0e..09e3778f3a9 100644
--- ./bfd/elf64-alpha.c
+++ ./bfd/elf64-alpha.c
@@ -4904,6 +4904,32 @@ elf64_alpha_relocate_section (struct bfd_link_info *info,
 		  {
 		    srel_out = elf_hash_table (info)->irelplt;
 
+		    /* Every entry of .rela.iplt is applied, so it must not
+		       contain the R_ALPHA_NONE that elf64_alpha_emit_dynrel
+		       writes for a relocation whose place in the output has
+		       been removed.  Sizing .rela.iplt skips the sections that
+		       do not make it into the output, but .eh_frame editing
+		       deletes the place of a relocation later still, long
+		       after the section has been sized and given an address;
+		       there is nothing left to shrink it by.  Report it rather
+		       than produce an executable that faults at startup.  */
+		    if ((_bfd_elf_section_offset (info->output_bfd, info,
+						  input_section, rel->r_offset)
+			 | 1) == (bfd_vma) -1)
+		      {
+			_bfd_error_handler
+			  /* xgettext:c-format */
+			  (_("%pB: cannot resolve STT_GNU_IFUNC symbol `%s': "
+			     "the place of its %s relocation in `%pA' was "
+			     "deleted"),
+			   input_bfd,
+			   elf64_alpha_sym_name (input_bfd, symtab_hdr, h,
+						 sym, sec),
+			   howto->name, input_section);
+			ret_val = false;
+			continue;
+		      }
+
 		    /* Startup code in a static executable applies this after
 		       the kernel has mapped the segment, and unlike the
 		       dynamic linker it cannot make a read-only one writable.
@@ -5466,6 +5492,7 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
   asection *o;
   struct bfd_link_order *p;
   asection *mdebug_sec;
+  asection *irelplt;
   struct ecoff_debug_info debug;
   const struct ecoff_debug_swap *swap
     = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
@@ -5708,6 +5735,26 @@ elf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
   if (! _bfd_elf_final_link (abfd, info))
     return false;
 
+  /* libc's startup code applies every entry between __rela_iplt_start and
+     __rela_iplt_end, so an entry left as R_ALPHA_NONE would fault.  Every
+     way for relocate_section to reserve a slot and then not fill it is
+     diagnosed there, so this is a consistency check on the sizing rather
+     than something a user can provoke.  */
+  irelplt = elf_hash_table (info)->irelplt;
+  if (irelplt != NULL
+      && irelplt->reloc_count * sizeof (Elf64_External_Rela) != irelplt->size)
+    {
+      _bfd_error_handler
+	/* xgettext:c-format */
+	(_("%pB: internal error: %lu .rela.iplt entries were reserved but "
+	   "%lu were written"),
+	 abfd,
+	 (unsigned long) (irelplt->size / sizeof (Elf64_External_Rela)),
+	 (unsigned long) irelplt->reloc_count);
+      bfd_set_error (bfd_error_bad_value);
+      return false;
+    }
+
   /* Now write out the computed sections.  */
 
   /* The .got subsections...  */
diff --git ./ld/testsuite/ld-alpha/ifunc-ehframe-a.s ./ld/testsuite/ld-alpha/ifunc-ehframe-a.s
new file mode 100644
index 00000000000..a4332973069
--- /dev/null
+++ ./ld/testsuite/ld-alpha/ifunc-ehframe-a.s
@@ -0,0 +1,19 @@
+	.text
+
+	# A personality routine named with DW_EH_PE_absptr puts a REFQUAD
+	# against the IFUNC in .eh_frame.  Both objects name the same one, so
+	# their CIEs are identical and .eh_frame editing deletes one of them,
+	# along with the place of the relocation that check_relocs counted.
+	.globl	global_ifunc
+	.type	global_ifunc, @gnu_indirect_function
+global_ifunc:
+	ret
+
+	.globl	_start
+	.ent	_start
+_start:
+	.cfi_startproc
+	.cfi_personality 0x00, global_ifunc
+	ret
+	.cfi_endproc
+	.end	_start
diff --git ./ld/testsuite/ld-alpha/ifunc-ehframe-b.s ./ld/testsuite/ld-alpha/ifunc-ehframe-b.s
new file mode 100644
index 00000000000..801a81bc909
--- /dev/null
+++ ./ld/testsuite/ld-alpha/ifunc-ehframe-b.s
@@ -0,0 +1,10 @@
+	.text
+
+	.globl	other
+	.ent	other
+other:
+	.cfi_startproc
+	.cfi_personality 0x00, global_ifunc
+	ret
+	.cfi_endproc
+	.end	other
diff --git ./ld/testsuite/ld-alpha/ifunc-ehframe.d ./ld/testsuite/ld-alpha/ifunc-ehframe.d
new file mode 100644
index 00000000000..3fa213ab0f3
--- /dev/null
+++ ./ld/testsuite/ld-alpha/ifunc-ehframe.d
@@ -0,0 +1,4 @@
+#source: ifunc-ehframe-a.s
+#source: ifunc-ehframe-b.s
+#ld: -melf64alpha tmpdir/libalphaifunc.so
+#error: \A[^\n]*: cannot resolve STT_GNU_IFUNC symbol `global_ifunc': the place of its REFQUAD relocation in `\.eh_frame' was deleted\n[^\n]*: final link failed[^\n]*\n?\Z
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.