diff options
author | Florian Weimer <fweimer@redhat.com> | 2021-12-28 22:52:56 +0100 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2021-12-28 22:52:56 +0100 |
commit | 5d28a8962dcb6ec056b81d730e3c6fb57185a210 (patch) | |
tree | 3d714aaef575deba322fa5a1e29c76c6f96dc850 /elf/dl-find_object.h | |
parent | 83b8d5027d2f80c4603cd706da95d6c9a09a4e16 (diff) | |
download | glibc-5d28a8962dcb6ec056b81d730e3c6fb57185a210.tar.gz glibc-5d28a8962dcb6ec056b81d730e3c6fb57185a210.tar.xz glibc-5d28a8962dcb6ec056b81d730e3c6fb57185a210.zip |
elf: Add _dl_find_object function
It can be used to speed up the libgcc unwinder, and the internal _dl_find_dso_for_object function (which is used for caller identification in dlopen and related functions, and in dladdr). _dl_find_object is in the internal namespace due to bug 28503. If libgcc switches to _dl_find_object, this namespace issue will be fixed. It is located in libc for two reasons: it is necessary to forward the call to the static libc after static dlopen, and there is a link ordering issue with -static-libgcc and libgcc_eh.a because libc.so is not a linker script that includes ld.so in the glibc build tree (so that GCC's internal -lc after libgcc_eh.a does not pick up ld.so). It is necessary to do the i386 customization in the sysdeps/x86/bits/dl_find_object.h header shared with x86-64 because otherwise, multilib installations are broken. The implementation uses software transactional memory, as suggested by Torvald Riegel. Two copies of the supporting data structures are used, also achieving full async-signal-safety. Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Diffstat (limited to 'elf/dl-find_object.h')
-rw-r--r-- | elf/dl-find_object.h | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/elf/dl-find_object.h b/elf/dl-find_object.h new file mode 100644 index 0000000000..f899905e09 --- /dev/null +++ b/elf/dl-find_object.h @@ -0,0 +1,115 @@ +/* Locating objects in the process image. ld.so implementation. + Copyright (C) 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 + <https://www.gnu.org/licenses/>. */ + +#ifndef _DL_FIND_EH_FRAME_H +#define _DL_FIND_EH_FRAME_H + +#include <assert.h> +#include <dlfcn.h> +#include <ldsodefs.h> +#include <stdbool.h> +#include <stdint.h> + +/* Internal version of struct dl_find_object. Does not include the + (yet unused) flags member. We need to make a copy of data also in + struct link_map to support non-contiguous mappings, and to support + software transactional memory (the link map is not covered by + transactions). */ +struct dl_find_object_internal +{ + uintptr_t map_start; + uintptr_t map_end; /* Set to map_start by dlclose. */ + struct link_map *map; /* Set to NULL by dlclose. */ + void *eh_frame; +#if DLFO_STRUCT_HAS_EH_DBASE + void *eh_dbase; +#endif +#if DLFO_STRUCT_HAS_EH_COUNT + int eh_count; +#endif +}; + +static inline void +_dl_find_object_to_external (struct dl_find_object_internal *internal, + struct dl_find_object *external) +{ + external->dlfo_flags = 0; + external->dlfo_map_start = (void *) internal->map_start; + external->dlfo_map_end = (void *) internal->map_end; + external->dlfo_link_map = internal->map; + external->dlfo_eh_frame = internal->eh_frame; +# if DLFO_STRUCT_HAS_EH_DBASE + external->dlfo_eh_dbase = internal->eh_dbase; +# endif +# if DLFO_STRUCT_HAS_EH_COUNT + external->dlfo_eh_count = internal->eh_count; +# endif +} + +/* Extract the object location data from a link map and writes it to + *RESULT. */ +static void __attribute__ ((unused)) +_dl_find_object_from_map (struct link_map *l, + struct dl_find_object_internal *result) +{ + result->map_start = (uintptr_t) l->l_map_start; + result->map_end = (uintptr_t) l->l_map_end; + result->map = l; + +#if DLFO_STRUCT_HAS_EH_DBASE + result->eh_dbase = (void *) l->l_info[DT_PLTGOT]; +#endif + + for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum; + ph < ph_end; ++ph) + if (ph->p_type == DLFO_EH_SEGMENT_TYPE) + { + result->eh_frame = (void *) (ph->p_vaddr + l->l_addr); +#if DLFO_STRUCT_HAS_EH_COUNT + result->eh_count = ph->p_memsz / 8; +#endif + return; + } + + /* Object has no exception handling segment. */ + result->eh_frame = NULL; +#if DLFO_STRUCT_HAS_EH_COUNT + result->eh_count = 0; +#endif +} + +/* Called by the dynamic linker to set up the data structures for the + initially loaded objects. This creates a few persistent + allocations, so it should be called with the minimal malloc. */ +void _dl_find_object_init (void) attribute_hidden; + +/* Called by dlopen/dlmopen to add new objects to the DWARF EH frame + data structures. NEW_MAP is the dlopen'ed link map. Link maps on + the l_next list are added if l_object_processed is 0. Needs to + be protected by loader write lock. Returns true on success, false + on malloc failure. */ +bool _dl_find_object_update (struct link_map *new_map) attribute_hidden; + +/* Called by dlclose to remove the link map from the DWARF EH frame + data structures. Needs to be protected by loader write lock. */ +void _dl_find_object_dlclose (struct link_map *l) attribute_hidden; + +/* Called from __libc_freeres to deallocate malloc'ed memory. */ +void _dl_find_object_freeres (void) attribute_hidden; + +#endif /* _DL_FIND_OBJECT_H */ |