Re: [PATCH v2 1/2] elf: Honour skip_ifunc for cross-object IFUNC relocations [BZ #34428]
Sam James <[email protected]>
| Newsgroups | gmane.comp.lib.glibc.alpha |
|---|---|
| Organization | Gentoo |
| Message-ID | <[email protected]> |
Adhemerval Zanella <[email protected]> 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 <[email protected]> > --- > 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")));
signature.asc
(application/pgp-signature, 418 B)
-----BEGIN PGP SIGNATURE----- iQEBBAEWCgCpFiEEJaa7iN2bdkxrVUHCc4QJ9SDfkZAFAmp2i3sbFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMiwyXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25z Lm9wZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQyNUE2QkI4OEREOUI3NjRDNkI1NTQx QzI3Mzg0MDlGNTIwREY5MTkwDxxzYW1AZ2VudG9vLm9yZwAKCRBzhAn1IN+RkGpG AP9Q0oLBfEyaBMvUzpbBSJAiamw8j8iQ8yb19/i/D4L6SwD/fAdiNihUzqYXEZrS lwbzuSc1o24xBPkrMYqN4/R8sgw= =exaS -----END PGP SIGNATURE-----