[PATCH 1/4] alpha: add IFUNC (STT_GNU_IFUNC) and R_ALPHA_IRELATIVE support

Matt Turner mattst88@gmail.com
Sun Aug 9 19:23:36 GMT 2026


Define a new R_ALPHA_IRELATIVE relocation (42) for use with GNU
indirect functions (IFUNC) on Alpha.

In the BFD backend (elf64-alpha.c):
- Add HOWTO table entry and BFD_RELOC_IRELATIVE mapping for the new
  relocation.
- Classify R_ALPHA_IRELATIVE as reloc_class_ifunc in
  elf64_alpha_reloc_type_class.
- Recognize STT_GNU_IFUNC in elf64_alpha_want_plt so IFUNC symbols are
  eligible for PLT entries.
- Allow IFUNC symbols to receive PLT entries even when not dynamic in
  elf64_alpha_adjust_dynamic_symbol.
- Emit R_ALPHA_IRELATIVE (with the resolver address as addend) instead
  of R_ALPHA_JMP_SLOT for locally-defined IFUNC symbols in
  elf64_alpha_finish_dynamic_symbol.
- Handle data references (R_ALPHA_REFQUAD) to IFUNC symbols by emitting
  R_ALPHA_IRELATIVE in elf64_alpha_relocate_section.
- Use R_ALPHA_IRELATIVE instead of R_ALPHA_RELATIVE for GOT entries
  that reference local IFUNC symbols.

Remove Alpha from the IFUNC test exclusion list in
ld/testsuite/ld-ifunc/ifunc.exp.
---
 bfd/elf64-alpha.c   | 66 ++++++++++++++++++++++++++++++++++++++-------
 include/elf/alpha.h |  2 ++
 2 files changed, 59 insertions(+), 9 deletions(-)

diff --git ./bfd/elf64-alpha.c ./bfd/elf64-alpha.c
index 10175882d88..6925bdd0a4d 100644
--- ./bfd/elf64-alpha.c
+++ ./bfd/elf64-alpha.c
@@ -1020,6 +1020,21 @@ static reloc_howto_type elf64_alpha_howto_table[] =
 	 0xffff,		/* src_mask */
 	 0xffff,		/* dst_mask */
 	 false),		/* pcrel_offset */
+
+  /* A dynamic relocation for an IFUNC resolver.  */
+  HOWTO (R_ALPHA_IRELATIVE,	/* type */
+	 0,			/* rightshift */
+	 8,			/* size */
+	 64,			/* bitsize */
+	 false,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "IRELATIVE",		/* name */
+	 false,			/* partial_inplace */
+	 0,			/* src_mask */
+	 MINUS_ONE,		/* dst_mask */
+	 false),		/* pcrel_offset */
 };
 
 /* A mapping from BFD reloc types to Alpha ELF reloc types.  */
@@ -1062,6 +1077,7 @@ static const struct elf_reloc_map elf64_alpha_reloc_map[] =
   {BFD_RELOC_ALPHA_TPREL_HI16,		R_ALPHA_TPRELHI},
   {BFD_RELOC_ALPHA_TPREL_LO16,		R_ALPHA_TPRELLO},
   {BFD_RELOC_ALPHA_TPREL16,		R_ALPHA_TPREL16},
+  {BFD_RELOC_IRELATIVE,			R_ALPHA_IRELATIVE},
 };
 
 /* Given a BFD reloc type, return a HOWTO structure.  */
@@ -1733,6 +1749,7 @@ static bool
 elf64_alpha_want_plt (struct alpha_elf_link_hash_entry *ah)
 {
   return ((ah->root.type == STT_FUNC
+	  || ah->root.type == STT_GNU_IFUNC
 	  || ah->root.root.type == bfd_link_hash_undefweak
 	  || ah->root.root.type == bfd_link_hash_undefined)
 	  && (ah->flags & ALPHA_ELF_LINK_HASH_LU_PLT) != 0
@@ -2033,8 +2050,10 @@ elf64_alpha_adjust_dynamic_symbol (struct bfd_link_info *info,
      about whether this symbol should get a .plt entry.  Irritatingly, it
      is common for folk to leave undefined symbols in shared libraries,
      and they still expect lazy binding; accept undefined symbols in lieu
-     of STT_FUNC.  */
-  if (alpha_elf_dynamic_symbol_p (h, info) && elf64_alpha_want_plt (ah))
+     of STT_FUNC.  IFUNC symbols always need a PLT entry for the
+     IRELATIVE resolver mechanism, even when not dynamic.  */
+  if ((alpha_elf_dynamic_symbol_p (h, info) || h->type == STT_GNU_IFUNC)
+      && elf64_alpha_want_plt (ah))
     {
       h->needs_plt = true;
 
@@ -4334,13 +4353,21 @@ elf64_alpha_relocate_section (struct bfd_link_info *info,
 
 	      /* If the symbol has been forced local, output a
 		 RELATIVE reloc, otherwise it will be handled in
-		 finish_dynamic_symbol.  */
+		 finish_dynamic_symbol.  Use IRELATIVE for local
+		 IFUNC symbols.  */
 	      if (bfd_link_pic (info)
 		  && !dynamic_symbol_p
 		  && !undef_weak_ref)
-		elf64_alpha_emit_dynrel (info->output_bfd, info, sgot, srelgot,
-					 gotent->got_offset, 0,
-					 R_ALPHA_RELATIVE, value);
+		{
+		  long r_type_dyn = R_ALPHA_RELATIVE;
+
+		  if (h != NULL && h->root.type == STT_GNU_IFUNC)
+		    r_type_dyn = R_ALPHA_IRELATIVE;
+
+		  elf64_alpha_emit_dynrel (info->output_bfd, info, sgot, srelgot,
+					   gotent->got_offset, 0,
+					   r_type_dyn, value);
+		}
 	    }
 
 	  value = (sgot->output_section->vma
@@ -4500,6 +4527,14 @@ elf64_alpha_relocate_section (struct bfd_link_info *info,
 		dynindx = 0;
 		dynaddend = value - dtp_base;
 	      }
+	    else if (h != NULL
+		     && h->root.type == STT_GNU_IFUNC
+		     && (input_section->flags & SEC_ALLOC))
+	      {
+		dynindx = 0;
+		dyntype = R_ALPHA_IRELATIVE;
+		dynaddend = value;
+	      }
 	    else if (bfd_link_pic (info)
 		     && r_symndx != STN_UNDEF
 		     && (input_section->flags & SEC_ALLOC)
@@ -4772,8 +4807,9 @@ elf64_alpha_finish_dynamic_symbol (struct bfd_link_info *info,
       bfd_vma got_addr, plt_addr;
       bfd_vma plt_index;
       struct alpha_elf_got_entry *gotent;
+      bool is_ifunc = h->type == STT_GNU_IFUNC;
 
-      BFD_ASSERT (h->dynindx != -1);
+      BFD_ASSERT (is_ifunc || h->dynindx != -1);
 
       splt = elf_hash_table (info)->splt;
       BFD_ASSERT (splt != NULL);
@@ -4830,8 +4866,18 @@ elf64_alpha_finish_dynamic_symbol (struct bfd_link_info *info,
 
 	    /* Fill in the entry in the .rela.plt section.  */
 	    outrel.r_offset = got_addr;
-	    outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_JMP_SLOT);
-	    outrel.r_addend = 0;
+	    if (is_ifunc && !alpha_elf_dynamic_symbol_p (h, info))
+	      {
+		outrel.r_info = ELF64_R_INFO (0, R_ALPHA_IRELATIVE);
+		outrel.r_addend = (h->root.u.def.value
+				   + h->root.u.def.section->output_section->vma
+				   + h->root.u.def.section->output_offset);
+	      }
+	    else
+	      {
+		outrel.r_info = ELF64_R_INFO (h->dynindx, R_ALPHA_JMP_SLOT);
+		outrel.r_addend = 0;
+	      }
 
 	    loc = srel->contents + plt_index * sizeof (Elf64_External_Rela);
 	    bfd_elf64_swap_reloca_out (info->output_bfd, &outrel, loc);
@@ -5308,6 +5354,8 @@ elf64_alpha_reloc_type_class (const struct bfd_link_info *info ATTRIBUTE_UNUSED,
       return reloc_class_plt;
     case R_ALPHA_COPY:
       return reloc_class_copy;
+    case R_ALPHA_IRELATIVE:
+      return reloc_class_ifunc;
     default:
       return reloc_class_normal;
     }
diff --git ./include/elf/alpha.h ./include/elf/alpha.h
index 9b7b4cfe16a..f7a0f040508 100644
--- ./include/elf/alpha.h
+++ ./include/elf/alpha.h
@@ -118,6 +118,8 @@ START_RELOC_NUMBERS (elf_alpha_reloc_type)
   RELOC_NUMBER (R_ALPHA_TPRELLO, 40)
   RELOC_NUMBER (R_ALPHA_TPREL16, 41)
 
+  RELOC_NUMBER (R_ALPHA_IRELATIVE, 42)
+
 END_RELOC_NUMBERS (R_ALPHA_max)
 
 #define LITUSE_ALPHA_ADDR	0
-- 
2.54.0



More information about the Binutils mailing list