diff --git a/elf/Makefile b/elf/Makefile
index fda796f6d5..3a1cb72955 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -453,6 +453,9 @@ tests += \
tst-recursive-tls \
tst-relsort1 \
tst-ro-dynamic \
+ tst-rtld-no-malloc \
+ tst-rtld-no-malloc-audit \
+ tst-rtld-no-malloc-preload \
tst-rtld-run-static \
tst-single_threaded \
tst-single_threaded-pthread \
@@ -3160,3 +3163,9 @@ tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so
tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so
$(objpfx)tst-dlopen-auditdup.out: \
$(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so
+
+# Reuse an audit module which provides ample debug logging.
+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
diff --git a/elf/dl-support.c b/elf/dl-support.c
index 451932dd03..ee590edf93 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -338,8 +338,7 @@ _dl_non_dynamic_init (void)
call_function_static_weak (_dl_find_object_init);
/* Setup relro on the binary itself. */
- if (_dl_main_map.l_relro_size != 0)
- _dl_protect_relro (&_dl_main_map);
+ _dl_protect_relro (&_dl_main_map);
}
#ifdef DL_SYSINFO_IMPLEMENTATION
diff --git a/elf/rtld.c b/elf/rtld.c
index dcd0f4cdc6..b8cc3f605f 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -2321,30 +2321,27 @@ dl_main (const ElfW(Phdr) *phdr,
/* Make sure no new search directories have been added. */
assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
- /* Re-relocate ourselves with user-controlled symbol definitions.
-
- We must do this after TLS initialization in case after this
- re-relocation, we might call a user-supplied function
- (e.g. calloc from _dl_relocate_object) that uses TLS data. */
-
/* Set up the object lookup structures. */
_dl_find_object_init ();
- /* The malloc implementation has been relocated, so resolving
- its symbols (and potentially calling IFUNC resolvers) is safe
- at this point. */
- __rtld_malloc_init_real (main_map);
-
/* Likewise for the locking implementation. */
__rtld_mutex_init ();
+ /* Re-relocate ourselves with user-controlled symbol definitions. */
+
{
RTLD_TIMING_VAR (start);
rtld_timer_start (&start);
- /* Mark the link map as not yet relocated again. */
- GL(dl_rtld_map).l_relocated = 0;
- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
+
+ /* The malloc implementation has been relocated, so resolving
+ its symbols (and potentially calling IFUNC resolvers) is safe
+ at this point. */
+ __rtld_malloc_init_real (main_map);
+
+ if (GL(dl_rtld_map).l_relro_size != 0)
+ _dl_protect_relro (&GL(dl_rtld_map));
rtld_timer_accum (&relocate_time, start);
}
diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c
new file mode 100644
index 0000000000..a028377ad1
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-audit.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c
new file mode 100644
index 0000000000..a028377ad1
--- /dev/null
+++ b/elf/tst-rtld-no-malloc-preload.c
@@ -0,0 +1 @@
+#include "tst-rtld-no-malloc.c"
diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c
new file mode 100644
index 0000000000..5f24d4bd72
--- /dev/null
+++ b/elf/tst-rtld-no-malloc.c
@@ -0,0 +1,76 @@
+/* Test that program loading does not call malloc.
+ 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
+ . */
+
+
+#include
+#include
+
+static void
+print (const char *s)
+{
+ const char *end = s + strlen (s);
+ while (s < end)
+ {
+ ssize_t ret = write (STDOUT_FILENO, s, end - s);
+ if (ret <= 0)
+ _exit (2);
+ s += ret;
+ }
+}
+
+static void __attribute__ ((noreturn))
+unexpected_call (const char *function)
+{
+ print ("error: unexpected call to ");
+ print (function);
+ print ("\n");
+ _exit (1);
+}
+
+/* These are the malloc functions implement in elf/dl-minimal.c. */
+
+void
+free (void *ignored)
+{
+ unexpected_call ("free");
+}
+
+void *
+calloc (size_t ignored1, size_t ignored2)
+{
+ unexpected_call ("calloc");
+}
+
+void *
+malloc (size_t ignored)
+{
+ unexpected_call ("malloc");
+}
+
+void *
+realloc (void *ignored1, size_t ignored2)
+{
+ unexpected_call ("realloc");
+}
+
+int
+main (void)
+{
+ /* Do not use the test wrapper, to avoid spurious malloc calls from it. */
+ return 0;
+}