@@ -3169,3 +3169,14 @@ tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
# Any shared object should do.
tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so
+
+# These rules link (without libc.so) and run the special
+# elf/tst-nolink-libc test if a port adds it to the $(tests) or
+# $(tests-internals) variables. The test is always run directly, not
+# under the dynamic linker.
+$(objpfx)tst-nolink-libc: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so
+ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \
+ -Wl,--dynamic-link=$(objpfx)ld.so $(objpfx)ld.so
+CFLAGS-tst-nolink-libc.c += $(no-stack-protector)
+$(objpfx)tst-nolink-libc.out: $(objpfx)tst-nolink-libc $(objpfx)ld.so
+ $< > $@ 2>&1; $(evaluate-test)
@@ -82,6 +82,11 @@ __rtld_malloc_init_real (struct link_map *main_map)
rtld relocation (which enables RELRO, after which the pointer
variables cannot be written to). */
+ if (GL (dl_ns)[LM_ID_BASE].libc_map == NULL)
+ /* Nothing is against libc.so, which means that there is no malloc
+ implementation available. */
+ return;
+
struct r_found_version version;
version.name = symbol_version_string (libc, GLIBC_2_0);
version.hidden = 0;
@@ -35,6 +35,10 @@ __rtld_mutex_init (void)
constructor while holding loader locks. */
struct link_map *libc_map = GL (dl_ns)[LM_ID_BASE].libc_map;
+ if (libc_map == NULL)
+ /* Special case: the program links against ld.so, but not libc.so,
+ so the full locking implementation is not available. */
+ return;
const ElfW(Sym) *sym
= _dl_lookup_direct (libc_map, "pthread_mutex_lock",
@@ -652,6 +652,8 @@ install-bin += \
# install-bin
$(objpfx)pldd: $(objpfx)xmalloc.o
+
+tests-internal += tst-nolink-libc
endif
ifeq ($(subdir),rt)
@@ -1,5 +1,8 @@
ifeq ($(subdir),elf)
sysdep-rtld-routines += aeabi_read_tp libc-do-syscall
+# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses
+# an undefined reference to __libc_do_syscall.
+CFLAGS-tst-nolink-libc.c += -marm
endif
ifeq ($(subdir),misc)
new file mode 100644
@@ -0,0 +1,25 @@
+/* Test program not linked against libc.so and not using any glibc functions.
+ Copyright (C) 2024 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 <sysdep.h>
+
+void
+_start (void)
+{
+ INTERNAL_SYSCALL_CALL (exit_group, 0);
+}