The BZ#33326 testcase triggers an assertion during process startup,
which results in a segmentation fault instead of an error message
and process termination with a SIGABRT. The assert issues
__libc_message_impl, which in turn might call string functions
depending on the ABI (strchrnul, strlen, memcpy/mempcpy), system
calls (writev and mmap), and finally the abort call.
Since each function may be called during process startup, before
self-relocation and/or the thread pointer being set up, the
functions should be built without stack protection.
The dl-symbol-redir-ifunc.h is also expanded to cover
strlen/memcpy/mempcpy/strchrnul on multiple architectures that implement
ifunc.
On i386, syscalls should not use the vDSO ("call *%gs:SYSINFO_OFFSET")
during program startup because thread pointer is not yet initialized. This
requires __raise_direct, _dl_writev, and _dl_mmap to use I386_USE_SYSENTER.
To avoid possible sysdep.h I386_USE_SYSENTER redefinition, all
implementations are done on their own translation unit.
The s390x requires not calling libgcc for the generic strchrnul-c (via
ctz/clz macros) due to a libgcc issue: the __clzdi2 builtin is not built
against a hidden reference to __clz_tab, which creates a GOT reference
for static-pie (and it cannot be called before self-relocation).
Creating a test case is challenging. For static-pie, the assert is only
called for ill-formed ELF files on elf_get_dynamic_info and by some targets
on ELF_DYNAMIC_RELOCATE (although not all targets use assert in their
dl-machine.h). Some targets also issue __libc_fatal on ARCH_SETUP_IREL,
but also only for ill-formatted ELF files.
The test employs a different strategy and overrides the __tunables_init
symbol, which is invoked immediately before self-relocation and TLS setup.
The test is built with -Wl,-z,muldefs to avoid linker issues.
I checked on aarch64, x86_64, i686, s390x (qemu), sparc (qemu),
mips64el (qemu), armhf, riscv, and powerpc.
---
assert/Makefile | 5 +++
elf/Makefile | 18 +++++++++
elf/tst-assert-startup-static.c | 40 +++++++++++++++++++
libio/Makefile | 5 +++
stdlib/Makefile | 5 +++
string/Makefile | 1 +
.../aarch64/multiarch/dl-symbol-redir-ifunc.h | 1 +
sysdeps/aarch64/multiarch/memcpy_generic.S | 4 ++
.../armv7/multiarch/dl-symbol-redir-ifunc.h | 27 +++++++++++++
sysdeps/generic/dl-mmap.h | 34 ++++++++++++++++
.../lp64/multiarch/dl-symbol-redir-ifunc.h | 2 +
sysdeps/posix/libc_fatal.c | 12 ++++--
.../powerpc32/power4/multiarch/Makefile | 5 +++
.../be/multiarch/dl-symbol-redir-ifunc.h | 27 +++++++++++++
.../le/multiarch/dl-symbol-redir-ifunc.h | 1 +
sysdeps/powerpc/powerpc64/multiarch/Makefile | 1 +
sysdeps/s390/Makefile | 5 +++
.../s390/multiarch/dl-symbol-redir-ifunc.h | 4 ++
sysdeps/s390/string-bitops.h | 27 +++++++++++++
.../sparcv9/multiarch/dl-symbol-redir-ifunc.h | 3 ++
.../sparc64/multiarch/dl-symbol-redir-ifunc.h | 3 ++
sysdeps/unix/sysv/linux/Makefile | 12 ++++++
sysdeps/unix/sysv/linux/i386/Makefile | 14 +++++++
sysdeps/unix/sysv/linux/i386/dl-mmap.c | 36 +++++++++++++++++
sysdeps/unix/sysv/linux/i386/dl-mmap.h | 27 +++++++++++++
sysdeps/unix/sysv/linux/i386/dl-writev.c | 32 +++++++++++++++
sysdeps/unix/sysv/linux/i386/dl-writev.h | 15 ++++---
sysdeps/unix/sysv/linux/i386/raise_direct.c | 26 ++++++++++++
.../unix/sysv/linux/riscv/multiarch/Makefile | 8 ++++
.../x86_64/multiarch/dl-symbol-redir-ifunc.h | 22 ++++++++++
30 files changed, 414 insertions(+), 8 deletions(-)
create mode 100644 elf/tst-assert-startup-static.c
create mode 100644 sysdeps/arm/armv7/multiarch/dl-symbol-redir-ifunc.h
create mode 100644 sysdeps/generic/dl-mmap.h
create mode 100644 sysdeps/powerpc/powerpc64/be/multiarch/dl-symbol-redir-ifunc.h
create mode 100644 sysdeps/s390/string-bitops.h
create mode 100644 sysdeps/unix/sysv/linux/i386/dl-mmap.c
create mode 100644 sysdeps/unix/sysv/linux/i386/dl-mmap.h
create mode 100644 sysdeps/unix/sysv/linux/i386/dl-writev.c
create mode 100644 sysdeps/unix/sysv/linux/i386/raise_direct.c
On 08/06/26 07:46, Florian Weimer wrote:
> * Adhemerval Zanella:
>
> I think the general issue is not right: During startup, we should not
> use mmap to allocate the backing store. We can preserve the assert
> message and file name by copying them to on-stack buffer. As no user
> code should be running at this point, we do not need to be prepared for
> arbitrarily-long assert messages (but we still should have a length
> check, of course).
>
> Can we redirect to a different assert implementation during early
> startup?
I think I can reinstate the assert wrapper [1]. I kept the assert used
simplify the the implementation and use the same code path. We can use
a stack allocated buffer and cap the message string, for glibc own usage we
would know when we need to increase it.
But it also raises the question whether we do copy the buffer in this case,
this assert will be only used during process startup and it would be triggered
in cases that can be considered glibc issues.
[1] https://sourceware.org/pipermail/libc-alpha/2026-March/176039.html
>
> I'm not sure this actually works for HIDDEN_VAR_NEEDS_DYNAMIC_RELOC
> because of remaining global variable accesses in __assert_fail, but
> maybe we do not support static PIE for them anyway?
>
>> diff --git a/elf/tst-assert-startup-static.c b/elf/tst-assert-startup-static.c
>> new file mode 100644
>> index 00000000000..9fd79a0e243
>> --- /dev/null
>> +++ b/elf/tst-assert-startup-static.c
>> @@ -0,0 +1,40 @@
>> +/* Check if assert work during program startup.
>
> Typo: work[s]
Ack.
>
>> diff --git a/sysdeps/loongarch/lp64/multiarch/dl-symbol-redir-ifunc.h b/sysdeps/loongarch/lp64/multiarch/dl-symbol-redir-ifunc.h
>> index 1cd204c2f69..4379770c314 100644
>> --- a/sysdeps/loongarch/lp64/multiarch/dl-symbol-redir-ifunc.h
>> +++ b/sysdeps/loongarch/lp64/multiarch/dl-symbol-redir-ifunc.h
>> @@ -20,8 +20,10 @@
>> #define _DL_IFUNC_GENERIC_H
>>
>> #ifndef SHARED
>> +asm ("memcpy = __memcpy_aligned");
>> asm ("memset = __memset_aligned");
>> asm ("memcmp = __memcmp_aligned");
>> +asm ("__strchrnul = __strchrnul_aligned");
>> asm ("strlen = __strlen_aligned");
>> asm ("memcpy = __memcpy_unaligned");
>> asm ("memmove = __memmove_unaligned");
>
> Now memcpy is redirected twice. The existing unconsistency between the
> *_aligned and *_unaligned variants is a bit jarring, but I don't know
> enough about the port to resolve it.
Ack, I will remove the memcpy. We can remove the unconsistency later, it
is a performance improvement.
>
>> diff --git a/sysdeps/powerpc/powerpc64/be/multiarch/dl-symbol-redir-ifunc.h b/sysdeps/powerpc/powerpc64/be/multiarch/dl-symbol-redir-ifunc.h
>> new file mode 100644
>> index 00000000000..560f57366b2
>> --- /dev/null
>> +++ b/sysdeps/powerpc/powerpc64/be/multiarch/dl-symbol-redir-ifunc.h
>> @@ -0,0 +1,27 @@
>> +/* Symbol rediretion for loader/static initialization code.
>
> Typo: Symbol redire[c]tion
>
> This occurs multiple times.
Ack.
>
>> diff --git a/sysdeps/s390/string-bitops.h b/sysdeps/s390/string-bitops.h
>> new file mode 100644
>> index 00000000000..f660d019c77
>> --- /dev/null
>> +++ b/sysdeps/s390/string-bitops.h
>> @@ -0,0 +1,27 @@
>> +/* Zero byte detection, define whether to use stdbit.h
>
> Should say “s390 version”.
>
Ack.
>> +/* s390x support static-pie and the libgcc implementation for
>> + __builtin_clzl/__builtin_ctzl might access extern data that is not marked
>> + as hidden, which creates additiona GOT access that is used before
>> + self-relocation. */
>
> Typo: additiona[l]
Ack.
>
>> +#if __ARCH__ > 6
>> +# define HAVE_BITOPTS_WORKING 1
>> +#else
>> +# define HAVE_BITOPTS_WORKING 0
>> +#endif
>
> Do we really support __ARCH__ == 6 and earlier?
>
> (There's an existing issue: The file name and the macro name are
> inconsistent.)
It is still used with build-many-glibc.py toolchail.
>
>> diff --git a/sysdeps/unix/sysv/linux/i386/dl-mmap.c b/sysdeps/unix/sysv/linux/i386/dl-mmap.c
>> new file mode 100644
>> index 00000000000..ab6f96300fb
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/i386/dl-mmap.c
>> @@ -0,0 +1,36 @@
>> +/* mmap wrapper for dynamic loader. Linux/i386 version.
>
>> +/* This mmap call is used to allocate some memory to backup assert() messages
>> + before TLS setup is done, so it can not use "call *%gs:SYSINFO_OFFSET"
>> + during startup in static PIE. */
>
> Typo: can[]not (multiple times in the patch)
Ack.
>
>> diff --git a/sysdeps/unix/sysv/linux/i386/dl-mmap.h b/sysdeps/unix/sysv/linux/i386/dl-mmap.h
>> new file mode 100644
>> index 00000000000..291f92ee14f
>> --- /dev/null
>> +++ b/sysdeps/unix/sysv/linux/i386/dl-mmap.h
>> @@ -0,0 +1,27 @@
>> +/* mmap wrapper for dynamic loader.
>
> Should say: i386 version
Ack.
>
>> diff --git a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
>> index 2fdd4af3eb7..a10dd30d12b 100644
>> --- a/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
>> +++ b/sysdeps/unix/sysv/linux/riscv/multiarch/Makefile
>> @@ -24,8 +24,16 @@ sysdep_routines += \
>> strncmp-vector \
>> # sysdep_routines
>>
>> +# Called during static library initialization, so turn stack-protection
>> +# off for non-shared builds.
>> +CFLAGS-memset-generic.o = $(no-stack-protector)
>> +CFLAGS-memset-generic.op = $(no-stack-protector)
>> +CFLAGS-memcpy-generic.o = $(no-stack-protector)
>> +CFLAGS-memcpy-generic.op = $(no-stack-protector)
>> +
>> CFLAGS-memcpy_noalignment.c += -mno-strict-align
>> # Called during static initialization
>> +CFLAGS-strlen-generic.c += $(no-stack-protector)
>> CFLAGS-memset-generic.c += $(no-stack-protector)
>> CFLAGS-memcpy-generic.c += $(no-stack-protector)
>> endif
>
> Isn't the first block of flags changes redundant given the existing
> CFLAGS-memset-generic.c setting?
Yes, I will remove then.
>
>> diff --git a/sysdeps/x86_64/multiarch/dl-symbol-redir-ifunc.h b/sysdeps/x86_64/multiarch/dl-symbol-redir-ifunc.h
>> index 1f3ca20307c..4d9cc5dd914 100644
>> --- a/sysdeps/x86_64/multiarch/dl-symbol-redir-ifunc.h
>> +++ b/sysdeps/x86_64/multiarch/dl-symbol-redir-ifunc.h
>> @@ -73,6 +73,28 @@ asm ("memmove = " HAVE_MEMMOVE_IFUNC_GENERIC);
>> asm ("mempcpy = " HAVE_MEMPCPY_IFUNC_GENERIC);
>> asm ("__mempcpy = " HAVE_MEMPCPY_IFUNC_GENERIC);
>>
>> +
>> +#if MINIMUM_X86_ISA_LEVEL >= 4
>
> Spurious blank line.
>
Ack.
> Thanks,
> Florian
>
@@ -33,6 +33,11 @@ routines := \
assert-perr \
# routines
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-__libc_assert_fail.o = $(no-stack-protector)
+CFLAGS-__libc_assert_fail.op = $(no-stack-protector)
+
tests := \
test-assert \
test-assert-2 \
@@ -278,6 +278,7 @@ tests-static-normal := \
# tests-static-normal
tests-static-internal := \
+ tst-assert-startup-static \
tst-dl-printf-static \
tst-dl_find_object-static \
tst-env-setuid-tunables \
@@ -296,6 +297,12 @@ tests-static-internal += \
# tests-static-internal
endif
+ifeq (yes,$(run-built-tests))
+tests-special += \
+ $(objpfx)tst-assert-startup-static.out \
+ # tests-special
+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
@@ -3670,3 +3677,14 @@ $(objpfx)tst-dl-debug-exclude.out: tst-dl-debug-exclude.sh \
$(objpfx)tst-recursive-tls > $@; \
$(evaluate-test)
endif
+
+CFLAGS-tst-assert-startup-static.c += $(no-stack-protector)
+LDFLAGS-tst-assert-startup-static = -Wl,-z,muldefs
+
+$(objpfx)tst-assert-startup-static.out: $(objpfx)tst-assert-startup-static
+ $(test-program-cmd-before-env) \
+ $(run-program-env) \
+ $< > $@ 2>&1; echo "status: $$?" >> $@; \
+ grep -q 'Fatal glibc error: tst-assert-startup-static' $@ \
+ && grep -q '^status: 134$$' $@; \
+ $(evaluate-test)
new file mode 100644
@@ -0,0 +1,40 @@
+/* Check if assert work during program 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/>. */
+
+#include <stdlib.h>
+#include <assert.h>
+
+/* The __tunables_init is called just before self-relocation and TLS setup,
+ and the __libc_assert_fail is used internally for assert() calls. */
+extern _Noreturn __typeof (__assert_fail) __libc_assert_fail;
+
+void __tunables_init (char **env)
+{
+/* The assert called by the loader/startup issues __libc_assert_fail instead
+ of __[]assert[_fail], and __libc_assert_fail does not perform the
+ translation (which would require additional handling to be called at this
+ point, like disable stack protection). So issue the internal routine
+ directly, instead of using assert here. */
+ __libc_assert_fail ("error", __FILE__, __LINE__, __func__);
+}
+
+int main (int argc, char *argv[])
+{
+ /* Fail with a different error code than abort. */
+ exit (EXIT_FAILURE);
+}
@@ -195,6 +195,11 @@ endif
CPPFLAGS += $(libio-mtsafe)
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-libc_fatal.o = $(no-stack-protector)
+CFLAGS-libc_fatal.op = $(no-stack-protector)
+
# Support for exception handling.
CFLAGS-fileops.c += -fexceptions
CFLAGS-fputc.c += -fexceptions
@@ -530,6 +530,11 @@ generated += \
tst-putenvmod.so \
# generated
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-abort.o = $(no-stack-protector)
+CFLAGS-abort.op = $(no-stack-protector)
+
CFLAGS-bsearch.c += $(uses-callbacks)
CFLAGS-qsort.c += $(uses-callbacks)
CFLAGS-system.c += -fexceptions
@@ -287,6 +287,7 @@ CFLAGS-wordcopy.c += $(no-stack-protector)
CFLAGS-strncmp.c += $(no-stack-protector)
CFLAGS-memset.c += $(no-stack-protector)
CFLAGS-strlen.c += $(no-stack-protector)
+CFLAGS-strchrnul.c += $(no-stack-protector)
ifeq ($(run-built-tests),yes)
$(objpfx)tst-svc-cmp.out: tst-svc.expect $(objpfx)tst-svc.out
@@ -19,6 +19,7 @@
#ifndef _DL_IFUNC_GENERIC_H
#define _DL_IFUNC_GENERIC_H
+asm ("memcpy = __memcpy_generic");
asm ("memset = __memset_generic");
asm ("strlen = __strlen_generic");
#ifndef SHARED
@@ -42,3 +42,7 @@
#endif
#include "../memcpy.S"
+
+#if IS_IN (rtld)
+strong_alias (memcpy, __memcpy_generic)
+#endif
new file mode 100644
@@ -0,0 +1,27 @@
+/* Symbol redirection for loader/static initialization code. Linux/ARM
+ 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_IFUNC_GENERIC_H
+#define _DL_IFUNC_GENERIC_H
+
+#ifndef __ARM_NEON__
+asm ("memcpy = __memcpy_vfp");
+#endif
+
+#endif
new file mode 100644
@@ -0,0 +1,34 @@
+/* mmap wrapper for dynamic loader.
+ 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_MMAP_H
+#define _DL_MMAP_H
+
+#include <sys/mman.h>
+
+/* This mmap call is used to allocate some memory to backup assert() messages
+ before TLS setup is done (which setup the thread pointer used by some ABIs
+ to issues syscalls). */
+
+static inline void *
+_dl_mmap (void *addr, size_t len, int prot, int flags)
+{
+ return __mmap (addr, len, prot, flags, -1, 0);
+}
+
+#endif
@@ -20,8 +20,10 @@
#define _DL_IFUNC_GENERIC_H
#ifndef SHARED
+asm ("memcpy = __memcpy_aligned");
asm ("memset = __memset_aligned");
asm ("memcmp = __memcmp_aligned");
+asm ("__strchrnul = __strchrnul_aligned");
asm ("strlen = __strlen_aligned");
asm ("memcpy = __memcpy_unaligned");
asm ("memmove = __memmove_unaligned");
@@ -16,7 +16,12 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
+/* Mark symbols hidden in static PIE for early self relocation to work. */
+#if BUILD_PIE_DEFAULT
+# pragma GCC visibility push(hidden)
+#endif
#include <dl-writev.h>
+#include <dl-mmap.h>
#include <assert.h>
#include <ldsodefs.h>
#include <setvmaname.h>
@@ -24,6 +29,7 @@
#include <stdio.h>
#include <sys/uio.h>
#include <unistd.h>
+#include <dl-symbol-redir-ifunc.h>
#ifdef FATAL_PREPARE_INCLUDE
#include FATAL_PREPARE_INCLUDE
@@ -113,9 +119,9 @@ __libc_message_impl (const char *vma_name, const char *fmt, ...)
total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
GLRO(dl_pagesize));
- struct abort_msg_s *buf = __mmap (NULL, total,
- PROT_READ | PROT_WRITE,
- MAP_ANON | MAP_PRIVATE, -1, 0);
+ struct abort_msg_s *buf = _dl_mmap (NULL, total,
+ PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE);
if (__glibc_likely (buf != MAP_FAILED))
{
buf->size = total;
@@ -11,4 +11,9 @@ sysdep_routines += memcpy-power7 memcpy-a2 memcpy-power6 memcpy-cell \
strchr-power7 strchr-ppc32 \
wordcopy-power7 wordcopy-ppc32 \
memmove-power7 memmove-ppc
+
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-strchrnul-ppc32.o = $(no-stack-protector)
+CFLAGS-strchrnul-ppc32.op = $(no-stack-protector)
endif
new file mode 100644
@@ -0,0 +1,27 @@
+/* Symbol rediretion for loader/static initialization code.
+ 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_IFUNC_GENERIC_H
+#define _DL_IFUNC_GENERIC_H
+
+#ifndef SHARED
+asm ("__mempcpy = __mempcpy_ppc");
+asm ("__strchrnul = __strchrnul_ppc");
+#endif
+
+#endif
@@ -21,5 +21,6 @@
asm ("memset = __memset_power8");
asm ("__mempcpy = __mempcpy_power7");
+asm ("__strchrnul = __strchrnul_power8");
#endif
@@ -40,3 +40,4 @@ endif
# Called during static initialization
CFLAGS-strncmp-ppc64.c += $(no-stack-protector)
+CFLAGS-strchrnul-ppc64.c += $(no-stack-protector)
@@ -258,6 +258,11 @@ routines_no_fortify += \
# routines_no_fortify
endif
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-strchrnul-c.o = $(no-stack-protector)
+CFLAGS-strchrnul-c.op = $(no-stack-protector)
+
ifeq ($(subdir),wcsmbs)
sysdep_routines += \
wcpcpy \
@@ -21,11 +21,15 @@
#include <ifunc-memset.h>
#include <ifunc-memcmp.h>
+#include <ifunc-strchrnul.h>
#define IFUNC_SYMBOL_STR1(s) #s
#define IFUNC_SYMBOL_STR(s) IFUNC_SYMBOL_STR1(s)
+#ifndef SHARED
asm ("memset = " IFUNC_SYMBOL_STR(MEMSET_DEFAULT));
asm ("memcmp = " IFUNC_SYMBOL_STR(MEMCMP_DEFAULT));
+asm ("__strchrnul = " IFUNC_SYMBOL_STR(STRCHRNUL_DEFAULT));
+#endif
#endif
new file mode 100644
@@ -0,0 +1,27 @@
+/* Zero byte detection, define whether to use stdbit.h
+ 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/>. */
+
+/* s390x support static-pie and the libgcc implementation for
+ __builtin_clzl/__builtin_ctzl might access extern data that is not marked
+ as hidden, which creates additiona GOT access that is used before
+ self-relocation. */
+#if __ARCH__ > 6
+# define HAVE_BITOPTS_WORKING 1
+#else
+# define HAVE_BITOPTS_WORKING 0
+#endif
@@ -19,6 +19,9 @@
#ifndef _DL_IFUNC_GENERIC_H
#define _DL_IFUNC_GENERIC_H
+#ifndef SHARED
asm ("memset = __memset_ultra1");
+asm ("memcpy = __memcpy_ultra1");
+#endif
#endif
@@ -19,6 +19,9 @@
#ifndef _DL_IFUNC_GENERIC_H
#define _DL_IFUNC_GENERIC_H
+#ifndef SHARED
asm ("memset = __memset_ultra1");
+asm ("memcpy = __memcpy_ultra1");
+#endif
#endif
@@ -114,6 +114,11 @@ sysdep_routines += \
xstat \
xstat64 \
# sysdep_routines
+#
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-setvmaname.o = $(no-stack-protector)
+CFLAGS-setvmaname.op = $(no-stack-protector)
CFLAGS-gethostid.c = -fexceptions
CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
@@ -459,6 +464,13 @@ sysdep_routines += \
raise_direct \
# sysdep_routines
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-raise.o = $(no-stack-protector)
+CFLAGS-raise.op = $(no-stack-protector)
+CFLAGS-raise_direct.o = $(no-stack-protector)
+CFLAGS-raise_direct.op = $(no-stack-protector)
+
tests-special += \
$(objpfx)tst-signal-numbers.out \
# tests-special
@@ -28,3 +28,17 @@ ifeq ($(subdir),rt)
librt-routines += sysdep
librt-shared-only-routines += sysdep
endif
+
+ifeq ($(subdir),elf)
+sysdep_routines += \
+ dl-mmap \
+ dl-writev \
+ # sysdep-routines
+
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-dl-mmap.o = $(no-stack-protector)
+CFLAGS-dl-mmap.op = $(no-stack-protector)
+CFLAGS-dl-writev.o = $(no-stack-protector)
+CFLAGS-dl-writev.op = $(no-stack-protector)
+endif
new file mode 100644
@@ -0,0 +1,36 @@
+/* mmap wrapper for dynamic loader. Linux/i386 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/>. */
+
+/* This mmap call is used to allocate some memory to backup assert() messages
+ before TLS setup is done, so it can not use "call *%gs:SYSINFO_OFFSET"
+ during startup in static PIE. */
+#if BUILD_PIE_DEFAULT
+# define I386_USE_SYSENTER 0
+#endif
+
+#include <sys/mman.h>
+#include <dl-mmap.h>
+#include <mmap_internal.h>
+#include <sysdep.h>
+
+void *
+_dl_mmap (void *addr, size_t len, int prot, int flags)
+{
+ return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, -1, 0);
+}
+
new file mode 100644
@@ -0,0 +1,27 @@
+/* mmap wrapper for dynamic loader.
+ 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_MMAP_H
+#define _DL_MMAP_H
+
+/* i386 requires out-of-line implementation because it sets
+ I386_USE_SYSENTER to 0 to avoid use the vDSO. */
+void * _dl_mmap (void *addr, size_t len, int prot, int flags)
+ attribute_hidden;
+
+#endif
new file mode 100644
@@ -0,0 +1,32 @@
+/* writev wrapper for the dynamic linker. Linux/i386 version.
+ Copyright (C) 2013-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 writev call is used to assert() before TLS setup is done, so it can
+ not use "call *%gs:SYSINFO_OFFSET" during startup in static PIE. */
+#if BUILD_PIE_DEFAULT
+# define I386_USE_SYSENTER 0
+#endif
+
+#include <dl-writev.h>
+#include <sysdep.h>
+
+ssize_t
+_dl_writev (int fd, const struct iovec *iov, size_t niov)
+{
+ return INTERNAL_SYSCALL_CALL (writev, fd, iov, niov);
+}
@@ -16,9 +16,14 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#if BUILD_PIE_DEFAULT
-/* Can't use "call *%gs:SYSINFO_OFFSET" during startup in static PIE. */
-# define I386_USE_SYSENTER 0
-#endif
+#ifndef _DL_WRITEV_H
+#define _DL_WRITEV_H
-#include <sysdeps/unix/sysv/linux/dl-writev.h>
+#include <sys/uio.h>
+
+/* i386 requires out-of-line implementation because it sets
+ I386_USE_SYSENTER to 0 to avoid use the vDSO. */
+ssize_t _dl_writev (int fd, const struct iovec *iov, size_t niov)
+ attribute_hidden;
+
+#endif
new file mode 100644
@@ -0,0 +1,26 @@
+/* Internal function to send a signal to itself. Linux/i386 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/>. */
+
+/* This is called from abort() (issued by assert()) before TLS setup is done,
+ so it can not use "call *%gs:SYSINFO_OFFSET" during startup in static
+ PIE. */
+#if BUILD_PIE_DEFAULT
+# define I386_USE_SYSENTER 0
+#endif
+
+#include <sysdeps/unix/sysv/linux/raise_direct.c>
@@ -24,8 +24,16 @@ sysdep_routines += \
strncmp-vector \
# sysdep_routines
+# Called during static library initialization, so turn stack-protection
+# off for non-shared builds.
+CFLAGS-memset-generic.o = $(no-stack-protector)
+CFLAGS-memset-generic.op = $(no-stack-protector)
+CFLAGS-memcpy-generic.o = $(no-stack-protector)
+CFLAGS-memcpy-generic.op = $(no-stack-protector)
+
CFLAGS-memcpy_noalignment.c += -mno-strict-align
# Called during static initialization
+CFLAGS-strlen-generic.c += $(no-stack-protector)
CFLAGS-memset-generic.c += $(no-stack-protector)
CFLAGS-memcpy-generic.c += $(no-stack-protector)
endif
@@ -73,6 +73,28 @@ asm ("memmove = " HAVE_MEMMOVE_IFUNC_GENERIC);
asm ("mempcpy = " HAVE_MEMPCPY_IFUNC_GENERIC);
asm ("__mempcpy = " HAVE_MEMPCPY_IFUNC_GENERIC);
+
+#if MINIMUM_X86_ISA_LEVEL >= 4
+# define HAVE_STRCHRNUL_IFUNC_GENERIC "__strchrnul_evex"
+#elif MINIMUM_X86_ISA_LEVEL == 3
+# define HAVE_STRCHRNUL_IFUNC_GENERIC "__strchrnul_avx2"
+#else
+# define HAVE_STRCHRNUL_IFUNC_GENERIC "__strchrnul_sse2"
+#endif
+
+asm ("__strchrnul = " HAVE_STRCHRNUL_IFUNC_GENERIC);
+
+
+#if MINIMUM_X86_ISA_LEVEL >= 4
+# define HAVE_STRLEN_IFUNC_GENERIC "__strlen_evex"
+#elif MINIMUM_X86_ISA_LEVEL == 3
+# define HAVE_STRLEN_IFUNC_GENERIC "__strlen_avx2"
+#else
+# define HAVE_STRLEN_IFUNC_GENERIC "__strlen_sse2"
+#endif
+
+asm ("strlen = " HAVE_STRLEN_IFUNC_GENERIC);
+
#endif /* SHARED */
#endif