[PATCH v2 1/2] elf: Honour skip_ifunc for cross-object IFUNC relocations [BZ #34428]

Sam James sam@gentoo.org
Sat Aug 8 01:50:51 GMT 2026


Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:

> Commit 63b31c05a8a ("elf: Defer all IRELATIVE relocations until after PLT
> setup") dropped the skip_ifunc argument from elf_dynamic_do_Rel, assuming
> the new deferred elf_dynamic_do_Rel_irelative pass handles every relocation
> that may run an IFUNC resolver.  That only holds for IFUNC symbols defined
> in the object being relocated: a reference to an IFUNC in another object is
> an ordinary JMP_SLOT or GLOB_DAT against an undefined symbol, and its IFUNC
> nature is only known after symbol resolution inside elf_machine_rel.  Those
> relocations stay in the regular pass, which no longer propagated
> skip_ifunc, so __RTLD_NOIFUNC was ignored for them.
>
> ldd -u forces non-lazy binding (GLRO(dl_lazy) = 0 for DL_DEBUG_UNUSED), so
> the resolver was called and the diagnostic emitted:
>
>   $ ldd -u /bin/ls
>   /bin/ls: Relink `' with `/usr/lib64/libc.so.6' for IFUNC symbol `__mempcpy_chk'
>
> ldd -r with LD_BIND_NOW is affected in the same way.
>
> Restore the skip_ifunc parameter and thread it through _ELF_DYNAMIC_DO_RELOC.
>
> This new semantic shows that ELF_DYNAMIC_RELOCATE_NOIFUNC naming is misleading
> (it reads as "do not process IFUNC", yet it takes a skip_ifunc
> argument). Replace it to:
>
>   DL_RELOC_BOTH     -> DL_RELOC_ALL
>   DL_RELOC_NOIFUNC  -> DL_RELOC_NORMAL
>   DL_RELOC_IFUNC    -> DL_RELOC_IRELATIVE
>
> ELF_DYNAMIC_RELOCATE_NOIFUNC and ELF_DYNAMIC_RELOCATE_IFUNC become a single
> ELF_DYNAMIC_RELOCATE_PASS taking the pass as its first argument, and
> ELF_DYNAMIC_DO_REL/ELF_DYNAMIC_DO_RELA take the pass instead of having three
> near-identical variants each.
>
> Checked on x86_64-linux-gnu, and built for all supported architectures.

Sorry for delay, I'd missed v2 was sent. It looks good (only real issue
I had w/ v1 was the name).

Reviewed-by: Sam James <sam@gentoo.org>

> ---
>  elf/Makefile                      |  28 +++++++
>  elf/dl-reloc-static-pie.c         |   4 +-
>  elf/dl-reloc.c                    |   6 +-
>  elf/do-rel.h                      |  24 ++++--
>  elf/dynamic-link.h                | 117 +++++++++++++-----------------
>  elf/tst-ifunc-fault-dep-bindnow.c |  19 +++++
>  elf/tst-ifunc-fault-dep-lazy.c    |  27 +++++++
>  elf/tst-ifunc-fault-mod.c         |  38 ++++++++++
>  8 files changed, 186 insertions(+), 77 deletions(-)
>  create mode 100644 elf/tst-ifunc-fault-dep-bindnow.c
>  create mode 100644 elf/tst-ifunc-fault-dep-lazy.c
>  create mode 100644 elf/tst-ifunc-fault-mod.c
>
> diff --git a/elf/Makefile b/elf/Makefile
> index 94c5b7e6ed8..6cfb1b5cf30 100644
> --- a/elf/Makefile
> +++ b/elf/Makefile
> @@ -1396,6 +1396,13 @@ modules-names += \
>    tst-ifunc-tls-write-lib \
>    tst-tls-tdata-reloc-lib \
>    # modules-names
> +ifeq (yes,$(have-gcc-ifunc))
> +tests += \
> +  tst-ifunc-fault-dep-bindnow \
> +  tst-ifunc-fault-dep-lazy \
> +  # tests
> +modules-names += tst-ifunc-fault-mod
> +endif
>  ifneq (no,$(have-test-mtls-descriptor))
>  tests += tst-ifunc-tls-init-tlsdesc
>  modules-names += tst-ifunc-tls-init-tlsdesc-lib
> @@ -2545,6 +2552,27 @@ $(objpfx)tst-ifunc-fault-bindnow.out: $(objpfx)tst-ifunc-fault-bindnow \
>     $(objpfx)ld.so
>  	$(tst-ifunc-fault-script)
>  
> +LDFLAGS-tst-ifunc-fault-dep-lazy = -Wl,-z,lazy
> +LDFLAGS-tst-ifunc-fault-dep-bindnow = -Wl,-z,now
> +define tst-ifunc-fault-dep-script
> +( $(test-wrapper) $(rtld-prefix) --verify $< \
> +  && $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 $(rtld-prefix) $< \
> +  && $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_DEBUG=unused \
> +			 $(rtld-prefix) $< \
> +  && $(test-wrapper-env) LD_TRACE_LOADED_OBJECTS=1 LD_WARN=yes LD_BIND_NOW=1 \
> +			 $(rtld-prefix) $< \
> +) > $@; $(evaluate-test)
> +endef
> +$(objpfx)tst-ifunc-fault-dep-lazy: $(objpfx)tst-ifunc-fault-mod.so
> +$(objpfx)tst-ifunc-fault-dep-bindnow: $(objpfx)tst-ifunc-fault-mod.so
> +$(objpfx)tst-ifunc-fault-dep-lazy.out: $(objpfx)tst-ifunc-fault-dep-lazy \
> +   $(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
> +	$(tst-ifunc-fault-dep-script)
> +$(objpfx)tst-ifunc-fault-dep-bindnow.out: \
> +   $(objpfx)tst-ifunc-fault-dep-bindnow \
> +   $(objpfx)tst-ifunc-fault-mod.so $(objpfx)ld.so
> +	$(tst-ifunc-fault-dep-script)
> +
>  LDFLAGS-tst-ifunc-plt-lib.so = -Wl,-z,lazy
>  
>  tst-ifunc-plt-bindnow-ENV = LD_BIND_NOW=1
> diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
> index 8463e46147d..5dc5a545a8d 100644
> --- a/elf/dl-reloc-static-pie.c
> +++ b/elf/dl-reloc-static-pie.c
> @@ -80,7 +80,7 @@ _dl_relocate_static_pie (void)
>  
>    /* Relocate ourselves so we can do normal function calls and data access
>       using the global offset table.  IRELATIVE entries are deferred.  */
> -  ELF_DYNAMIC_RELOCATE_NOIFUNC (main_map, NULL, 0, 0);
> +  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, main_map, NULL, 0, 0, 0);
>  
>    /* Initialize _r_debug_extended.  */
>    struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
> @@ -98,7 +98,7 @@ void
>  _dl_relocate_static_pie_ifunc (void)
>  {
>    struct link_map *main_map = _dl_get_dl_main_map ();
> -  ELF_DYNAMIC_RELOCATE_IFUNC (main_map, NULL, 0, 0);
> +  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, main_map, NULL, 0, 0, 0);
>    main_map->l_relocated = 1;
>  }
>  #endif
> diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c
> index 15a6a4cffef..fa2f41ac445 100644
> --- a/elf/dl-reloc.c
> +++ b/elf/dl-reloc.c
> @@ -278,7 +278,8 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
>         IFUNC resolvers.  Without this, a resolver would see the unrelocated
>         initialiser bytes that were placed into the slot by the early
>         _dl_allocate_tls_init.  */
> -    ELF_DYNAMIC_RELOCATE_NOIFUNC (l, scope, lazy, consider_profiling);
> +    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_NORMAL, l, scope, lazy,
> +			       consider_profiling, skip_ifunc);
>  
>  #ifdef SHARED
>      /* Re-initialise the static TLS slot with the .tdata so the IRELATIVE
> @@ -291,7 +292,8 @@ _dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[],
>        _dl_init_static_tls (l);
>  #endif
>  
> -    ELF_DYNAMIC_RELOCATE_IFUNC (l, scope, lazy, skip_ifunc);
> +    ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_IRELATIVE, l, scope, lazy,
> +			       0, skip_ifunc);
>  
>      if ((consider_profiling || consider_symbind)
>  	&& l->l_info[DT_PLTRELSZ] != NULL)
> diff --git a/elf/do-rel.h b/elf/do-rel.h
> index 77022447348..c610d12dbeb 100644
> --- a/elf/do-rel.h
> +++ b/elf/do-rel.h
> @@ -79,17 +79,23 @@ elf_dynamic_Rel_audit_symbind (struct link_map *map,
>  /* Perform the relocations in MAP on the running program image as specified
>     by RELTAG, SZTAG.  If LAZY is nonzero, this is the first pass on PLT
>     relocations; they should be set up to call _dl_runtime_resolve, rather
> -   than fully resolved now.
> +   than fully resolved now.  If SKIP_IFUNC is nonzero no IFUNC resolver is
> +   called; this is required for the trace modes (ldd -u / ldd -r), which
> +   relocate objects.
>  
> -   IRELATIVE entries are always skipped (non-bootstrap); they are handled
> +   IRELATIVE entries and relocations against an STT_GNU_IFUNC symbol defined
> +   in MAP itself are always skipped (non-bootstrap); they are handled
>     separately by elf_dynamic_do_Rel_irelative after all other relocations
> -   for both .rel.dyn and .rel.plt have been processed.  */
> +   for both .rel.dyn and .rel.plt have been processed.  Relocations against
> +   an IFUNC symbol defined in *another* object are not deferred, since the
> +   IFUNC symbol is only known after symbol resolution, and the defining object
> +   has already been relocated at this point.  */
>  
>  static inline void __attribute__ ((always_inline))
>  elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
>  		    ElfW(Addr) reladdr, ElfW(Addr) relsize,
>  		    __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative,
> -		    int lazy)
> +		    int lazy, int skip_ifunc)
>  {
>    const ElfW(Rel) *relative = (const void *) reladdr;
>    const ElfW(Rel) *r = relative + nrelative;
> @@ -111,7 +117,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
>        void *const r_addr_arg = (void *) (l_addr + r->r_offset);
>        const struct r_found_version *rversion = &map->l_versions[ndx];
>  
> -      elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
> +      elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, skip_ifunc);
>      }
>  #else /* !RTLD_BOOTSTRAP */
>  #if !defined DO_RELA || !defined ELF_MACHINE_PLT_REL
> @@ -126,7 +132,7 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
>  	  const ElfW (Sym) *sym = &symtab[ELFW (R_SYM) (r->r_info)];
>  	  if (elf_dynamic_is_Rel_irelative (r, sym))
>  	    continue;
> -	  elf_machine_lazy_rel (map, scope, l_addr, r, 0);
> +	  elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
>  	}
>      }
>    else
> @@ -158,7 +164,8 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
>  
>  	      if (elf_dynamic_is_Rel_irelative (r, sym))
>  		continue;
> -	      elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
> +	      elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg,
> +			       skip_ifunc);
>  	      elf_dynamic_Rel_audit_symbind (map, scope, r, sym, rversion,
>  					     r_addr_arg);
>  	    }
> @@ -172,7 +179,8 @@ elf_dynamic_do_Rel (struct link_map *map, struct r_scope_elem *scope[],
>  
>  	      if (elf_dynamic_is_Rel_irelative (r, sym))
>  		continue;
> -	      elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg, 0);
> +	      elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg,
> +			       skip_ifunc);
>  	      elf_dynamic_Rel_audit_symbind (map, scope, r, sym, NULL,
>  					     r_addr_arg);
>  	    }
> diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h
> index 35141acec4b..0130c63feb1 100644
> --- a/elf/dynamic-link.h
> +++ b/elf/dynamic-link.h
> @@ -78,18 +78,23 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[],
>     consumes precisely the very end of the DT_REL*, or DT_JMPREL and DT_REL*
>     are completely separate and there is a gap between them.  */
>  
> -/* This controls which sub-passes _ELF_DYNAMIC_DO_RELOC runs.  Used to
> -   interleave TLS / stack-protector setup between the two passes so IFUNC
> -   resolvers see a fully-initialised TCB.  */
> -enum elf_dynamic_reloc_phase
> +/* Selects which relocations a pass processes.  Splitting them allows the
> +   caller to interleave TLS / stack-protector setup between the two passes,
> +   so IFUNC resolvers see a fully-initialised TCB.
> +
> +   This is orthogonal to the skip_ifunc argument, which says whether an IFUNC
> +   resolver may be run at all and is honoured by every pass.  In particular
> +   DL_RELOC_NORMAL also runs IFUNC resolvers, for relocations against an
> +   IFUNC symbol defined in another object.  */
> +enum elf_dynamic_reloc_pass
>  {
> -  DL_RELOC_BOTH     = 0,  /* Non-IRELATIVE pass then IRELATIVE pass.  */
> -  DL_RELOC_NOIFUNC  = 1,  /* Non-IRELATIVE pass only.  */
> -  DL_RELOC_IFUNC    = 2,  /* IRELATIVE pass only.  */
> +  DL_RELOC_ALL	     = 0, /* Non-IRELATIVE relocations, then IRELATIVE.  */
> +  DL_RELOC_NORMAL    = 1, /* Non-IRELATIVE relocations only.  */
> +  DL_RELOC_IRELATIVE = 2, /* IRELATIVE relocations only.  */
>  };
>  
>  # define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, \
> -			       test_rel, phase)				      \
> +			       test_rel, pass)				      \
>    do {									      \
>      struct { ElfW(Addr) start, size;					      \
>  	     __typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; }  \
> @@ -136,14 +141,15 @@ enum elf_dynamic_reloc_phase
>  	 by the linker.  */						      \
>        if (!DO_RTLD_BOOTSTRAP)						      \
>  	{								      \
> -	  if ((phase) != DL_RELOC_IFUNC)				      \
> +	  if ((pass) != DL_RELOC_IRELATIVE)				      \
>  	    for (int ranges_index = 0; ranges_index < 2; ++ranges_index)      \
>  	      elf_dynamic_do_##reloc ((map), scope,			      \
>  				      ranges[ranges_index].start,	      \
>  				      ranges[ranges_index].size,	      \
>  				      ranges[ranges_index].nrelative,	      \
> -				      ranges[ranges_index].lazy);	      \
> -	  if ((phase) != DL_RELOC_NOIFUNC)				      \
> +				      ranges[ranges_index].lazy,	      \
> +				      skip_ifunc);			      \
> +	  if ((pass) != DL_RELOC_NORMAL)				      \
>  	    for (int ranges_index = 0; ranges_index < 2; ++ranges_index)      \
>  	      elf_dynamic_do_##reloc##_irelative ((map), scope,		      \
>  						  ranges[ranges_index].start, \
> @@ -158,7 +164,8 @@ enum elf_dynamic_reloc_phase
>  				  ranges[ranges_index].start,		      \
>  				  ranges[ranges_index].size,		      \
>  				  ranges[ranges_index].nrelative,	      \
> -				  ranges[ranges_index].lazy);		      \
> +				  ranges[ranges_index].lazy,		      \
> +				  skip_ifunc);				      \
>    } while (0)
>  
>  # if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
> @@ -169,37 +176,21 @@ enum elf_dynamic_reloc_phase
>  
>  # if ! ELF_MACHINE_NO_REL
>  #  include "do-rel.h"
> -#  define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc)	      \
> +#  define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc, pass)      \
>    _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc,      \
> -			 _ELF_CHECK_REL, DL_RELOC_BOTH)
> -#  define ELF_DYNAMIC_DO_REL_NOIFUNC(map, scope, lazy)		      \
> -  _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, 0,		      \
> -			 _ELF_CHECK_REL, DL_RELOC_NOIFUNC)
> -#  define ELF_DYNAMIC_DO_REL_IFUNCONLY(map, scope, lazy, skip_ifunc)  \
> -  _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc,      \
> -			 _ELF_CHECK_REL, DL_RELOC_IFUNC)
> +			 _ELF_CHECK_REL, pass)
>  # else
> -#  define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) /* Nothing to do.  */
> -#  define ELF_DYNAMIC_DO_REL_NOIFUNC(map, scope, lazy) /* Nothing to do.  */
> -#  define ELF_DYNAMIC_DO_REL_IFUNCONLY(map, scope, lazy, skip_ifunc) /* Nothing.  */
> +#  define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc, pass) /* Nothing.  */
>  # endif
>  
>  # if ! ELF_MACHINE_NO_RELA
>  #  define DO_RELA
>  #  include "do-rel.h"
> -#  define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc)	      \
> +#  define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc, pass)     \
>    _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc,    \
> -			 _ELF_CHECK_REL, DL_RELOC_BOTH)
> -#  define ELF_DYNAMIC_DO_RELA_NOIFUNC(map, scope, lazy)		      \
> -  _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, 0,	      \
> -			 _ELF_CHECK_REL, DL_RELOC_NOIFUNC)
> -#  define ELF_DYNAMIC_DO_RELA_IFUNCONLY(map, scope, lazy, skip_ifunc) \
> -  _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc,    \
> -			 _ELF_CHECK_REL, DL_RELOC_IFUNC)
> +			 _ELF_CHECK_REL, pass)
>  # else
> -#  define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) /* Nothing to do.  */
> -#  define ELF_DYNAMIC_DO_RELA_NOIFUNC(map, scope, lazy) /* Nothing to do.  */
> -#  define ELF_DYNAMIC_DO_RELA_IFUNCONLY(map, scope, lazy, skip_ifunc) /* Nothing.  */
> +#  define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc, pass) /* Nothing.  */
>  # endif
>  
>  # define ELF_DYNAMIC_DO_RELR(map)					      \
> @@ -240,37 +231,33 @@ enum elf_dynamic_reloc_phase
>  # else
>  #  define DO_RTLD_BOOTSTRAP 0
>  # endif
> +/* Perform one relocation pass over MAP.  PASS selects which relocations are
> +   processed.  It is orthogonal to SKIP_IFUNC, which suppresses running IFUNC
> +   resolvers in whichever pass is selected.
> +
> +   Unless PASS is DL_RELOC_IRELATIVE, this also performs the machine-specific
> +   PLT/GOT setup, the DT_RELR relocations, and the ELF_DYNAMIC_AFTER_RELOC
> +   hook.  */
> +# define ELF_DYNAMIC_RELOCATE_PASS(pass, map, scope, lazy, consider_profile,  \
> +				   skip_ifunc)				      \
> +  do {									      \
> +    int edr_lazy = (lazy);						      \
> +    if ((pass) != DL_RELOC_IRELATIVE)					      \
> +      {									      \
> +	edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy),	      \
> +					      (consider_profile));	      \
> +	if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP)		      \
> +	  ELF_DYNAMIC_DO_RELR (map);					      \
> +      }									      \
> +    ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc, (pass));	      \
> +    ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc, (pass));	      \
> +    if ((pass) != DL_RELOC_IRELATIVE)					      \
> +      ELF_DYNAMIC_AFTER_RELOC ((map), edr_lazy);			      \
> +  } while (0)
> +
> +/* Run both passes back to back, for callers with nothing to interleave.  */
>  # define ELF_DYNAMIC_RELOCATE(map, scope, lazy, consider_profile, skip_ifunc) \
> -  do {									      \
> -    int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy),	      \
> -					      (consider_profile));	      \
> -    if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP)			      \
> -      ELF_DYNAMIC_DO_RELR (map);					      \
> -    ELF_DYNAMIC_DO_REL ((map), (scope), edr_lazy, skip_ifunc);		      \
> -    ELF_DYNAMIC_DO_RELA ((map), (scope), edr_lazy, skip_ifunc);		      \
> -    ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy));			      \
> -  } while (0)
> -
> -/* Like ELF_DYNAMIC_RELOCATE but only processes the non-IRELATIVE pass.
> -   The IRELATIVE pass must be completed later via ELF_DYNAMIC_RELOCATE_IFUNC.
> -   Used by the static-pie startup so the TCB and stack-protector canary can
> -   be initialised between the two passes.  */
> -# define ELF_DYNAMIC_RELOCATE_NOIFUNC(map, scope, lazy, consider_profile)     \
> -  do {									      \
> -    int edr_lazy = elf_machine_runtime_setup ((map), (scope), (lazy),	      \
> -					      (consider_profile));	      \
> -    if (!is_rtld_link_map (map) || DO_RTLD_BOOTSTRAP)			      \
> -      ELF_DYNAMIC_DO_RELR (map);					      \
> -    ELF_DYNAMIC_DO_REL_NOIFUNC ((map), (scope), edr_lazy);		      \
> -    ELF_DYNAMIC_DO_RELA_NOIFUNC ((map), (scope), edr_lazy);		      \
> -    ELF_DYNAMIC_AFTER_RELOC ((map), (edr_lazy));			      \
> -  } while (0)
> -
> -/* IRELATIVE-only companion to ELF_DYNAMIC_RELOCATE_NOIFUNC.  */
> -# define ELF_DYNAMIC_RELOCATE_IFUNC(map, scope, lazy, skip_ifunc)	      \
> -  do {									      \
> -    ELF_DYNAMIC_DO_REL_IFUNCONLY ((map), (scope), (lazy), skip_ifunc);	      \
> -    ELF_DYNAMIC_DO_RELA_IFUNCONLY ((map), (scope), (lazy), skip_ifunc);	      \
> -  } while (0)
> +  ELF_DYNAMIC_RELOCATE_PASS (DL_RELOC_ALL, (map), (scope), (lazy),	      \
> +			     (consider_profile), skip_ifunc)
>  
>  #endif
> diff --git a/elf/tst-ifunc-fault-dep-bindnow.c b/elf/tst-ifunc-fault-dep-bindnow.c
> new file mode 100644
> index 00000000000..60d97dcaa44
> --- /dev/null
> +++ b/elf/tst-ifunc-fault-dep-bindnow.c
> @@ -0,0 +1,19 @@
> +/* Program calling an IFUNC defined in a dependency.  BIND_NOW variant.
> +   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/>.  */
> +
> +#include "tst-ifunc-fault-dep-lazy.c"
> diff --git a/elf/tst-ifunc-fault-dep-lazy.c b/elf/tst-ifunc-fault-dep-lazy.c
> new file mode 100644
> index 00000000000..122d33f391e
> --- /dev/null
> +++ b/elf/tst-ifunc-fault-dep-lazy.c
> @@ -0,0 +1,27 @@
> +/* Program calling an IFUNC defined in a dependency (BZ 34428).
> +   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/>.  */
> +
> +extern void magic (void);
> +
> +int
> +main (void)
> +{
> +  /* JMP_SLOT relocation against an undefined symbol.  */
> +  magic ();
> +  return 1;
> +}
> diff --git a/elf/tst-ifunc-fault-mod.c b/elf/tst-ifunc-fault-mod.c
> new file mode 100644
> index 00000000000..11c21b48ac4
> --- /dev/null
> +++ b/elf/tst-ifunc-fault-mod.c
> @@ -0,0 +1,38 @@
> +/* Shared object exporting an IFUNC symbol with a resolver which crashes.
> +   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/>.  */
> +
> +#include <stddef.h>
> +
> +static void
> +implementation (void)
> +{
> +  /* Produce a crash, without depending on any relocations.  */
> +  volatile char *volatile p = NULL;
> +  *p = 0;
> +}
> +
> +static __typeof__ (implementation) *
> +resolver (void)
> +{
> +  /* Produce a crash, without depending on any relocations.  */
> +  volatile char *volatile p = NULL;
> +  *p = 0;
> +  return implementation;
> +}
> +
> +void magic (void) __attribute__ ((ifunc ("resolver")));
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 418 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libc-alpha/attachments/20260808/8344543f/attachment-0001.sig>


More information about the Libc-alpha mailing list