tests += \
tst-ifunc-fault-bindnow \
tst-ifunc-fault-lazy \
+ tst-ifunc-plt \
+ tst-ifunc-plt-bindnow \
+ tst-ifunc-plt-dlopen \
+ tst-ifunc-plt-dlopen-bindnow \
# tests
# Note: sysdeps/x86_64/ifuncmain8.c uses ifuncmain8.
tests-internal += \
ifuncmod1 \
ifuncmod3 \
ifuncmod6 \
+ tst-ifunc-plt-dep \
+ tst-ifunc-plt-lib \
# modules-names
ifeq (no,$(with-lld))
modules-names += ifuncmod5
ifuncmod1.so-no-z-defs = yes
ifuncmod5.so-no-z-defs = yes
ifuncmod6.so-no-z-defs = yes
+tst-ifunc-plt-lib.so-no-z-defs = yes
tst-auditmod9a.so-no-z-defs = yes
tst-auditmod9b.so-no-z-defs = yes
tst-nodelete-uniquemod.so-no-z-defs = yes
$(objpfx)ld.so
$(tst-ifunc-fault-script)
+LDFLAGS-tst-ifunc-plt-lib.so = -Wl,-z,lazy
+
+tst-ifunc-plt-bindnow-ENV = LD_BIND_NOW=1
+tst-ifunc-plt-dlopen-bindnow-ENV = LD_BIND_NOW=1
+
+$(objpfx)tst-ifunc-plt-lib.so: $(objpfx)tst-ifunc-plt-dep.so
+$(objpfx)tst-ifunc-plt: $(objpfx)tst-ifunc-plt-lib.so
+$(objpfx)tst-ifunc-plt-bindnow: $(objpfx)tst-ifunc-plt-lib.so
+$(objpfx)tst-ifunc-plt-dlopen.out: \
+ $(objpfx)tst-ifunc-plt-lib.so $(objpfx)tst-ifunc-plt-dep.so
+$(objpfx)tst-ifunc-plt-dlopen-bindnow.out: \
+ $(objpfx)tst-ifunc-plt-lib.so $(objpfx)tst-ifunc-plt-dep.so
+
$(objpfx)tst-unique1.out: $(objpfx)tst-unique1mod1.so \
$(objpfx)tst-unique1mod2.so
#ifdef DO_RELA
# define elf_dynamic_do_Rel elf_dynamic_do_Rela
+# define elf_dynamic_do_Rel_irelative elf_dynamic_do_Rela_irelative
+# define elf_dynamic_is_Rel_irelative elf_dynamic_is_Rela_irelative
+# define elf_dynamic_Rel_audit_symbind elf_dynamic_Rela_audit_symbind
# define Rel Rela
# define elf_machine_rel elf_machine_rela
# define elf_machine_rel_relative elf_machine_rela_relative
(void *) (l_addr + relative->r_offset))
#endif
+static __always_inline bool
+elf_dynamic_is_Rel_irelative (const ElfW(Rel) *reloc, const ElfW(Sym) *sym)
+{
+#ifdef ELF_MACHINE_IRELATIVE
+ const unsigned int r_type = ELFW (R_TYPE) (reloc->r_info);
+ return ((sym != NULL
+ && ELFW(ST_TYPE) (sym->st_info) == STT_GNU_IFUNC
+ && sym->st_shndx != SHN_UNDEF)
+ || r_type == ELF_MACHINE_IRELATIVE);
+#else
+ return false;
+#endif
+}
+
+static __always_inline void
+elf_dynamic_Rel_audit_symbind (struct link_map *map,
+ struct r_scope_elem *scope[],
+ const ElfW(Rel) *reloc, const ElfW(Sym) *sym,
+ const struct r_found_version *rversion,
+ void *r_addr_arg)
+{
+#if defined SHARED
+ if (ELFW(R_TYPE) (reloc->r_info) == ELF_MACHINE_JMP_SLOT
+ && GLRO(dl_naudit) > 0)
+ {
+ struct link_map *sym_map
+ = RESOLVE_MAP (map, scope, &sym, rversion, ELF_MACHINE_JMP_SLOT);
+ if (sym != NULL)
+ _dl_audit_symbind (map, NULL, reloc, sym, r_addr_arg, sym_map, false);
+ }
+#endif
+}
+
/* 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.
+
+ IRELATIVE entries 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. */
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 skip_ifunc)
+ int lazy)
{
const ElfW(Rel) *relative = (const void *) reladdr;
const ElfW(Rel) *r = relative + nrelative;
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, skip_ifunc);
+ elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
}
#else /* !RTLD_BOOTSTRAP */
-# if defined ELF_MACHINE_IRELATIVE
- const ElfW(Rel) *r2 = NULL;
- const ElfW(Rel) *end2 = NULL;
-# endif
-
#if !defined DO_RELA || !defined ELF_MACHINE_PLT_REL
/* We never bind lazily during ld.so bootstrap. Unfortunately gcc is
not clever enough to see through all the function calls to realize
{
/* Doing lazy PLT relocations; they need very little info. */
for (; r < end; ++r)
-# ifdef ELF_MACHINE_IRELATIVE
- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
- {
- if (r2 == NULL)
- r2 = r;
- end2 = r;
- }
- else
-# endif
- elf_machine_lazy_rel (map, scope, l_addr, r, skip_ifunc);
-
-# ifdef ELF_MACHINE_IRELATIVE
- if (r2 != NULL)
- for (; r2 <= end2; ++r2)
- if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
- elf_machine_lazy_rel (map, scope, l_addr, r2, skip_ifunc);
-# endif
+ {
+ 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);
+ }
}
else
#endif
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
const struct r_found_version *rversion = &map->l_versions[ndx];
-#if defined ELF_MACHINE_IRELATIVE
- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
- {
- if (r2 == NULL)
- r2 = r;
- end2 = r;
- continue;
- }
-#endif
+ if (elf_dynamic_is_Rel_irelative (r, sym))
+ continue;
+ elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg, 0);
+ elf_dynamic_Rel_audit_symbind (map, scope, r, sym, rversion,
+ r_addr_arg);
+ }
+ }
+ else
+ {
+ for (; r < end; ++r)
+ {
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
+ void *const r_addr_arg = (void *) (l_addr + r->r_offset);
+
+ if (elf_dynamic_is_Rel_irelative (r, sym))
+ continue;
+ elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg, 0);
+ elf_dynamic_Rel_audit_symbind (map, scope, r, sym, NULL,
+ r_addr_arg);
+ }
+ }
+ }
+#endif /* !RTLD_BOOTSTRAP */
+}
+
+/* Process only IRELATIVE entries (and other relocations targeting a defined
+ STT_GNU_IFUNC symbol) in the relocation range [reladdr, reladdr+relsize).
+ The first NRELATIVE entries are R_*_RELATIVE and are skipped without
+ inspection. When lazy is non-zero the PLT lazy-binding path
+ (elf_machine_lazy_rel) is used, otherwise the full non-lazy path
+ (elf_machine_rel) is used.
+
+ Called by _ELF_DYNAMIC_DO_RELOC after all non-IRELATIVE relocations have
+ been processed for both .rela.dyn and .rela.plt, so that IRELATIVE
+ resolvers may call PLT stubs safely regardless of which section the linker
+ placed R_*_IRELATIVE in. */
+static __always_inline void
+elf_dynamic_do_Rel_irelative (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 skip_ifunc)
+{
+# ifdef ELF_MACHINE_IRELATIVE
+ const ElfW(Rel) *r = (const ElfW(Rel) *) reladdr + nrelative;
+ const ElfW(Rel) *end = (const void *) (reladdr + relsize);
+ ElfW(Addr) l_addr = map->l_addr;
+ const ElfW(Sym) *const symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]);
+
+ if (lazy)
+ {
+ for (; r < end; ++r)
+ {
+ 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, skip_ifunc);
+ }
+ }
+ else
+ {
+ if (map->l_info[VERSYMIDX (DT_VERSYM)])
+ {
+ const ElfW(Half) *const version =
+ (const void *) D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+
+ for (; r < end; ++r)
+ {
+ const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
+ void *const r_addr_arg = (void *) (l_addr + r->r_offset);
+ if (!elf_dynamic_is_Rel_irelative (r, sym))
+ continue;
+
+ ElfW(Half) ndx = version[ELFW(R_SYM) (r->r_info)] & 0x7fff;
+ const struct r_found_version *rversion = &map->l_versions[ndx];
elf_machine_rel (map, scope, r, sym, rversion, r_addr_arg,
skip_ifunc);
-#if defined SHARED
- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
- && GLRO(dl_naudit) > 0)
- {
- struct link_map *sym_map
- = RESOLVE_MAP (map, scope, &sym, rversion,
- ELF_MACHINE_JMP_SLOT);
- if (sym != NULL)
- _dl_audit_symbind (map, NULL, r, sym, r_addr_arg, sym_map,
- false);
- }
-#endif
+ elf_dynamic_Rel_audit_symbind (map, scope, r, sym, rversion,
+ r_addr_arg);
}
-
-#if defined ELF_MACHINE_IRELATIVE
- if (r2 != NULL)
- for (; r2 <= end2; ++r2)
- if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
- {
- ElfW(Half) ndx
- = version[ELFW(R_SYM) (r2->r_info)] & 0x7fff;
- elf_machine_rel (map, scope, r2,
- &symtab[ELFW(R_SYM) (r2->r_info)],
- &map->l_versions[ndx],
- (void *) (l_addr + r2->r_offset),
- skip_ifunc);
- }
-#endif
}
else
{
{
const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (r->r_info)];
void *const r_addr_arg = (void *) (l_addr + r->r_offset);
-# ifdef ELF_MACHINE_IRELATIVE
- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_IRELATIVE)
- {
- if (r2 == NULL)
- r2 = r;
- end2 = r;
- continue;
- }
-# endif
+ if (!elf_dynamic_is_Rel_irelative (r, sym))
+ continue;
+
elf_machine_rel (map, scope, r, sym, NULL, r_addr_arg,
skip_ifunc);
-# if defined SHARED
- if (ELFW(R_TYPE) (r->r_info) == ELF_MACHINE_JMP_SLOT
- && GLRO(dl_naudit) > 0)
- {
- struct link_map *sym_map
- = RESOLVE_MAP (map, scope, &sym,
- (struct r_found_version *) NULL,
- ELF_MACHINE_JMP_SLOT);
- if (sym != NULL)
- _dl_audit_symbind (map, NULL, r, sym,r_addr_arg, sym_map,
- false);
- }
-# endif
+ elf_dynamic_Rel_audit_symbind (map, scope, r, sym, NULL,
+ r_addr_arg);
}
-
-# ifdef ELF_MACHINE_IRELATIVE
- if (r2 != NULL)
- for (; r2 <= end2; ++r2)
- if (ELFW(R_TYPE) (r2->r_info) == ELF_MACHINE_IRELATIVE)
- elf_machine_rel (map, scope, r2, &symtab[ELFW(R_SYM) (r2->r_info)],
- NULL, (void *) (l_addr + r2->r_offset),
- skip_ifunc);
-# endif
}
}
-#endif /* !RTLD_BOOTSTRAP */
+# endif
}
#undef elf_dynamic_do_Rel
+#undef elf_dynamic_do_Rel_irelative
+#undef elf_dynamic_is_Rel_irelative
+#undef elf_dynamic_Rel_audit_symbind
#undef Rel
#undef elf_machine_rel
#undef elf_machine_rel_relative
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. */
-# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, test_rel) \
+# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, \
+ test_rel) \
do { \
struct { ElfW(Addr) start, size; \
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
} \
} \
\
- 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, \
- skip_ifunc); \
+ /* Defer all IRELATIVE relocations until after all non-IRELATIVE \
+ relocations (including PLT lazy-binding setup) have been processed \
+ for both sections. This ensures IRELATIVE resolvers can call PLT \
+ stubs safely regardless of which section R_*_IRELATIVE was placed in \
+ by the linker. */ \
+ if (!DO_RTLD_BOOTSTRAP) \
+ { \
+ 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); \
+ for (int ranges_index = 0; ranges_index < 2; ++ranges_index) \
+ elf_dynamic_do_##reloc##_irelative ((map), scope, \
+ ranges[ranges_index].start, \
+ ranges[ranges_index].size, \
+ ranges[ranges_index].nrelative,\
+ ranges[ranges_index].lazy, \
+ skip_ifunc); \
+ } \
+ else \
+ 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); \
} while (0)
# if ELF_MACHINE_NO_REL || ELF_MACHINE_NO_RELA
--- /dev/null
+/* Test that IRELATIVE resolvers may call PLT functions with LD_BIND_NOW=1.
+ Copyright (C) 2019-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/>. */
+
+/* Same as tst-ifunc-plt, but the test is run with LD_BIND_NOW=1 so the
+ library is processed eagerly. Under eager binding the JMP_SLOT entries
+ in .rela.plt are resolved by elf_machine_rel during relocation; this
+ exercises the eager path of the deferred IRELATIVE processing. */
+
+#include "tst-ifunc-plt.c"
--- /dev/null
+/* Dependency library for tst-ifunc-plt.
+ 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/>. */
+
+int
+get_value (void)
+{
+ return 42;
+}
--- /dev/null
+/* Test that IRELATIVE resolvers may call PLT functions via dlopen + RTLD_NOW.
+ 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/>. */
+
+
+/* Same as tst-ifunc-plt-dlopen, but uses RTLD_NOW to force eager
+ relocation of the loaded library. This exercises the dlopen entry
+ point along the eager-binding path. */
+
+#include <support/xdlfcn.h>
+#include <support/check.h>
+
+typedef int (*fn_t) (void);
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-ifunc-plt-lib.so", RTLD_NOW | RTLD_LOCAL);
+
+ fn_t compute_a = (fn_t) xdlsym (handle, "compute_a");
+ TEST_COMPARE (compute_a (), 1);
+
+ fn_t compute_b = (fn_t) xdlsym (handle, "compute_b");
+ TEST_COMPARE (compute_b (), 2);
+
+ xdlclose (handle);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Test that IRELATIVE resolvers may call PLT functions on a dlopen'd library.
+ 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/>. */
+
+
+/* dlopen tst-ifunc-plt-lib.so with RTLD_LAZY and verify that the IFUNC
+ resolver (which calls get_value() via PLT) ran successfully. This
+ exercises the same _dl_relocate_object code path as startup loading
+ but via the dlopen entry point. */
+
+#include <support/xdlfcn.h>
+#include <support/check.h>
+
+typedef int (*fn_t) (void);
+
+static int
+do_test (void)
+{
+ void *handle = xdlopen ("tst-ifunc-plt-lib.so", RTLD_LAZY | RTLD_LOCAL);
+
+ fn_t compute_a = (fn_t) xdlsym (handle, "compute_a");
+ TEST_COMPARE (compute_a (), 1);
+
+ fn_t compute_b = (fn_t) xdlsym (handle, "compute_b");
+ TEST_COMPARE (compute_b (), 2);
+
+ xdlclose (handle);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Shared library for tst-ifunc-plt.
+ Two static IFUNCs whose resolvers both call get_value() via PLT.
+ 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/>. */
+
+
+/* Both resolvers call get_value() via PLT (one JUMP_SLOT entry in
+ .rel{a}.plt). This verifies that every IRELATIVE entry is deferred
+ until after .rela.plt has been processed, not just the first one. */
+
+#include <stddef.h>
+
+extern int get_value (void);
+
+static int
+impl_a (void)
+{
+ return 1;
+}
+
+static int
+impl_b (void)
+{
+ return 2;
+}
+
+static int (*
+resolve_a (void)) (void)
+{
+ return get_value () == 42 ? impl_a : NULL;
+}
+
+static int (*
+resolve_b (void)) (void)
+{
+ return get_value () == 42 ? impl_b : NULL;
+}
+
+/* The test is only built for $(have-ifunc), so we can assume HAVE_GCC_IFUNC
+ here. */
+int compute_a (void) __attribute__ ((ifunc ("resolve_a")));
+int compute_b (void) __attribute__ ((ifunc ("resolve_b")));
--- /dev/null
+/* Test that IRELATIVE resolvers may call PLT functions during startup.
+ 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/>. */
+
+
+/* tst-ifunc-plt-multi-lib.so defines two static IFUNCs (compute_a and
+ compute_b), each producing an R_*_IRELATIVE in .rel{a}.dyn, with both
+ resolvers calling get_value() via PLT. The test verifies that both
+ IRELATIVEs are deferred until after .rel{a}.plt is processed. */
+
+#include <support/check.h>
+
+extern int compute_a (void);
+extern int compute_b (void);
+
+static int
+do_test (void)
+{
+ TEST_COMPARE (compute_a (), 1);
+ TEST_COMPARE (compute_b (), 2);
+ return 0;
+}
+
+#include <support/test-driver.c>
| (((type) == R_AARCH64_COPY) * ELF_RTYPE_CLASS_COPY))
#define ELF_MACHINE_JMP_SLOT R_AARCH64_JUMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_AARCH64_IRELATIVE
#define DL_PLATFORM_INIT dl_platform_init ()
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_ARM_JUMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_ARM_IRELATIVE
/* We define an initialization functions. This is called very early in
_dl_sysdep_start. */
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_386_JMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_386_IRELATIVE
/* We define an initialization functions. This is called very early in
_dl_sysdep_start. */
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_PPC_JMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_PPC_IRELATIVE
/* We define an initialization function to initialize HWCAP/HWCAP2 and
platform data so it can be copied into the TCB later. This is called
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_PPC64_JMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_PPC64_IRELATIVE
/* We define an initialization function to initialize HWCAP/HWCAP2 and
platform data so it can be copied into the TCB later. This is called
#endif
#define ELF_MACHINE_JMP_SLOT R_RISCV_JUMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_RISCV_IRELATIVE
#define elf_machine_type_class(type) \
((ELF_RTYPE_CLASS_PLT * ((type) == ELF_MACHINE_JMP_SLOT \
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_SPARC_IRELATIVE
/* Undo the sub %sp, 6*4, %sp; add %sp, 22*4, %o0 below to get at the
value we want in __libc_stack_end. */
/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
#define ELF_MACHINE_JMP_SLOT R_SPARC_JMP_SLOT
+#define ELF_MACHINE_IRELATIVE R_SPARC_IRELATIVE
/* Set up the loaded object described by L so its unrelocated PLT
entries will jump to the on-demand fixup code in dl-runtime.c. */