diff --git a/elf/Makefile b/elf/Makefile index e3db643a30..8f11c04d7e 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -3372,3 +3372,20 @@ endef $(foreach m,$(modules-semantic-interposition),\ $(eval $(call enable-semantic-interposition,$(m)))) endif + +# These rules link and run the special elf/tst-nolink-libc-* tests if +# a port adds them to the tests variables. Neither test variant is +# linked against libc.so, but tst-nolink-libc-1 is linked against +# ld.so. The test is always run directly, not under the dynamic +# linker. +CFLAGS-tst-nolink-libc.c += $(no-stack-protector) +$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so + $(LINK.o) -nostdlib -nostartfiles -o $@ $< \ + -Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so +$(objpfx)tst-nolink-libc-1.out: $(objpfx)tst-nolink-libc-1 $(objpfx)ld.so + $< > $@ 2>&1; $(evaluate-test) +$(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o + $(LINK.o) -nostdlib -nostartfiles -o $@ $< \ + -Wl,--dynamic-linker=$(objpfx)ld.so +$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so + $< > $@ 2>&1; $(evaluate-test) diff --git a/elf/rtld.c b/elf/rtld.c index 9c51eef79d..f32058bba6 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2242,25 +2242,25 @@ dl_main (const ElfW(Phdr) *phdr, _rtld_main_check (main_map, _dl_argv[0]); - /* Now we have all the objects loaded. Relocate them all except for - the dynamic linker itself. We do this in reverse order so that copy - relocs of earlier objects overwrite the data written by later - objects. We do not re-relocate the dynamic linker itself in this - loop because that could result in the GOT entries for functions we - call being changed, and that would break us. It is safe to relocate - the dynamic linker out of order because it has no copy relocations. - Likewise for libc, which is relocated early to ensure that IFUNC - resolvers in libc work. */ + /* Now we have all the objects loaded. */ int consider_profiling = GLRO(dl_profile) != NULL; /* If we are profiling we also must do lazy reloaction. */ GLRO(dl_lazy) |= consider_profiling; + /* If libc.so has been loaded, relocate it early, after the dynamic + loader itself. The initial self-relocation of ld.so should be + sufficient for IFUNC resolvers in libc.so. */ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) - _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, - GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, - GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, + GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, + GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); + rtld_timer_accum (&relocate_time, start); + } RTLD_TIMING_VAR (start); rtld_timer_start (&start); @@ -2283,9 +2283,8 @@ dl_main (const ElfW(Phdr) *phdr, /* Also allocated with the fake malloc(). */ l->l_free_initfini = 0; - if (l != &_dl_rtld_map) - _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0, - consider_profiling); + _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0, + consider_profiling); /* Add object to slot information data if necessasy. */ if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called) @@ -2323,27 +2322,22 @@ dl_main (const ElfW(Phdr) *phdr, /* Set up the object lookup structures. */ _dl_find_object_init (); - /* Likewise for the locking implementation. */ - __rtld_mutex_init (); + /* If libc.so was loaded, relocate ld.so against it. Complete ld.so + initialization with mutex symbols from libc.so and malloc symbols + from the global scope. */ + if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + _dl_relocate_object_no_relro (&_dl_rtld_map, main_map->l_scope, 0, 0); + rtld_timer_accum (&relocate_time, start); - /* Re-relocate ourselves with user-controlled symbol definitions. */ + __rtld_mutex_init (); + __rtld_malloc_init_real (main_map); + } - { - RTLD_TIMING_VAR (start); - rtld_timer_start (&start); - - _dl_relocate_object_no_relro (&_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 (_dl_rtld_map.l_relro_size != 0) - _dl_protect_relro (&_dl_rtld_map); - - rtld_timer_accum (&relocate_time, start); - } + /* All ld.so initialization is complete. Apply RELRO. */ + _dl_protect_relro (&_dl_rtld_map); /* Relocation is complete. Perform early libc initialization. This is the initial libc, even if audit modules have been loaded with diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index eb9c697ce5..4e7044f12f 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -652,7 +652,15 @@ install-bin += \ # install-bin $(objpfx)pldd: $(objpfx)xmalloc.o + +test-internal-extras += tst-nolink-libc +ifeq ($(run-built-tests),yes) +tests-special += \ + $(objpfx)tst-nolink-libc-1.out \ + $(objpfx)tst-nolink-libc-2.out \ + # tests-special endif +endif # $(subdir) == elf ifeq ($(subdir),rt) CFLAGS-mq_send.c += -fexceptions diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile index a73c897f43..e73ce4f811 100644 --- a/sysdeps/unix/sysv/linux/arm/Makefile +++ b/sysdeps/unix/sysv/linux/arm/Makefile @@ -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) diff --git a/sysdeps/unix/sysv/linux/tst-nolink-libc.c b/sysdeps/unix/sysv/linux/tst-nolink-libc.c new file mode 100644 index 0000000000..817f37784b --- /dev/null +++ b/sysdeps/unix/sysv/linux/tst-nolink-libc.c @@ -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 + . */ + +#include + +void +_start (void) +{ + INTERNAL_SYSCALL_CALL (exit_group, 0); +}