ARCH_INIT_CPU_FEATURES ();
- /* Do static pie self relocation after tunables and cpu features
- are setup for ifunc resolvers. Before this point relocations
- must be avoided. */
+ /* Do static-pie self relocation for the non-IRELATIVE part after tunables
+ and cpu features are set up. IFUNC entries are deferred until after the
+ TCB and the stack-protector canary are usable, so that an instrumented
+ resolver does not fault. Before this point relocations must be
+ avoided. */
_dl_relocate_static_pie ();
- /* Perform IREL{,A} relocations. */
- ARCH_SETUP_IREL ();
-
- /* The stack guard goes into the TCB, so initialize it early. */
+ /* Set up the TCB so that the IFUNC pass below can fire resolvers
+ compiled with stack protection, and so that resolvers reading TLS
+ (errno, __thread variables, powerpc's hwcap / at_platform in the
+ TCB) observe an initialised slot. */
ARCH_SETUP_TLS ();
- /* In some architectures, IREL{,A} relocations happen after TLS setup in
- order to let IFUNC resolvers benefit from TCB information, e.g. powerpc's
- hwcap and platform fields available in the TCB. */
- ARCH_APPLY_IREL ();
-
- /* Set up the stack checker's canary. */
+ /* Set up the stack checker's canary. Must happen before any IFUNC resolver
+ runs so a resolver compiled with stack protection loads a defined
+ canary. */
uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
# ifdef THREAD_SET_STACK_GUARD
THREAD_SET_STACK_GUARD (stack_chk_guard);
__stack_chk_guard = stack_chk_guard;
# endif
- /* Initialize libpthread if linked in. */
- if (__pthread_initialize_minimal != NULL)
- __pthread_initialize_minimal ();
-
/* Set up the pointer guard value. */
uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
stack_chk_guard);
__pointer_chk_guard_local = pointer_chk_guard;
# endif
+ /* Now that the TCB, canary, and pointer guard are in place, run the
+ deferred IFUNC relocations. For non-PIE static binaries this is
+ ARCH_SETUP_IREL (apply_irel); for static-pie it is the IRELATIVE
+ phase of _dl_relocate_static_pie above. */
+ _dl_relocate_static_pie_ifunc ();
+ ARCH_SETUP_IREL ();
+
+ /* Initialize libpthread if linked in. */
+ if (__pthread_initialize_minimal != NULL)
+ __pthread_initialize_minimal ();
+
#endif /* !SHARED */
/* Register the destructor of the dynamic linker if there is any. */
_dl_relocate_static_pie (void)
{
}
+
+void
+_dl_relocate_static_pie_ifunc (void)
+{
+}
#endif
tst-tunables-enable_secure \
# tests-static-internal
+ifeq (yes,$(have-gcc-ifunc))
+tests-static-internal += \
+ tst-ifunc-resolver-protector-static \
+ tst-ifunc-resolver-protector-static-non-pie \
+ # tests-static-internal
+endif
+
CRT-tst-tls1-static-non-pie := $(csu-objpfx)crt1.o
tst-tls1-static-non-pie-no-pie = yes
+CRT-tst-ifunc-resolver-protector-static-non-pie := $(csu-objpfx)crt1.o
+tst-ifunc-resolver-protector-static-non-pie-no-pie = yes
tests-container := \
tst-dl-cache-long-path \
tst-tlsmod17a \
tst-tlsmod18a \
# test-extras
+
+ifeq (yes,$(have-gcc-ifunc))
+# The resolver helper needs <tls.h> for the TCB-canary STACK_CHK_GUARD
+# macro, so it must be compiled with MODULE_NAME=testsuite_internal.
+extra-test-objs += \
+ tst-ifunc-resolver-protector-static-mod.o \
+ tst-ifunc-resolver-protector-static-non-pie-mod.o \
+ # extra-test-objs
+test-internal-extras += \
+ tst-ifunc-resolver-protector-static-mod \
+ tst-ifunc-resolver-protector-static-non-pie-mod \
+ # test-internal-extras
+endif
modules-names += \
circlemod1 \
circlemod1a \
ifuncmain7static \
# tests-ifuncstatic
ifeq (yes,$(have-gcc-ifunc))
-tests-ifuncstatic += ifuncmain9static ifuncmain9picstatic
+tests-ifuncstatic += \
+ ifuncmain9picstatic \
+ ifuncmain9static \
+ tst-ifunc-bz28817 \
+ # tests-ifuncstatic
endif
tests-static += $(tests-ifuncstatic)
tests-internal += $(tests-ifuncstatic)
tst-ifunc-plt-bindnow \
tst-ifunc-plt-dlopen \
tst-ifunc-plt-dlopen-bindnow \
+ tst-ifunc-resolver-protector \
tst-ifunc-tls-init \
tst-ifunc-tls-write \
# tests
ifuncmod6 \
tst-ifunc-plt-dep \
tst-ifunc-plt-lib \
+ tst-ifunc-resolver-protector-mod \
tst-ifunc-tls-init-lib1 \
tst-ifunc-tls-init-lib2 \
tst-ifunc-tls-write-lib \
$(objpfx)tst-tlsalign-extern: $(objpfx)tst-tlsalign-vars.o
$(objpfx)tst-tlsalign-extern-static: $(objpfx)tst-tlsalign-vars.o
+# The resolver translation unit must always be compiled with
+# -fstack-protector-all so the canary code is emitted regardless of the
+# default.
+CFLAGS-tst-ifunc-resolver-protector-static-mod.c = -fstack-protector-all
+CFLAGS-tst-ifunc-resolver-protector-static-non-pie-mod.c = -fstack-protector-all
+CFLAGS-tst-ifunc-resolver-protector-mod.c = -fstack-protector-all
+$(objpfx)tst-ifunc-resolver-protector-static: \
+ $(objpfx)tst-ifunc-resolver-protector-static-mod.o
+$(objpfx)tst-ifunc-resolver-protector-static-non-pie: \
+ $(objpfx)tst-ifunc-resolver-protector-static-non-pie-mod.o
+$(objpfx)tst-ifunc-resolver-protector: \
+ $(objpfx)tst-ifunc-resolver-protector-mod.so
+
tst-null-argv-ENV = LD_DEBUG=all LD_DEBUG_OUTPUT=$(objpfx)tst-null-argv.debug.out
LDFLAGS-nodel2mod3.so = -Wl,--no-as-needed
LDFLAGS-reldepmod5.so = -Wl,--no-as-needed
#include "dynamic-link.h"
#include "get-dynamic-info.h"
-/* Relocate static executable with PIE. */
-
+/* Phase 1: relocate static PIE - non-IRELATIVE pass. IFUNC resolvers are
+ deferred to _dl_relocate_static_pie_ifunc so that csu/libc-start.c can
+ initialise the TCB (and write the stack-protector canary into it) between
+ the two passes. */
void
_dl_relocate_static_pie (void)
{
ELF_MACHINE_BEFORE_RTLD_RELOC (main_map, main_map->l_info);
# endif
- /* Relocate ourselves so we can do normal function calls and
- data access using the global offset table. */
- ELF_DYNAMIC_RELOCATE (main_map, NULL, 0, 0, 0);
- main_map->l_relocated = 1;
+ /* 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);
/* Initialize _r_debug_extended. */
struct r_debug *r = _dl_debug_initialize (0, LM_ID_BASE);
time. */
elf_setup_debug_entry (main_map, r);
}
+
+/* Phase 2: run the deferred IRELATIVE entries for the static-pie main map.
+ Must be called after the TCB is set up and the stack-protector canary is
+ written, so that an instrumented IFUNC resolver does not fault. */
+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);
+ main_map->l_relocated = 1;
+}
#endif
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
+{
+ 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. */
+};
+
# define _ELF_DYNAMIC_DO_RELOC(RELOC, reloc, map, scope, do_lazy, skip_ifunc, \
- test_rel) \
+ test_rel, phase) \
do { \
struct { ElfW(Addr) start, size; \
__typeof (((ElfW(Dyn) *) 0)->d_un.d_val) nrelative; int lazy; } \
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); \
+ if ((phase) != DL_RELOC_IFUNC) \
+ 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) \
+ 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) \
# if ! ELF_MACHINE_NO_REL
# include "do-rel.h"
# define ELF_DYNAMIC_DO_REL(map, scope, lazy, skip_ifunc) \
- _ELF_DYNAMIC_DO_RELOC (REL, Rel, map, scope, lazy, skip_ifunc, _ELF_CHECK_REL)
+ _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)
# 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. */
# endif
# if ! ELF_MACHINE_NO_RELA
# define DO_RELA
# include "do-rel.h"
# define ELF_DYNAMIC_DO_RELA(map, scope, lazy, skip_ifunc) \
- _ELF_DYNAMIC_DO_RELOC (RELA, Rela, map, scope, lazy, skip_ifunc, _ELF_CHECK_REL)
+ _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)
# 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. */
# endif
# define ELF_DYNAMIC_DO_RELR(map) \
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)
+
#endif
--- /dev/null
+/* BZ 28817: TLS read from a static-pie IFUNC resolver.
+ 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 <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+
+__thread int bar;
+extern __thread int bar_gd asm ("bar")
+ __attribute__ ((tls_model("global-dynamic")));
+static int *bar_ptr;
+
+int foo (void);
+
+static void
+init_foo (void)
+{
+ bar_ptr = &bar_gd;
+}
+
+static int
+my_foo (void)
+{
+ return bar_ptr != NULL;
+}
+
+static __typeof (foo) *
+inhibit_stack_protector
+foo_ifunc (void)
+{
+ init_foo ();
+ __typeof (foo) *res = my_foo;
+ return res;
+};
+__typeof (foo) foo __attribute__ ((ifunc ("foo" "_ifunc")));
+
+static int
+do_test (void)
+{
+ TEST_VERIFY (foo ());
+ TEST_VERIFY (&bar == bar_ptr);
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Stack-protector-instrumented IFUNC resolver in a shared library, used
+ by tst-ifunc-resolver-protector. BZ #27582.
+ 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/>. */
+
+/* Built with -fstack-protector-all so the resolver's prologue/epilogue
+ carries the full canary check. Reaching the return statement means the
+ canary load did not fault (TCB-canary ABIs) and the canary compare did not
+ call __stack_chk_fail. The dynamic linker calls security_init() before the
+ main relocation loop, so resolvers fired from startup or dlopen should
+ always observe an initialised canary; this test guards against any future
+ reordering that would break that invariant. */
+
+#define SENTINEL 0x5A5A1234
+
+static volatile int resolver_ran;
+
+int
+get_resolver_ran (void)
+{
+ return resolver_ran;
+}
+
+static int
+impl_ok (int x)
+{
+ return x + SENTINEL;
+}
+
+typedef int (*fn_t) (int);
+
+static fn_t
+resolver (void)
+{
+ /* Buffer + zero-fill force -fstack-protector-all canary code. */
+ volatile char buf[32];
+ for (unsigned i = 0; i < sizeof (buf); ++i)
+ buf[i] = 0;
+ resolver_ran = 1;
+ return impl_ok;
+}
+
+int compute (int) __attribute__ ((ifunc ("resolver")));
+
+/* Address taken in DSO data to force an R_*_IRELATIVE in .rela.dyn (a
+ non-PLT relocation against the IFUNC). */
+int (*fptr) (int) = compute;
--- /dev/null
+/* Stack-protector-instrumented IFUNC resolver used by
+ tst-ifunc-resolver-protector-static. BZ #34164.
+ 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/>. */
+
+/* This translation unit is built with -fstack-protector-all so that the
+ compiler instruments the resolver below. The resolver's prologue loads
+ the canary from the TCB (TCB-canary ABIs) or from __stack_chk_guard
+ (global-var ABIs); the epilogue compares it against the on-stack copy.
+ Pre-fix the prologue load either faulted (TCB-canary) or loaded zero
+ (global-var).
+
+ The resolver also records the canary value via STACK_CHK_GUARD so the
+ test can verify it matches what main observes. */
+
+#include <stackguard-macros.h>
+#include <stdint.h>
+#include <tls.h>
+
+#define SENTINEL 0x5A5A1234
+
+static volatile uintptr_t resolver_canary;
+
+uintptr_t
+get_resolver_canary (void)
+{
+ return resolver_canary;
+}
+
+static int
+impl_ok (int x)
+{
+ return x + SENTINEL;
+}
+
+typedef int (*fn_t) (int);
+
+static fn_t
+resolver (void)
+{
+ /* Buffer forces -fstack-protector-all to emit canary code even with
+ no other reason to. */
+ volatile char buf[32];
+ for (unsigned i = 0; i < sizeof (buf); ++i)
+ buf[i] = 0;
+
+ resolver_canary = STACK_CHK_GUARD;
+
+ return impl_ok;
+}
+
+int compute (int) __attribute__ ((ifunc ("resolver")));
+
+int (*fptr) (int) = compute;
--- /dev/null
+/* Companion module for tst-ifunc-resolver-protector-static-non-pie. */
+#include "tst-ifunc-resolver-protector-static-mod.c"
--- /dev/null
+/* Same coverage as tst-ifunc-resolver-protector-static, but linked as non-PIE
+ static. Exercises the apply_irel / __rela_iplt_start path instead of the
+ static-pie _dl_relocate_static_pie_ifunc path. */
+
+#include "tst-ifunc-resolver-protector-static.c"
--- /dev/null
+/* Check that a stack-protector-instrumented IFUNC resolver works in a
+ static binary. BZ #34164.
+ 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/>. */
+
+/* When a static binary's IFUNC resolver is compiled with stack protector, the
+ resolver prologue loads the canary from the TCB (TCB-canary ABIs: x86_64,
+ i386, powerpc, s390) or from the global __stack_chk_guard (other ABIs).
+ The test checks if TCB-canary or the global-var is properly initialized:
+
+ 1. The resolver runs without SIGSEGV (TCB-canary) or SIGABRT (canary
+ mismatch).
+
+ 2. The resolver records the canary value it observed via STACK_CHK_GUARD,
+ and main asserts it equals the value visible from user code -- catching
+ the "silent zero canary" variant on global-var ABIs. */
+
+#include <stackguard-macros.h>
+#include <stdint.h>
+#include <tls.h>
+#include <support/check.h>
+
+#define SENTINEL 0x5A5A1234
+
+extern int compute (int);
+extern uintptr_t get_resolver_canary (void);
+
+static int
+do_test (void)
+{
+ /* compute() returns its argument + SENTINEL iff the resolver picked
+ impl_ok, which it does whenever the canary check at the resolver
+ prologue / epilogue did not abort. */
+ TEST_COMPARE (compute (1), 1 + SENTINEL);
+
+ /* Silent-variant check: the canary the resolver loaded must match the
+ canary do_test reads. On global-var ABIs, it checks if the stack
+ protector cookie is properly initialised. */
+ uintptr_t resolver_canary = get_resolver_canary ();
+ uintptr_t main_canary = STACK_CHK_GUARD;
+ TEST_VERIFY (resolver_canary != 0);
+ TEST_COMPARE (resolver_canary, main_canary);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Check that a stack-protector-instrumented IFUNC resolver works in a
+ dynamically-linked binary. BZ #27582.
+ 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/>. */
+
+/* Dynamic counterpart to tst-ifunc-resolver-protector-static.
+
+ The dynamic linker calls security_init() before the main relocation
+ loop, so a stack-protected resolver fired from startup should observe
+ an initialised canary -- but having a regression test guards against
+ any future reordering that would break that invariant. */
+
+#include <support/check.h>
+
+#define SENTINEL 0x5A5A1234
+
+extern int compute (int);
+extern int get_resolver_ran (void);
+
+static int
+do_test (void)
+{
+ TEST_COMPARE (compute (1), 1 + SENTINEL);
+ TEST_VERIFY (get_resolver_ran () != 0);
+ return 0;
+}
+
+#include <support/test-driver.c>
asm ("memset = __memset_generic");
asm ("strlen = __strlen_generic");
+#ifndef SHARED
+asm ("memcpy = __memcpy_generic");
+asm ("memmove = __memmove_generic");
+#endif
#endif
void __libc_setup_tls (void);
# if ENABLE_STATIC_PIE
-/* Relocate static executable with PIE. */
+/* _dl_relocate_static_pie runs every relocation except IRELATIVE. The
+ second entry point _dl_relocate_static_pie_ifunc must be invoked
+ afterwards -- but only once the TCB and the stack-protector canary
+ are usable -- to fire the IFUNC resolvers. */
extern void _dl_relocate_static_pie (void) attribute_hidden;
+extern void _dl_relocate_static_pie_ifunc (void) attribute_hidden;
# else
# define _dl_relocate_static_pie()
+# define _dl_relocate_static_pie_ifunc()
# endif
#endif
#define _LIBC_START_H
#ifndef SHARED
-/* By default we perform STT_GNU_IFUNC resolution *before* TLS
- initialization, and this means you cannot, without machine
- knowledge, access TLS from an IFUNC resolver. */
+/* Static startup runs ARCH_SETUP_TLS (and writes the stack-protector
+ canary) before ARCH_SETUP_IREL, so IFUNC resolvers can read TLS and
+ stack-protector instrumented resolvers do not fault. */
+#define ARCH_SETUP_TLS() __libc_setup_tls ()
#define ARCH_SETUP_IREL() apply_irel ()
-#define ARCH_SETUP_TLS() __libc_setup_tls ()
-#define ARCH_APPLY_IREL()
#endif /* ! SHARED */
#endif /* _LIBC_START_H */
asm ("memset = __memset_aligned");
asm ("memcmp = __memcmp_aligned");
asm ("strlen = __strlen_aligned");
+asm ("memcpy = __memcpy_unaligned");
+asm ("memmove = __memmove_unaligned");
#endif
#endif
# define ARCH_SETUP_IREL() apply_irel ()
# define ARCH_SETUP_TLS() aarch64_libc_setup_tls ()
-# define ARCH_APPLY_IREL()
#endif /* ! SHARED */
#endif /* _LIBC_START_H */
+++ /dev/null
-/* PowerPC definitions for libc main startup.
- Copyright (C) 2017-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 _LIBC_START_H
-#define _LIBC_START_H
-
-#ifndef SHARED
-/* IREL{,A} must happen after TCB initialization in order to allow IFUNC
- resolvers to read TCB fields, e.g. hwcap and at_platform. */
-#define ARCH_SETUP_IREL()
-#define ARCH_SETUP_TLS() __libc_setup_tls ()
-#define ARCH_APPLY_IREL() apply_irel ()
-#endif /* ! SHARED */
-
-#endif /* _LIBC_START_H */
#ifndef SHARED
# define ARCH_SETUP_IREL() apply_irel ()
-# define ARCH_APPLY_IREL()
# ifdef __CET__
/* Get CET features enabled in the static executable. */
asm ("strlen = " HAVE_STRCMP_IFUNC_GENERIC);
+#if MINIMUM_X86_ISA_LEVEL >= 4
+# define HAVE_MEMCPY_IFUNC_GENERIC "__memcpy_evex_unaligned"
+# define HAVE_MEMMOVE_IFUNC_GENERIC "__memmove_evex_unaligned"
+# define HAVE_MEMPCPY_IFUNC_GENERIC "__mempcpy_evex_unaligned"
+#elif MINIMUM_X86_ISA_LEVEL == 3
+# define HAVE_MEMCPY_IFUNC_GENERIC "__memcpy_avx_unaligned"
+# define HAVE_MEMMOVE_IFUNC_GENERIC "__memmove_avx_unaligned"
+# define HAVE_MEMPCPY_IFUNC_GENERIC "__mempcpy_avx_unaligned"
+#else
+# define HAVE_MEMCPY_IFUNC_GENERIC "__memcpy_sse2_unaligned"
+# define HAVE_MEMMOVE_IFUNC_GENERIC "__memmove_sse2_unaligned"
+# define HAVE_MEMPCPY_IFUNC_GENERIC "__mempcpy_sse2_unaligned"
+#endif
+
+asm ("memcpy = " HAVE_MEMCPY_IFUNC_GENERIC);
+asm ("memmove = " HAVE_MEMMOVE_IFUNC_GENERIC);
+asm ("mempcpy = " HAVE_MEMPCPY_IFUNC_GENERIC);
+asm ("__mempcpy = " HAVE_MEMPCPY_IFUNC_GENERIC);
+
#endif /* SHARED */
#endif