diff options
Diffstat (limited to 'libc/elf')
-rw-r--r-- | libc/elf/Makefile | 9 | ||||
-rw-r--r-- | libc/elf/dl-hwcaps.c | 279 | ||||
-rw-r--r-- | libc/elf/dl-load.c | 16 | ||||
-rw-r--r-- | libc/elf/dl-open.c | 4 | ||||
-rw-r--r-- | libc/elf/dl-runtime.c | 4 | ||||
-rw-r--r-- | libc/elf/dl-support.c | 26 | ||||
-rw-r--r-- | libc/elf/dl-sysdep.c | 261 | ||||
-rw-r--r-- | libc/elf/dl-version.c | 5 | ||||
-rw-r--r-- | libc/elf/do-rel.h | 8 | ||||
-rw-r--r-- | libc/elf/dynamic-link.h | 149 | ||||
-rw-r--r-- | libc/elf/get-dynamic-info.h | 161 | ||||
-rw-r--r-- | libc/elf/rtld.c | 107 | ||||
-rw-r--r-- | libc/elf/setup-vdso.h | 121 |
13 files changed, 598 insertions, 552 deletions
diff --git a/libc/elf/Makefile b/libc/elf/Makefile index b3b950be4..276581812 100644 --- a/libc/elf/Makefile +++ b/libc/elf/Makefile @@ -19,6 +19,8 @@ subdir := elf +include ../Makeconfig + headers = elf.h bits/elfclass.h link.h bits/link.h routines = $(dl-routines) dl-support dl-iteratephdr \ dl-addr enbl-secure dl-profstub \ @@ -26,10 +28,13 @@ routines = $(dl-routines) dl-support dl-iteratephdr \ # The core dynamic linking functions are in libc for the static and # profiled libraries. -dl-routines = $(addprefix dl-,load cache lookup object reloc deps \ +dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \ runtime error init fini debug misc \ version profile conflict tls origin scope \ execstack caller open close trampoline) +ifeq (yes,$(use-ldconfig)) +dl-routines += dl-cache +endif all-dl-routines = $(dl-routines) $(sysdep-dl-routines) # But they are absent from the shared libc, because that code is in ld.so. elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \ @@ -45,8 +50,6 @@ CFLAGS-dl-runtime.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-dl-lookup.c = -fexceptions -fasynchronous-unwind-tables CFLAGS-dl-iterate-phdr.c = $(uses-callbacks) -include ../Makeconfig - ifeq ($(unwind-find-fde),yes) routines += unwind-dw2-fde-glibc shared-only-routines += unwind-dw2-fde-glibc diff --git a/libc/elf/dl-hwcaps.c b/libc/elf/dl-hwcaps.c new file mode 100644 index 000000000..d911548f2 --- /dev/null +++ b/libc/elf/dl-hwcaps.c @@ -0,0 +1,279 @@ +/* Hardware capability support for run-time dynamic loader. + Copyright (C) 2012 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 + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <elf.h> +#include <errno.h> +#include <libintl.h> +#include <unistd.h> +#include <ldsodefs.h> + +#include <dl-procinfo.h> + +#ifdef _DL_FIRST_PLATFORM +# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT) +#else +# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT +#endif + +/* Return an array of useful/necessary hardware capability names. */ +const struct r_strlenpair * +internal_function +_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + size_t *max_capstrlen) +{ + /* Determine how many important bits are set. */ + uint64_t masked = GLRO(dl_hwcap) & GLRO(dl_hwcap_mask); + size_t cnt = platform != NULL; + size_t n, m; + size_t total; + struct r_strlenpair *temp; + struct r_strlenpair *result; + struct r_strlenpair *rp; + char *cp; + + /* Count the number of bits set in the masked value. */ + for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n) + if ((masked & (1ULL << n)) != 0) + ++cnt; + +#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO + /* The system-supplied DSO can contain a note of type 2, vendor "GNU". + This gives us a list of names to treat as fake hwcap bits. */ + + const char *dsocaps = NULL; + size_t dsocapslen = 0; + if (GLRO(dl_sysinfo_map) != NULL) + { + const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr; + const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum; + for (uint_fast16_t i = 0; i < phnum; ++i) + if (phdr[i].p_type == PT_NOTE) + { + const ElfW(Addr) start = (phdr[i].p_vaddr + + GLRO(dl_sysinfo_map)->l_addr); + const struct + { + ElfW(Word) vendorlen; + ElfW(Word) datalen; + ElfW(Word) type; + } *note = (const void *) start; + while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) + { +#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) + if (note->type == NT_GNU_HWCAP + && note->vendorlen == sizeof "GNU" + && !memcmp ((note + 1), "GNU", sizeof "GNU") + && note->datalen > 2 * sizeof (ElfW(Word)) + 2) + { + const ElfW(Word) *p = ((const void *) (note + 1) + + ROUND (sizeof "GNU")); + cnt += *p++; + ++p; /* Skip mask word. */ + dsocaps = (const char *) p; + dsocapslen = note->datalen - sizeof *p * 2; + break; + } + note = ((const void *) (note + 1) + + ROUND (note->vendorlen) + ROUND (note->datalen)); +#undef ROUND + } + if (dsocaps != NULL) + break; + } + } +#endif + + /* For TLS enabled builds always add 'tls'. */ + ++cnt; + + /* Create temporary data structure to generate result table. */ + temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp)); + m = 0; +#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO + if (dsocaps != NULL) + { + const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1]; + GLRO(dl_hwcap) |= (uint64_t) mask << _DL_FIRST_EXTRA; + /* Note that we add the dsocaps to the set already chosen by the + LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT). + So there is no way to request ignoring an OS-supplied dsocap + string and bit like you can ignore an OS-supplied HWCAP bit. */ + GLRO(dl_hwcap_mask) |= (uint64_t) mask << _DL_FIRST_EXTRA; + size_t len; + for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1) + { + uint_fast8_t bit = *p++; + len = strlen (p); + + /* Skip entries that are not enabled in the mask word. */ + if (__builtin_expect (mask & ((ElfW(Word)) 1 << bit), 1)) + { + temp[m].str = p; + temp[m].len = len; + ++m; + } + else + --cnt; + } + } +#endif + for (n = 0; masked != 0; ++n) + if ((masked & (1ULL << n)) != 0) + { + temp[m].str = _dl_hwcap_string (n); + temp[m].len = strlen (temp[m].str); + masked ^= 1ULL << n; + ++m; + } + if (platform != NULL) + { + temp[m].str = platform; + temp[m].len = platform_len; + ++m; + } + + temp[m].str = "tls"; + temp[m].len = 3; + ++m; + + assert (m == cnt); + + /* Determine the total size of all strings together. */ + if (cnt == 1) + total = temp[0].len + 1; + else + { + total = temp[0].len + temp[cnt - 1].len + 2; + if (cnt > 2) + { + total <<= 1; + for (n = 1; n + 1 < cnt; ++n) + total += temp[n].len + 1; + if (cnt > 3 + && (cnt >= sizeof (size_t) * 8 + || total + (sizeof (*result) << 3) + >= (1UL << (sizeof (size_t) * 8 - cnt + 3)))) + _dl_signal_error (ENOMEM, NULL, NULL, + N_("cannot create capability list")); + + total <<= cnt - 3; + } + } + + /* The result structure: we use a very compressed way to store the + various combinations of capability names. */ + *sz = 1 << cnt; + result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total); + if (result == NULL) + _dl_signal_error (ENOMEM, NULL, NULL, + N_("cannot create capability list")); + + if (cnt == 1) + { + result[0].str = (char *) (result + *sz); + result[0].len = temp[0].len + 1; + result[1].str = (char *) (result + *sz); + result[1].len = 0; + cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len); + *cp = '/'; + *sz = 2; + *max_capstrlen = result[0].len; + + return result; + } + + /* Fill in the information. This follows the following scheme + (indeces from TEMP for four strings): + entry #0: 0, 1, 2, 3 binary: 1111 + #1: 0, 1, 3 1101 + #2: 0, 2, 3 1011 + #3: 0, 3 1001 + This allows the representation of all possible combinations of + capability names in the string. First generate the strings. */ + result[1].str = result[0].str = cp = (char *) (result + *sz); +#define add(idx) \ + cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1); + if (cnt == 2) + { + add (1); + add (0); + } + else + { + n = 1 << (cnt - 1); + do + { + n -= 2; + + /* We always add the last string. */ + add (cnt - 1); + + /* Add the strings which have the bit set in N. */ + for (m = cnt - 2; m > 0; --m) + if ((n & (1 << m)) != 0) + add (m); + + /* Always add the first string. */ + add (0); + } + while (n != 0); + } +#undef add + + /* Now we are ready to install the string pointers and length. */ + for (n = 0; n < (1UL << cnt); ++n) + result[n].len = 0; + n = cnt; + do + { + size_t mask = 1 << --n; + + rp = result; + for (m = 1 << cnt; m > 0; ++rp) + if ((--m & mask) != 0) + rp->len += temp[n].len + 1; + } + while (n != 0); + + /* The first half of the strings all include the first string. */ + n = (1 << cnt) - 2; + rp = &result[2]; + while (n != (1UL << (cnt - 1))) + { + if ((--n & 1) != 0) + rp[0].str = rp[-2].str + rp[-2].len; + else + rp[0].str = rp[-1].str; + ++rp; + } + + /* The second half starts right after the first part of the string of + the corresponding entry in the first half. */ + do + { + rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1; + ++rp; + } + while (--n != 0); + + /* The maximum string length. */ + *max_capstrlen = result[0].len; + + return result; +} diff --git a/libc/elf/dl-load.c b/libc/elf/dl-load.c index 4d708bc5d..524e7369e 100644 --- a/libc/elf/dl-load.c +++ b/libc/elf/dl-load.c @@ -1090,7 +1090,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp, struct loadcmd { ElfW(Addr) mapstart, mapend, dataend, allocend; - off_t mapoff; + ElfW(Off) mapoff; int prot; } loadcmds[l->l_phnum], *c; size_t nloadcmds = 0; @@ -1347,7 +1347,7 @@ cannot allocate TLS data structures for initial thread"); l->l_text_end = l->l_addr + c->mapend; if (l->l_phdr == 0 - && (ElfW(Off)) c->mapoff <= header->e_phoff + && c->mapoff <= header->e_phoff && ((size_t) (c->mapend - c->mapstart + c->mapoff) >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr)))) /* Found the program header in this segment. */ @@ -2201,6 +2201,7 @@ _dl_map_object (struct link_map *loader, const char *name, &loader->l_runpath_dirs, &realname, &fb, loader, LA_SER_RUNPATH, &found_other_class); +#ifdef USE_LDCONFIG if (fd == -1 && (__builtin_expect (! (mode & __RTLD_SECURE), 1) || ! INTUSE(__libc_enable_secure)) @@ -2212,22 +2213,22 @@ _dl_map_object (struct link_map *loader, const char *name, if (cached != NULL) { -#ifdef SHARED +# ifdef SHARED // XXX Correct to unconditionally default to namespace 0? l = (loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded ?: &GL(dl_rtld_map)); -#else +# else l = loader; -#endif +# endif /* If the loader has the DF_1_NODEFLIB flag set we must not use a cache entry from any of these directories. */ if ( -#ifndef SHARED +# ifndef SHARED /* 'l' is always != NULL for dynamically linked objects. */ l != NULL && -#endif +# endif __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0)) { const char *dirp = system_dirs; @@ -2265,6 +2266,7 @@ _dl_map_object (struct link_map *loader, const char *name, } } } +#endif /* Finally, try the default path. */ if (fd == -1 diff --git a/libc/elf/dl-open.c b/libc/elf/dl-open.c index 903bdf13f..703218b0c 100644 --- a/libc/elf/dl-open.c +++ b/libc/elf/dl-open.c @@ -654,8 +654,8 @@ no more namespaces available for dlmopen()")); int errcode = _dl_catch_error (&objname, &errstring, &malloced, dl_open_worker, &args); -#ifndef MAP_COPY - /* We must munmap() the cache file. */ +#if defined USE_LDCONFIG && !defined MAP_COPY + /* We must unmap the cache file. */ _dl_unload_cache (); #endif diff --git a/libc/elf/dl-runtime.c b/libc/elf/dl-runtime.c index fdaa364c6..2e02a218e 100644 --- a/libc/elf/dl-runtime.c +++ b/libc/elf/dl-runtime.c @@ -36,10 +36,6 @@ # define PLTREL ElfW(Rel) #endif -#ifndef VERSYMIDX -# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) -#endif - /* The fixup functions might have need special attributes. If none are provided define the macro as empty. */ #ifndef ARCH_FIXUP_ATTRIBUTE diff --git a/libc/elf/dl-support.c b/libc/elf/dl-support.c index dff9aa074..a74cf636d 100644 --- a/libc/elf/dl-support.c +++ b/libc/elf/dl-support.c @@ -164,6 +164,11 @@ uintptr_t _dl_sysinfo = DL_SYSINFO_DEFAULT; #if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO /* Address of the ELF headers in the vsyscall page. */ const ElfW(Ehdr) *_dl_sysinfo_dso; + +struct link_map *_dl_sysinfo_map; + +# include "get-dynamic-info.h" +# include "setup-vdso.h" #endif /* During the program run we must not modify the global data of @@ -269,6 +274,10 @@ _dl_non_dynamic_init (void) _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + /* Set up the data structures for the system-supplied DSO early, + so they can influence _dl_init_paths. */ + setup_vdso (NULL, NULL); + /* Initialize the data structures for the search paths for shared objects. */ _dl_init_paths (getenv ("LD_LIBRARY_PATH")); @@ -329,23 +338,6 @@ _dl_non_dynamic_init (void) } } - -const struct r_strlenpair * -internal_function -_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, - size_t *max_capstrlen) -{ - static struct r_strlenpair result; - static char buf[1]; - - result.str = buf; /* Does not really matter. */ - result.len = 0; - - *sz = 1; - return &result; -} - - #ifdef DL_SYSINFO_IMPLEMENTATION DL_SYSINFO_IMPLEMENTATION #endif diff --git a/libc/elf/dl-sysdep.c b/libc/elf/dl-sysdep.c index 7d2283910..65a90469c 100644 --- a/libc/elf/dl-sysdep.c +++ b/libc/elf/dl-sysdep.c @@ -1,6 +1,5 @@ /* Operating system support for run-time dynamic linker. Generic Unix version. - Copyright (C) 1995-1998,2000-2010,2012 - Free Software Foundation, Inc. + Copyright (C) 1995-2012 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 @@ -17,6 +16,12 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +/* We conditionalize the whole of this file rather than simply eliding it + from the static build, because other sysdeps/ versions of this file + might define things needed by a static build. */ + +#ifdef SHARED + #include <assert.h> #include <elf.h> #include <errno.h> @@ -39,12 +44,6 @@ #include <hp-timing.h> #include <tls.h> -#ifdef _DL_FIRST_PLATFORM -# define _DL_FIRST_EXTRA (_DL_FIRST_PLATFORM + _DL_PLATFORMS_COUNT) -#else -# define _DL_FIRST_EXTRA _DL_HWCAP_COUNT -#endif - extern char **_environ attribute_hidden; extern char _end[] attribute_hidden; @@ -345,250 +344,4 @@ _dl_show_auxv (void) } } - -/* Return an array of useful/necessary hardware capability names. */ -const struct r_strlenpair * -internal_function -_dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, - size_t *max_capstrlen) -{ - /* Determine how many important bits are set. */ - uint64_t masked = GLRO(dl_hwcap) & GLRO(dl_hwcap_mask); - size_t cnt = platform != NULL; - size_t n, m; - size_t total; - struct r_strlenpair *temp; - struct r_strlenpair *result; - struct r_strlenpair *rp; - char *cp; - - /* Count the number of bits set in the masked value. */ - for (n = 0; (~((1ULL << n) - 1) & masked) != 0; ++n) - if ((masked & (1ULL << n)) != 0) - ++cnt; - -#if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED - /* The system-supplied DSO can contain a note of type 2, vendor "GNU". - This gives us a list of names to treat as fake hwcap bits. */ - - const char *dsocaps = NULL; - size_t dsocapslen = 0; - if (GLRO(dl_sysinfo_map) != NULL) - { - const ElfW(Phdr) *const phdr = GLRO(dl_sysinfo_map)->l_phdr; - const ElfW(Word) phnum = GLRO(dl_sysinfo_map)->l_phnum; - for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdr[i].p_type == PT_NOTE) - { - const ElfW(Addr) start = (phdr[i].p_vaddr - + GLRO(dl_sysinfo_map)->l_addr); - const struct - { - ElfW(Word) vendorlen; - ElfW(Word) datalen; - ElfW(Word) type; - } *note = (const void *) start; - while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) - { -#define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) - if (note->type == NT_GNU_HWCAP - && note->vendorlen == sizeof "GNU" - && !memcmp ((note + 1), "GNU", sizeof "GNU") - && note->datalen > 2 * sizeof (ElfW(Word)) + 2) - { - const ElfW(Word) *p = ((const void *) (note + 1) - + ROUND (sizeof "GNU")); - cnt += *p++; - ++p; /* Skip mask word. */ - dsocaps = (const char *) p; - dsocapslen = note->datalen - sizeof *p * 2; - break; - } - note = ((const void *) (note + 1) - + ROUND (note->vendorlen) + ROUND (note->datalen)); -#undef ROUND - } - if (dsocaps != NULL) - break; - } - } -#endif - - /* For TLS enabled builds always add 'tls'. */ - ++cnt; - - /* Create temporary data structure to generate result table. */ - temp = (struct r_strlenpair *) alloca (cnt * sizeof (*temp)); - m = 0; -#if (defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO) && defined SHARED - if (dsocaps != NULL) - { - const ElfW(Word) mask = ((const ElfW(Word) *) dsocaps)[-1]; - GLRO(dl_hwcap) |= (uint64_t) mask << _DL_FIRST_EXTRA; - /* Note that we add the dsocaps to the set already chosen by the - LD_HWCAP_MASK environment variable (or default HWCAP_IMPORTANT). - So there is no way to request ignoring an OS-supplied dsocap - string and bit like you can ignore an OS-supplied HWCAP bit. */ - GLRO(dl_hwcap_mask) |= (uint64_t) mask << _DL_FIRST_EXTRA; - size_t len; - for (const char *p = dsocaps; p < dsocaps + dsocapslen; p += len + 1) - { - uint_fast8_t bit = *p++; - len = strlen (p); - - /* Skip entries that are not enabled in the mask word. */ - if (__builtin_expect (mask & ((ElfW(Word)) 1 << bit), 1)) - { - temp[m].str = p; - temp[m].len = len; - ++m; - } - else - --cnt; - } - } #endif - for (n = 0; masked != 0; ++n) - if ((masked & (1ULL << n)) != 0) - { - temp[m].str = _dl_hwcap_string (n); - temp[m].len = strlen (temp[m].str); - masked ^= 1ULL << n; - ++m; - } - if (platform != NULL) - { - temp[m].str = platform; - temp[m].len = platform_len; - ++m; - } - - temp[m].str = "tls"; - temp[m].len = 3; - ++m; - - assert (m == cnt); - - /* Determine the total size of all strings together. */ - if (cnt == 1) - total = temp[0].len + 1; - else - { - total = temp[0].len + temp[cnt - 1].len + 2; - if (cnt > 2) - { - total <<= 1; - for (n = 1; n + 1 < cnt; ++n) - total += temp[n].len + 1; - if (cnt > 3 - && (cnt >= sizeof (size_t) * 8 - || total + (sizeof (*result) << 3) - >= (1UL << (sizeof (size_t) * 8 - cnt + 3)))) - _dl_signal_error (ENOMEM, NULL, NULL, - N_("cannot create capability list")); - - total <<= cnt - 3; - } - } - - /* The result structure: we use a very compressed way to store the - various combinations of capability names. */ - *sz = 1 << cnt; - result = (struct r_strlenpair *) malloc (*sz * sizeof (*result) + total); - if (result == NULL) - _dl_signal_error (ENOMEM, NULL, NULL, - N_("cannot create capability list")); - - if (cnt == 1) - { - result[0].str = (char *) (result + *sz); - result[0].len = temp[0].len + 1; - result[1].str = (char *) (result + *sz); - result[1].len = 0; - cp = __mempcpy ((char *) (result + *sz), temp[0].str, temp[0].len); - *cp = '/'; - *sz = 2; - *max_capstrlen = result[0].len; - - return result; - } - - /* Fill in the information. This follows the following scheme - (indeces from TEMP for four strings): - entry #0: 0, 1, 2, 3 binary: 1111 - #1: 0, 1, 3 1101 - #2: 0, 2, 3 1011 - #3: 0, 3 1001 - This allows the representation of all possible combinations of - capability names in the string. First generate the strings. */ - result[1].str = result[0].str = cp = (char *) (result + *sz); -#define add(idx) \ - cp = __mempcpy (__mempcpy (cp, temp[idx].str, temp[idx].len), "/", 1); - if (cnt == 2) - { - add (1); - add (0); - } - else - { - n = 1 << (cnt - 1); - do - { - n -= 2; - - /* We always add the last string. */ - add (cnt - 1); - - /* Add the strings which have the bit set in N. */ - for (m = cnt - 2; m > 0; --m) - if ((n & (1 << m)) != 0) - add (m); - - /* Always add the first string. */ - add (0); - } - while (n != 0); - } -#undef add - - /* Now we are ready to install the string pointers and length. */ - for (n = 0; n < (1UL << cnt); ++n) - result[n].len = 0; - n = cnt; - do - { - size_t mask = 1 << --n; - - rp = result; - for (m = 1 << cnt; m > 0; ++rp) - if ((--m & mask) != 0) - rp->len += temp[n].len + 1; - } - while (n != 0); - - /* The first half of the strings all include the first string. */ - n = (1 << cnt) - 2; - rp = &result[2]; - while (n != (1UL << (cnt - 1))) - { - if ((--n & 1) != 0) - rp[0].str = rp[-2].str + rp[-2].len; - else - rp[0].str = rp[-1].str; - ++rp; - } - - /* The second half starts right after the first part of the string of - the corresponding entry in the first half. */ - do - { - rp[0].str = rp[-(1 << (cnt - 1))].str + temp[cnt - 1].len + 1; - ++rp; - } - while (--n != 0); - - /* The maximum string length. */ - *max_capstrlen = result[0].len; - - return result; -} diff --git a/libc/elf/dl-version.c b/libc/elf/dl-version.c index 047db2f82..269c0aadf 100644 --- a/libc/elf/dl-version.c +++ b/libc/elf/dl-version.c @@ -28,11 +28,6 @@ #include <assert.h> -#ifndef VERSYMIDX -# define VERSYMIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) -#endif - - #define make_string(string, rest...) \ ({ \ const char *all[] = { string, ## rest }; \ diff --git a/libc/elf/do-rel.h b/libc/elf/do-rel.h index 1138ca4bd..cfb9a512f 100644 --- a/libc/elf/do-rel.h +++ b/libc/elf/do-rel.h @@ -32,14 +32,6 @@ (void *) (l_addr + relative->r_offset)) #endif -#ifndef VERSYMIDX -# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) -#endif -#ifndef VALIDX -# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ - + DT_EXTRANUM + DT_VALTAGIDX (tag)) -#endif - /* Perform the relocations in MAP on the running program image as specified by RELTAG, SZTAG. If LAZY is nonzero, this is the first pass on PLT relocations; they should be set up to call _dl_runtime_resolve, rather diff --git a/libc/elf/dynamic-link.h b/libc/elf/dynamic-link.h index 44f53b3c7..ad30d23a7 100644 --- a/libc/elf/dynamic-link.h +++ b/libc/elf/dynamic-link.h @@ -42,7 +42,6 @@ int internal_function _dl_try_allocate_static_tls (struct link_map *map); #include <elf.h> -#include <assert.h> #ifdef RESOLVE_MAP /* We pass reloc_addr as a pointer to void, as opposed to a pointer to @@ -88,153 +87,7 @@ elf_machine_lazy_rel (struct link_map *map, #include <dl-machine.h> -#ifndef VERSYMIDX -# define VERSYMIDX(sym) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (sym)) -#endif - - -/* Read the dynamic section at DYN and fill in INFO with indices DT_*. */ -#ifndef RESOLVE_MAP -static -#else -auto -#endif -inline void __attribute__ ((unused, always_inline)) -elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) -{ - ElfW(Dyn) *dyn = l->l_ld; - ElfW(Dyn) **info; -#if __ELF_NATIVE_CLASS == 32 - typedef Elf32_Word d_tag_utype; -#elif __ELF_NATIVE_CLASS == 64 - typedef Elf64_Xword d_tag_utype; -#endif - -#ifndef RTLD_BOOTSTRAP - if (dyn == NULL) - return; -#endif - - info = l->l_info; - - while (dyn->d_tag != DT_NULL) - { - if ((d_tag_utype) dyn->d_tag < DT_NUM) - info[dyn->d_tag] = dyn; - else if (dyn->d_tag >= DT_LOPROC && - dyn->d_tag < DT_LOPROC + DT_THISPROCNUM) - info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn; - else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM) - info[VERSYMIDX (dyn->d_tag)] = dyn; - else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM) - info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM] = dyn; - else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM) - info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn; - else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) - info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; - ++dyn; - } - -#define DL_RO_DYN_TEMP_CNT 8 - -#ifndef DL_RO_DYN_SECTION - /* Don't adjust .dynamic unnecessarily. */ - if (l->l_addr != 0) - { - ElfW(Addr) l_addr = l->l_addr; - int cnt = 0; - -# define ADJUST_DYN_INFO(tag) \ - do \ - if (info[tag] != NULL) \ - { \ - if (temp) \ - { \ - temp[cnt].d_tag = info[tag]->d_tag; \ - temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \ - info[tag] = temp + cnt++; \ - } \ - else \ - info[tag]->d_un.d_ptr += l_addr; \ - } \ - while (0) - - ADJUST_DYN_INFO (DT_HASH); - ADJUST_DYN_INFO (DT_PLTGOT); - ADJUST_DYN_INFO (DT_STRTAB); - ADJUST_DYN_INFO (DT_SYMTAB); -# if ! ELF_MACHINE_NO_RELA - ADJUST_DYN_INFO (DT_RELA); -# endif -# if ! ELF_MACHINE_NO_REL - ADJUST_DYN_INFO (DT_REL); -# endif - ADJUST_DYN_INFO (DT_JMPREL); - ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); - ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM); -# undef ADJUST_DYN_INFO - assert (cnt <= DL_RO_DYN_TEMP_CNT); - } -#endif - if (info[DT_PLTREL] != NULL) - { -#if ELF_MACHINE_NO_RELA - assert (info[DT_PLTREL]->d_un.d_val == DT_REL); -#elif ELF_MACHINE_NO_REL - assert (info[DT_PLTREL]->d_un.d_val == DT_RELA); -#else - assert (info[DT_PLTREL]->d_un.d_val == DT_REL - || info[DT_PLTREL]->d_un.d_val == DT_RELA); -#endif - } -#if ! ELF_MACHINE_NO_RELA - if (info[DT_RELA] != NULL) - assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela))); -# endif -# if ! ELF_MACHINE_NO_REL - if (info[DT_REL] != NULL) - assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); -#endif -#ifdef RTLD_BOOTSTRAP - /* 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); - assert (info[DT_FLAGS] == NULL - || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0); - /* Flags must not be set for ld.so. */ - assert (info[DT_RUNPATH] == NULL); - assert (info[DT_RPATH] == NULL); -#else - if (info[DT_FLAGS] != NULL) - { - /* Flags are used. Translate to the old form where available. - Since these l_info entries are only tested for NULL pointers it - is ok if they point to the DT_FLAGS entry. */ - l->l_flags = info[DT_FLAGS]->d_un.d_val; - - if (l->l_flags & DF_SYMBOLIC) - info[DT_SYMBOLIC] = info[DT_FLAGS]; - if (l->l_flags & DF_TEXTREL) - info[DT_TEXTREL] = info[DT_FLAGS]; - if (l->l_flags & DF_BIND_NOW) - info[DT_BIND_NOW] = info[DT_FLAGS]; - } - if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) - { - l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; - - if (l->l_flags_1 & DF_1_NOW) - info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)]; - } - if (info[DT_RUNPATH] != NULL) - /* If both RUNPATH and RPATH are given, the latter is ignored. */ - info[DT_RPATH] = NULL; -#endif -} +#include "get-dynamic-info.h" #ifdef RESOLVE_MAP diff --git a/libc/elf/get-dynamic-info.h b/libc/elf/get-dynamic-info.h new file mode 100644 index 000000000..ffac75f63 --- /dev/null +++ b/libc/elf/get-dynamic-info.h @@ -0,0 +1,161 @@ +/* Read the dynamic section at DYN and fill in INFO with indices DT_*. + Copyright (C) 2012 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 + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> + +#ifndef RESOLVE_MAP +static +#else +auto +#endif +inline void __attribute__ ((unused, always_inline)) +elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) +{ + ElfW(Dyn) *dyn = l->l_ld; + ElfW(Dyn) **info; +#if __ELF_NATIVE_CLASS == 32 + typedef Elf32_Word d_tag_utype; +#elif __ELF_NATIVE_CLASS == 64 + typedef Elf64_Xword d_tag_utype; +#endif + +#ifndef RTLD_BOOTSTRAP + if (dyn == NULL) + return; +#endif + + info = l->l_info; + + while (dyn->d_tag != DT_NULL) + { + if ((d_tag_utype) dyn->d_tag < DT_NUM) + info[dyn->d_tag] = dyn; + else if (dyn->d_tag >= DT_LOPROC && + dyn->d_tag < DT_LOPROC + DT_THISPROCNUM) + info[dyn->d_tag - DT_LOPROC + DT_NUM] = dyn; + else if ((d_tag_utype) DT_VERSIONTAGIDX (dyn->d_tag) < DT_VERSIONTAGNUM) + info[VERSYMIDX (dyn->d_tag)] = dyn; + else if ((d_tag_utype) DT_EXTRATAGIDX (dyn->d_tag) < DT_EXTRANUM) + info[DT_EXTRATAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM] = dyn; + else if ((d_tag_utype) DT_VALTAGIDX (dyn->d_tag) < DT_VALNUM) + info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn; + else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) + info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; + ++dyn; + } + +#define DL_RO_DYN_TEMP_CNT 8 + +#ifndef DL_RO_DYN_SECTION + /* Don't adjust .dynamic unnecessarily. */ + if (l->l_addr != 0) + { + ElfW(Addr) l_addr = l->l_addr; + int cnt = 0; + +# define ADJUST_DYN_INFO(tag) \ + do \ + if (info[tag] != NULL) \ + { \ + if (temp) \ + { \ + temp[cnt].d_tag = info[tag]->d_tag; \ + temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \ + info[tag] = temp + cnt++; \ + } \ + else \ + info[tag]->d_un.d_ptr += l_addr; \ + } \ + while (0) + + ADJUST_DYN_INFO (DT_HASH); + ADJUST_DYN_INFO (DT_PLTGOT); + ADJUST_DYN_INFO (DT_STRTAB); + ADJUST_DYN_INFO (DT_SYMTAB); +# if ! ELF_MACHINE_NO_RELA + ADJUST_DYN_INFO (DT_RELA); +# endif +# if ! ELF_MACHINE_NO_REL + ADJUST_DYN_INFO (DT_REL); +# endif + ADJUST_DYN_INFO (DT_JMPREL); + ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); + ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM); +# undef ADJUST_DYN_INFO + assert (cnt <= DL_RO_DYN_TEMP_CNT); + } +#endif + if (info[DT_PLTREL] != NULL) + { +#if ELF_MACHINE_NO_RELA + assert (info[DT_PLTREL]->d_un.d_val == DT_REL); +#elif ELF_MACHINE_NO_REL + assert (info[DT_PLTREL]->d_un.d_val == DT_RELA); +#else + assert (info[DT_PLTREL]->d_un.d_val == DT_REL + || info[DT_PLTREL]->d_un.d_val == DT_RELA); +#endif + } +#if ! ELF_MACHINE_NO_RELA + if (info[DT_RELA] != NULL) + assert (info[DT_RELAENT]->d_un.d_val == sizeof (ElfW(Rela))); +# endif +# if ! ELF_MACHINE_NO_REL + if (info[DT_REL] != NULL) + assert (info[DT_RELENT]->d_un.d_val == sizeof (ElfW(Rel))); +#endif +#ifdef RTLD_BOOTSTRAP + /* 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); + assert (info[DT_FLAGS] == NULL + || (info[DT_FLAGS]->d_un.d_val & ~DF_BIND_NOW) == 0); + /* Flags must not be set for ld.so. */ + assert (info[DT_RUNPATH] == NULL); + assert (info[DT_RPATH] == NULL); +#else + if (info[DT_FLAGS] != NULL) + { + /* Flags are used. Translate to the old form where available. + Since these l_info entries are only tested for NULL pointers it + is ok if they point to the DT_FLAGS entry. */ + l->l_flags = info[DT_FLAGS]->d_un.d_val; + + if (l->l_flags & DF_SYMBOLIC) + info[DT_SYMBOLIC] = info[DT_FLAGS]; + if (l->l_flags & DF_TEXTREL) + info[DT_TEXTREL] = info[DT_FLAGS]; + if (l->l_flags & DF_BIND_NOW) + info[DT_BIND_NOW] = info[DT_FLAGS]; + } + if (info[VERSYMIDX (DT_FLAGS_1)] != NULL) + { + l->l_flags_1 = info[VERSYMIDX (DT_FLAGS_1)]->d_un.d_val; + + if (l->l_flags_1 & DF_1_NOW) + info[DT_BIND_NOW] = info[VERSYMIDX (DT_FLAGS_1)]; + } + if (info[DT_RUNPATH] != NULL) + /* If both RUNPATH and RPATH are given, the latter is ignored. */ + info[DT_RPATH] = NULL; +#endif +} diff --git a/libc/elf/rtld.c b/libc/elf/rtld.c index 1ba35321b..0c5aebefa 100644 --- a/libc/elf/rtld.c +++ b/libc/elf/rtld.c @@ -255,15 +255,6 @@ RTLD_START # error "sysdeps/MACHINE/dl-machine.h fails to define RTLD_START" #endif -#ifndef VALIDX -# define VALIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ - + DT_EXTRANUM + DT_VALTAGIDX (tag)) -#endif -#ifndef ADDRIDX -# define ADDRIDX(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM \ - + DT_EXTRANUM + DT_VALNUM + DT_ADDRTAGIDX (tag)) -#endif - /* This is the second half of _dl_start (below). It can be inlined safely under DONT_USE_BOOTSTRAP_MAP, where it is careful not to make any GOT references. When the tools don't permit us to avoid using a GOT entry @@ -883,6 +874,7 @@ security_init (void) _dl_random = NULL; } +#include "setup-vdso.h" /* The library search path. */ static const char *library_path attribute_relro; @@ -1339,102 +1331,9 @@ of this helper program; chances are you did not intend to run this program.\n\ } struct link_map **first_preload = &GL(dl_rtld_map).l_next; -#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO /* Set up the data structures for the system-supplied DSO early, so they can influence _dl_init_paths. */ - if (GLRO(dl_sysinfo_dso) != NULL) - { - /* Do an abridged version of the work _dl_map_object_from_fd would do - to map in the object. It's already mapped and prelinked (and - better be, since it's read-only and so we couldn't relocate it). - We just want our data structures to describe it as if we had just - mapped and relocated it normally. */ - struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL, - 0, LM_ID_BASE); - if (__builtin_expect (l != NULL, 1)) - { - static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; - - l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso) - + GLRO(dl_sysinfo_dso)->e_phoff); - l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum; - for (uint_fast16_t i = 0; i < l->l_phnum; ++i) - { - const ElfW(Phdr) *const ph = &l->l_phdr[i]; - if (ph->p_type == PT_DYNAMIC) - { - l->l_ld = (void *) ph->p_vaddr; - l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); - } - else if (ph->p_type == PT_LOAD) - { - if (! l->l_addr) - l->l_addr = ph->p_vaddr; - if (ph->p_vaddr + ph->p_memsz >= l->l_map_end) - l->l_map_end = ph->p_vaddr + ph->p_memsz; - if ((ph->p_flags & PF_X) - && ph->p_vaddr + ph->p_memsz >= l->l_text_end) - l->l_text_end = ph->p_vaddr + ph->p_memsz; - } - else - /* There must be no TLS segment. */ - assert (ph->p_type != PT_TLS); - } - l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso); - l->l_addr = l->l_map_start - l->l_addr; - 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, dyn_temp); - _dl_setup_hash (l); - l->l_relocated = 1; - - /* The vDSO is always used. */ - l->l_used = 1; - - /* Initialize l_local_scope to contain just this map. This allows - the use of dl_lookup_symbol_x to resolve symbols within the vdso. - So we create a single entry list pointing to l_real as its only - element */ - l->l_local_scope[0]->r_nlist = 1; - l->l_local_scope[0]->r_list = &l->l_real; - - /* Now that we have the info handy, use the DSO image's soname - so this object can be looked up by name. Note that we do not - set l_name here. That field gives the file name of the DSO, - and this DSO is not associated with any file. */ - if (l->l_info[DT_SONAME] != NULL) - { - /* Work around a kernel problem. The kernel cannot handle - addresses in the vsyscall DSO pages in writev() calls. */ - const char *dsoname = ((char *) D_PTR (l, l_info[DT_STRTAB]) - + l->l_info[DT_SONAME]->d_un.d_val); - size_t len = strlen (dsoname); - char *copy = malloc (len); - if (copy == NULL) - _dl_fatal_printf ("out of memory\n"); - l->l_libname->name = l->l_name = memcpy (copy, dsoname, len); - } - - /* Add the vDSO to the object list. */ - _dl_add_to_namespace_list (l, LM_ID_BASE); - - /* Rearrange the list so this DSO appears after rtld_map. */ - assert (l->l_next == NULL); - assert (l->l_prev == main_map); - GL(dl_rtld_map).l_next = l; - l->l_prev = &GL(dl_rtld_map); - first_preload = &l->l_next; - - /* We have a prelinked DSO preloaded by the system. */ - GLRO(dl_sysinfo_map) = l; -# ifdef NEED_DL_SYSINFO - if (GLRO(dl_sysinfo) == DL_SYSINFO_DEFAULT) - GLRO(dl_sysinfo) = GLRO(dl_sysinfo_dso)->e_entry + l->l_addr; -# endif - } - } -#endif + setup_vdso (main_map, &first_preload); #ifdef DL_SYSDEP_OSCHECK DL_SYSDEP_OSCHECK (_dl_fatal_printf); @@ -2410,7 +2309,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", _dl_debug_state (); LIBC_PROBE (init_complete, 2, LM_ID_BASE, r); -#ifndef MAP_COPY +#if defined USE_LDCONFIG && !defined MAP_COPY /* We must munmap() the cache file. */ _dl_unload_cache (); #endif diff --git a/libc/elf/setup-vdso.h b/libc/elf/setup-vdso.h new file mode 100644 index 000000000..f8f348a5f --- /dev/null +++ b/libc/elf/setup-vdso.h @@ -0,0 +1,121 @@ +/* Set up the data structures for the system-supplied DSO. + Copyright (C) 2012 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 + <http://www.gnu.org/licenses/>. */ + +static inline void __attribute__ ((always_inline)) +setup_vdso (struct link_map *main_map __attribute__ ((unused)), + struct link_map ***first_preload __attribute__ ((unused))) +{ +#if defined NEED_DL_SYSINFO || defined NEED_DL_SYSINFO_DSO + if (GLRO(dl_sysinfo_dso) == NULL) + return; + + /* Do an abridged version of the work _dl_map_object_from_fd would do + to map in the object. It's already mapped and prelinked (and + better be, since it's read-only and so we couldn't relocate it). + We just want our data structures to describe it as if we had just + mapped and relocated it normally. */ + struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL, + 0, LM_ID_BASE); + if (__builtin_expect (l != NULL, 1)) + { + static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro; + + l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso) + + GLRO(dl_sysinfo_dso)->e_phoff); + l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum; + for (uint_fast16_t i = 0; i < l->l_phnum; ++i) + { + const ElfW(Phdr) *const ph = &l->l_phdr[i]; + if (ph->p_type == PT_DYNAMIC) + { + l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); + } + else if (ph->p_type == PT_LOAD) + { + if (! l->l_addr) + l->l_addr = ph->p_vaddr; + if (ph->p_vaddr + ph->p_memsz >= l->l_map_end) + l->l_map_end = ph->p_vaddr + ph->p_memsz; + if ((ph->p_flags & PF_X) + && ph->p_vaddr + ph->p_memsz >= l->l_text_end) + l->l_text_end = ph->p_vaddr + ph->p_memsz; + } + else + /* There must be no TLS segment. */ + assert (ph->p_type != PT_TLS); + } + l->l_map_start = (ElfW(Addr)) GLRO(dl_sysinfo_dso); + l->l_addr = l->l_map_start - l->l_addr; + 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, dyn_temp); + _dl_setup_hash (l); + l->l_relocated = 1; + + /* The vDSO is always used. */ + l->l_used = 1; + + /* Initialize l_local_scope to contain just this map. This allows + the use of dl_lookup_symbol_x to resolve symbols within the vdso. + So we create a single entry list pointing to l_real as its only + element */ + l->l_local_scope[0]->r_nlist = 1; + l->l_local_scope[0]->r_list = &l->l_real; + + /* Now that we have the info handy, use the DSO image's soname + so this object can be looked up by name. Note that we do not + set l_name here. That field gives the file name of the DSO, + and this DSO is not associated with any file. */ + if (l->l_info[DT_SONAME] != NULL) + { + /* Work around a kernel problem. The kernel cannot handle + addresses in the vsyscall DSO pages in writev() calls. */ + const char *dsoname = ((char *) D_PTR (l, l_info[DT_STRTAB]) + + l->l_info[DT_SONAME]->d_un.d_val); + size_t len = strlen (dsoname); + char *copy = malloc (len); + if (copy == NULL) + _dl_fatal_printf ("out of memory\n"); + l->l_libname->name = l->l_name = memcpy (copy, dsoname, len); + } + + /* Add the vDSO to the object list. */ + _dl_add_to_namespace_list (l, LM_ID_BASE); + +# ifdef IS_IN_rtld + /* Rearrange the list so this DSO appears after rtld_map. */ + assert (l->l_next == NULL); + assert (l->l_prev == main_map); + GL(dl_rtld_map).l_next = l; + l->l_prev = &GL(dl_rtld_map); + *first_preload = &l->l_next; +# else + GL(dl_nns) = 1; +# endif + + /* We have a prelinked DSO preloaded by the system. */ + GLRO(dl_sysinfo_map) = l; +# ifdef NEED_DL_SYSINFO + if (GLRO(dl_sysinfo) == DL_SYSINFO_DEFAULT) + GLRO(dl_sysinfo) = GLRO(dl_sysinfo_dso)->e_entry + l->l_addr; +# endif + } +#endif +} |