From 41348211d4b9a1fa0183fb6358efb1e345b09a26 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Wed, 13 Oct 2021 09:49:34 -0300 Subject: elf: Fix dynamic-link.h usage on rtld.c The 4af6982e4c fix does not fully handle RTLD_BOOTSTRAP usage on rtld.c due two issues: 1. RTLD_BOOTSTRAP is also used on dl-machine.h on various architectures and it changes the semantics of various machine relocation functions. 2. The elf_get_dynamic_info() change was done sideways, previously to 490e6c62aa get-dynamic-info.h was included by the first dynamic-link.h include *without* RTLD_BOOTSTRAP being defined. It means that the code within elf_get_dynamic_info() that uses RTLD_BOOTSTRAP is in fact unused. To fix 1. this patch now includes dynamic-link.h only once with RTLD_BOOTSTRAP defined. The ELF_DYNAMIC_RELOCATE call will now have the relocation fnctions with the expected semantics for the loader. And to fix 2. part of 4af6982e4c is reverted (the check argument elf_get_dynamic_info() is not required) and the RTLD_BOOTSTRAP pieces are removed. To reorganize the includes the static TLS definition is moved to its own header to avoid a circular dependency (it is defined on dynamic-link.h and dl-machine.h requires it at same time other dynamic-link.h definition requires dl-machine.h defitions). Also ELF_MACHINE_NO_REL, ELF_MACHINE_NO_RELA, and ELF_MACHINE_PLT_REL are moved to its own header. Only ancient ABIs need special values (arm, i386, and mips), so a generic one is used as default. The powerpc Elf64_FuncDesc is also moved to its own header, since csu code required its definition (which would require either include elf/ folder or add a full path with elf/). Checked on x86_64, i686, aarch64, armhf, powerpc64, powerpc32, and powerpc64le. Reviewed-by: Szabolcs Nagy (cherry picked from commit d6d89608ac8cf2b37c75debad1fff653f6939f90) Resolved conflicts: elf/rtld.c --- elf/dl-load.c | 2 +- elf/dl-reloc-static-pie.c | 2 +- elf/dl-static-tls.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++ elf/dynamic-link.h | 33 +----------------------------- elf/get-dynamic-info.h | 25 +++++++---------------- elf/rtld.c | 23 ++++++++++----------- elf/setup-vdso.h | 2 +- 7 files changed, 73 insertions(+), 65 deletions(-) create mode 100644 elf/dl-static-tls.h (limited to 'elf') diff --git a/elf/dl-load.c b/elf/dl-load.c index eea06629a9..fb3da5aa56 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -1296,7 +1296,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, if (l->l_ld != 0) l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr); - elf_get_dynamic_info (l, false); + elf_get_dynamic_info (l); /* Make sure we are not dlopen'ing an object that has the DF_1_NOOPEN flag set, or a PIE object. */ diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c index f323b4dd0d..ababafcf98 100644 --- a/elf/dl-reloc-static-pie.c +++ b/elf/dl-reloc-static-pie.c @@ -52,7 +52,7 @@ _dl_relocate_static_pie (void) break; } - elf_get_dynamic_info (main_map, false); + elf_get_dynamic_info (main_map); # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC ELF_MACHINE_BEFORE_RTLD_RELOC (main_map, main_map->l_info); diff --git a/elf/dl-static-tls.h b/elf/dl-static-tls.h new file mode 100644 index 0000000000..730924fc01 --- /dev/null +++ b/elf/dl-static-tls.h @@ -0,0 +1,51 @@ +/* Inline functions for dynamic linking. + Copyright (C) 1995-2021 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 + . */ + +#ifndef _DL_STATIC_TLS_H +#define _DL_STATIC_TLS_H + +/* This macro is used as a callback from elf_machine_rel{a,} when a + static TLS reloc is about to be performed. Since (in dl-load.c) we + permit dynamic loading of objects that might use such relocs, we + have to check whether each use is actually doable. If the object + whose TLS segment the reference resolves to was allocated space in + the static TLS block at startup, then it's ok. Otherwise, we make + an attempt to allocate it in surplus space on the fly. If that + can't be done, we fall back to the error that DF_STATIC_TLS is + intended to produce. */ +#define HAVE_STATIC_TLS(map, sym_map) \ + (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET \ + && ((sym_map)->l_tls_offset \ + != FORCED_DYNAMIC_TLS_OFFSET), 1)) + +#define CHECK_STATIC_TLS(map, sym_map) \ + do { \ + if (!HAVE_STATIC_TLS (map, sym_map)) \ + _dl_allocate_static_tls (sym_map); \ + } while (0) + +#define TRY_STATIC_TLS(map, sym_map) \ + (__builtin_expect ((sym_map)->l_tls_offset \ + != FORCED_DYNAMIC_TLS_OFFSET, 1) \ + && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \ + || _dl_try_allocate_static_tls (sym_map, true) == 0)) + +int _dl_try_allocate_static_tls (struct link_map *map, bool optional) + attribute_hidden; + +#endif diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index 21cdfc88bb..ac4cc70dea 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -16,35 +16,7 @@ License along with the GNU C Library; if not, see . */ -/* This macro is used as a callback from elf_machine_rel{a,} when a - static TLS reloc is about to be performed. Since (in dl-load.c) we - permit dynamic loading of objects that might use such relocs, we - have to check whether each use is actually doable. If the object - whose TLS segment the reference resolves to was allocated space in - the static TLS block at startup, then it's ok. Otherwise, we make - an attempt to allocate it in surplus space on the fly. If that - can't be done, we fall back to the error that DF_STATIC_TLS is - intended to produce. */ -#define HAVE_STATIC_TLS(map, sym_map) \ - (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET \ - && ((sym_map)->l_tls_offset \ - != FORCED_DYNAMIC_TLS_OFFSET), 1)) - -#define CHECK_STATIC_TLS(map, sym_map) \ - do { \ - if (!HAVE_STATIC_TLS (map, sym_map)) \ - _dl_allocate_static_tls (sym_map); \ - } while (0) - -#define TRY_STATIC_TLS(map, sym_map) \ - (__builtin_expect ((sym_map)->l_tls_offset \ - != FORCED_DYNAMIC_TLS_OFFSET, 1) \ - && (__builtin_expect ((sym_map)->l_tls_offset != NO_TLS_OFFSET, 1) \ - || _dl_try_allocate_static_tls (sym_map, true) == 0)) - -int _dl_try_allocate_static_tls (struct link_map *map, bool optional) - attribute_hidden; - +#include #include #ifdef RESOLVE_MAP @@ -91,9 +63,6 @@ elf_machine_lazy_rel (struct link_map *map, struct r_scope_elem *scope[], # endif #endif -#include - - #ifdef RESOLVE_MAP # if defined RTLD_BOOTSTRAP || defined STATIC_PIE_BOOTSTRAP diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index d169099fbc..1ac0663d1f 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -22,10 +22,11 @@ #define _GET_DYNAMIC_INFO_H #include +#include #include static inline void __attribute__ ((unused, always_inline)) -elf_get_dynamic_info (struct link_map *l, bool check) +elf_get_dynamic_info (struct link_map *l) { #if __ELF_NATIVE_CLASS == 32 typedef Elf32_Word d_tag_utype; @@ -33,7 +34,7 @@ elf_get_dynamic_info (struct link_map *l, bool check) typedef Elf64_Xword d_tag_utype; #endif -#if !defined RTLD_BOOTSTRAP && !defined STATIC_PIE_BOOTSTRAP +#ifndef STATIC_PIE_BOOTSTRAP if (l->l_ld == NULL) return; #endif @@ -111,21 +112,10 @@ elf_get_dynamic_info (struct link_map *l, bool check) if (info[DT_REL] != NULL) assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); #endif -#ifdef RTLD_BOOTSTRAP - if (check) - { - /* Only the bind now flags are allowed. */ - assert (info[VERSYMIDX (DT_FLAGS_1)] == NULL - || (info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val & ~DF_1_NOW) == 0); - /* Flags must not be set for ld.so. */ - assert (info[DT_FLAGS] == NULL - || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0); -# ifdef STATIC_PIE_BOOTSTRAP - assert (info[DT_RUNPATH] == NULL); - assert (info[DT_RPATH] == NULL); -# endif - } -#else +#ifdef STATIC_PIE_BOOTSTRAP + assert (info[DT_RUNPATH] == NULL); + assert (info[DT_RPATH] == NULL); +#endif if (info[DT_FLAGS] != NULL) { /* Flags are used. Translate to the old form where available. @@ -163,7 +153,6 @@ elf_get_dynamic_info (struct link_map *l, bool check) if (info[DT_RUNPATH] != NULL) /* If both RUNPATH and RPATH are given, the latter is ignored. */ info[DT_RPATH] = NULL; -#endif } #endif diff --git a/elf/rtld.c b/elf/rtld.c index 23207112a1..0a4c3d4fed 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -32,7 +32,6 @@ #include #include #include -#include "dynamic-link.h" #include #include #include @@ -50,9 +49,18 @@ #include #include #include +#include #include +/* This #define produces dynamic linking inline functions for + bootstrap relocation instead of general-purpose relocation. + Since ld.so must not have any undefined symbols the result + is trivial: always the map of ld.so itself. */ +#define RTLD_BOOTSTRAP +#define RESOLVE_MAP(map, scope, sym, version, flags) map +#include "dynamic-link.h" + /* Only enables rtld profiling for architectures which provides non generic hp-timing support. The generic support requires either syscall (clock_gettime), which will incur in extra overhead on loading time. @@ -507,15 +515,6 @@ _dl_start_final (void *arg, struct dl_start_final_info *info) # define bootstrap_map info.l #endif - /* This #define produces dynamic linking inline functions for - bootstrap relocation instead of general-purpose relocation. - Since ld.so must not have any undefined symbols the result - is trivial: always the map of ld.so itself. */ -#define RTLD_BOOTSTRAP -#define RESOLVE_MAP(map, scope, sym, version, flags) map -#include "get-dynamic-info.h" -#include "dynamic-link.h" - static ElfW(Addr) __attribute_used__ _dl_start (void *arg) { @@ -549,7 +548,7 @@ _dl_start (void *arg) /* Read our own dynamic section and fill in the info array. */ bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic (); bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION; - elf_get_dynamic_info (&bootstrap_map, true); + elf_get_dynamic_info (&bootstrap_map); #if NO_TLS_OFFSET != 0 bootstrap_map.l_tls_offset = NO_TLS_OFFSET; @@ -1617,7 +1616,7 @@ dl_main (const ElfW(Phdr) *phdr, if (! rtld_is_main) { /* Extract the contents of the dynamic section for easy access. */ - elf_get_dynamic_info (main_map, false); + elf_get_dynamic_info (main_map); /* If the main map is libc.so, update the base namespace to refer to this map. If libc.so is loaded later, this happens diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h index 6fdffafcca..f44748bc98 100644 --- a/elf/setup-vdso.h +++ b/elf/setup-vdso.h @@ -64,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)), l->l_map_end += l->l_addr; l->l_text_end += l->l_addr; l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr); - elf_get_dynamic_info (l, false); + elf_get_dynamic_info (l); _dl_setup_hash (l); l->l_relocated = 1; -- cgit v1.2.1