[PATCH 18/20] alpha: add IFUNC support to the dynamic linker

Matt Turner mattst88@gmail.com
Wed Aug 12 01:19:55 GMT 2026


Define R_ALPHA_IRELATIVE (42) and teach the dynamic linker to resolve
STT_GNU_IFUNC symbols with it.

elf_machine_rela runs the resolver for R_ALPHA_IRELATIVE and stores what it
returns, and ELF_MACHINE_IRELATIVE turns on the IRELATIVE pass in
elf/do-rel.h.  elf_machine_lazy_rel resolves an IFUNC PLT entry eagerly
rather than deferring it to the trampoline, which has no way to tell an
IFUNC apart from an ordinary lazy binding.

A symbolic reference to an IFUNC needs the same treatment: for
R_ALPHA_GLOB_DAT, R_ALPHA_JMP_SLOT and R_ALPHA_REFQUAD the address the
lookup returns is the resolver, not the implementation it picks, so the
resolver has to run there too, as the other targets do.  Without it every
call through such a symbol enters the resolver and takes the address it
returns as the result of the call.  With multi-arch enabled that is most of
the string functions -- strlen returning an address, memcmp a nonzero
constant for equal buffers, math/test-fenv crashing -- and quietly, since
the values look like plausible integers.

dl-irel.h provides elf_ifunc_invoke and elf_irela for a static binary, where
the C library applies the IRELATIVE relocations itself at startup.
---
 elf/elf.h                  |  1 +
 sysdeps/alpha/dl-irel.h    | 51 ++++++++++++++++++++++++++++++++++++++
 sysdeps/alpha/dl-machine.h | 29 ++++++++++++++++++++++
 3 files changed, 81 insertions(+)
 create mode 100644 sysdeps/alpha/dl-irel.h

diff --git ./elf/elf.h ./elf/elf.h
index b482fcfb64..f93215d8e6 100644
--- ./elf/elf.h
+++ ./elf/elf.h
@@ -2544,6 +2544,7 @@ enum
 #define R_ALPHA_TPRELHI		39
 #define R_ALPHA_TPRELLO		40
 #define R_ALPHA_TPREL16		41
+#define R_ALPHA_IRELATIVE	42
 /* Keep this the last entry.  */
 #define R_ALPHA_NUM		46
 
diff --git ./sysdeps/alpha/dl-irel.h ./sysdeps/alpha/dl-irel.h
new file mode 100644
index 0000000000..bbceaf846c
--- /dev/null
+++ ./sysdeps/alpha/dl-irel.h
@@ -0,0 +1,51 @@
+/* Machine-dependent ELF indirect relocation inline functions.
+   Alpha version.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _DL_IREL_H
+#define _DL_IREL_H
+
+#include <stdio.h>
+#include <unistd.h>
+
+#define ELF_MACHINE_IRELA	1
+
+static inline ElfW(Addr)
+__attribute ((always_inline))
+elf_ifunc_invoke (ElfW(Addr) addr)
+{
+  return ((ElfW(Addr) (*) (void)) (addr)) ();
+}
+
+static inline void
+__attribute ((always_inline))
+elf_irela (const ElfW(Rela) *reloc)
+{
+  ElfW(Addr) *const reloc_addr = (void *) reloc->r_offset;
+  const unsigned long int r_type = ELFW(R_TYPE) (reloc->r_info);
+
+  if (__glibc_likely (r_type == R_ALPHA_IRELATIVE))
+    {
+      ElfW(Addr) value = elf_ifunc_invoke (reloc->r_addend);
+      *reloc_addr = value;
+    }
+  else
+    __libc_fatal ("Unexpected reloc type in static binary.\n");
+}
+
+#endif /* dl-irel.h */
diff --git ./sysdeps/alpha/dl-machine.h ./sysdeps/alpha/dl-machine.h
index 7c500ea850..c357484cf1 100644
--- ./sysdeps/alpha/dl-machine.h
+++ ./sysdeps/alpha/dl-machine.h
@@ -203,6 +203,9 @@ _dl_start_user:							\n\
 /* A reloc type used for ld.so cmdline arg lookups to reject PLT entries.  */
 #define ELF_MACHINE_JMP_SLOT	 R_ALPHA_JMP_SLOT
 
+/* The IRELATIVE relocation for this architecture.  */
+#define ELF_MACHINE_IRELATIVE	 R_ALPHA_IRELATIVE
+
 /* We define an initialization functions.  This is called very early in
  *    _dl_sysdep_start.  */
 #define DL_PLATFORM_INIT dl_platform_init ()
@@ -367,6 +370,16 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
 	  sym_value += SYMBOL_ADDRESS (sym_map, sym, true);
 	}
 
+#ifndef RTLD_BOOTSTRAP
+      /* For an IFUNC symbol the address above is the resolver's; the
+	 address to use is what calling it returns.  */
+      if (sym != NULL
+	  && __glibc_unlikely (ELF64_ST_TYPE (sym->st_info) == STT_GNU_IFUNC)
+	  && __glibc_likely (sym->st_shndx != SHN_UNDEF)
+	  && __glibc_likely (!skip_ifunc))
+	sym_value = ((Elf64_Addr (*) (void)) sym_value) ();
+#endif
+
       if (r_type == R_ALPHA_GLOB_DAT)
 	*reloc_addr = sym_value;
       else if (r_type == R_ALPHA_JMP_SLOT)
@@ -410,6 +423,15 @@ elf_machine_rela (struct link_map *map, struct r_scope_elem *scope[],
 	    }
 # endif
 	}
+#ifndef RTLD_BOOTSTRAP
+      else if (r_type == R_ALPHA_IRELATIVE)
+	{
+	  Elf64_Addr value = map->l_addr + reloc->r_addend;
+	  if (__glibc_likely (!skip_ifunc))
+	    value = ((Elf64_Addr (*) (void)) value) ();
+	  *reloc_addr = value;
+	}
+#endif
       else
 	_dl_reloc_bad_type (map, r_type, 0);
     }
@@ -451,6 +473,13 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
 	 to the .plt.  */
       *reloc_addr += l_addr;
     }
+  else if (r_type == R_ALPHA_IRELATIVE)
+    {
+      Elf64_Addr value = l_addr + reloc->r_addend;
+      if (__glibc_likely (!skip_ifunc))
+	value = ((Elf64_Addr (*) (void)) value) ();
+      *reloc_addr = value;
+    }
   else if (r_type == R_ALPHA_NONE)
     return;
   else
-- 
2.54.0



More information about the Libc-alpha mailing list