[binutils-gdb] alpha: diagnose a reference to an IFUNC whose place is deleted

Sam James sjames@sourceware.org
Sat Sep 5 08:35:19 GMT 2026


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=f0759bf55fb3e3330911f920004bfa448f1beb52

commit f0759bf55fb3e3330911f920004bfa448f1beb52
Author: Matt Turner <mattst88@gmail.com>
Date:   Mon Aug 31 22:33:16 2026 -0400

    alpha: diagnose a reference to an IFUNC whose place is deleted
    
    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
    diagnosed where it happens, so a mismatch here means the sizing itself
    is wrong. Report both counts, since either can be the larger one.
    
    sizing: every way to reserve a slot and then not fill it is now

Diff:
---
 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(+)

diff --git a/bfd/elf64-alpha.c b/bfd/elf64-alpha.c
index 687f4134d0e..09e3778f3a9 100644
--- a/bfd/elf64-alpha.c
+++ b/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 a/ld/testsuite/ld-alpha/ifunc-ehframe-a.s b/ld/testsuite/ld-alpha/ifunc-ehframe-a.s
new file mode 100644
index 00000000000..a4332973069
--- /dev/null
+++ b/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 a/ld/testsuite/ld-alpha/ifunc-ehframe-b.s b/ld/testsuite/ld-alpha/ifunc-ehframe-b.s
new file mode 100644
index 00000000000..801a81bc909
--- /dev/null
+++ b/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 a/ld/testsuite/ld-alpha/ifunc-ehframe.d b/ld/testsuite/ld-alpha/ifunc-ehframe.d
new file mode 100644
index 00000000000..3fa213ab0f3
--- /dev/null
+++ b/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


More information about the Binutils-cvs mailing list