diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-close.c | 6 | ||||
-rw-r--r-- | elf/dl-hwcaps.c | 14 | ||||
-rw-r--r-- | elf/dl-misc.c | 23 | ||||
-rw-r--r-- | elf/dl-open.c | 7 | ||||
-rw-r--r-- | elf/dl-sysdep.c | 13 | ||||
-rw-r--r-- | elf/dl-writev.h | 56 | ||||
-rw-r--r-- | elf/ldconfig.c | 6 | ||||
-rw-r--r-- | elf/sprof.c | 4 |
8 files changed, 95 insertions, 34 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c index c86f609402..fe3014cca3 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -183,6 +183,8 @@ _dl_close_worker (struct link_map *map) /* Mark all dependencies as used. */ if (l->l_initfini != NULL) { + /* We are always the zeroth entry, and since we don't include + ourselves in the dependency analysis start at 1. */ struct link_map **lp = &l->l_initfini[1]; while (*lp != NULL) { @@ -193,6 +195,10 @@ _dl_close_worker (struct link_map *map) if (!used[(*lp)->l_idx]) { used[(*lp)->l_idx] = 1; + /* If we marked a new object as used, and we've + already processed it, then we need to go back + and process again from that point forward to + ensure we keep all of its dependencies also. */ if ((*lp)->l_idx - 1 < done_index) done_index = (*lp)->l_idx - 1; } diff --git a/elf/dl-hwcaps.c b/elf/dl-hwcaps.c index 8d49383d76..1b7fe52a6a 100644 --- a/elf/dl-hwcaps.c +++ b/elf/dl-hwcaps.c @@ -66,6 +66,11 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, { const ElfW(Addr) start = (phdr[i].p_vaddr + GLRO(dl_sysinfo_map)->l_addr); + /* The standard ELF note layout is exactly as the anonymous struct. + The next element is a variable length vendor name of length + VENDORLEN (with a real length rounded to ElfW(Addr)), followed + by the data of length DATALEN (with a real length rounded to + ElfW(Addr)). */ const struct { ElfW(Word) vendorlen; @@ -75,6 +80,11 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, while ((ElfW(Addr)) (note + 1) - start < phdr[i].p_memsz) { #define ROUND(len) (((len) + sizeof (ElfW(Word)) - 1) & -sizeof (ElfW(Word))) + /* The layout of the type 2, vendor "GNU" note is as follows: + .long <Number of capabilities enabled by this note> + .long <Capabilities mask> (as mask >> _DL_FIRST_EXTRA). + .byte <The bit number for the next capability> + .asciz <The name of the capability>. */ if (note->type == NT_GNU_HWCAP && note->vendorlen == sizeof "GNU" && !memcmp ((note + 1), "GNU", sizeof "GNU") @@ -84,7 +94,7 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, + ROUND (sizeof "GNU")); cnt += *p++; ++p; /* Skip mask word. */ - dsocaps = (const char *) p; + dsocaps = (const char *) p; /* Pseudo-string "<b>name" */ dsocapslen = note->datalen - sizeof *p * 2; break; } @@ -107,6 +117,8 @@ _dl_important_hwcaps (const char *platform, size_t platform_len, size_t *sz, #ifdef NEED_DL_SYSINFO_DSO if (dsocaps != NULL) { + /* dsocaps points to the .asciz string, and -1 points to the mask + .long just before the string. */ 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 diff --git a/elf/dl-misc.c b/elf/dl-misc.c index a8e9a3f2f0..e0e105b88f 100644 --- a/elf/dl-misc.c +++ b/elf/dl-misc.c @@ -31,7 +31,8 @@ #include <sys/uio.h> #include <sysdep.h> #include <_itoa.h> -#include <bits/libc-lock.h> +#include <dl-writev.h> + /* Read the whole contents of FILE into new mmap'd space with given protections. *SIZEP gets the size of the file. On error MAP_FAILED @@ -239,25 +240,7 @@ _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) } /* Finally write the result. */ -#ifdef HAVE_INLINED_SYSCALLS - INTERNAL_SYSCALL_DECL (err); - INTERNAL_SYSCALL (writev, err, 3, fd, &iov, niov); -#elif RTLD_PRIVATE_ERRNO - /* We have to take this lock just to be sure we don't clobber the private - errno when it's being used by another thread that cares about it. - Yet we must be sure not to try calling the lock functions before - the thread library is fully initialized. */ - if (__builtin_expect (INTUSE (_dl_starting_up), 0)) - __writev (fd, iov, niov); - else - { - __rtld_lock_lock_recursive (GL(dl_load_lock)); - __writev (fd, iov, niov); - __rtld_lock_unlock_recursive (GL(dl_load_lock)); - } -#else - __writev (fd, iov, niov); -#endif + _dl_writev (fd, iov, niov); } diff --git a/elf/dl-open.c b/elf/dl-open.c index 9ff5f5736d..92fae7f59b 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -37,13 +37,6 @@ #include <dl-dst.h> -extern ElfW(Addr) _dl_sysdep_start (void **start_argptr, - void (*dl_main) (const ElfW(Phdr) *phdr, - ElfW(Word) phnum, - ElfW(Addr) *user_entry, - ElfW(auxv_t) *auxv)); -weak_extern (_dl_sysdep_start) - extern int __libc_multiple_libcs; /* Defined in init-first.c. */ /* We must be careful not to leave us in an inconsistent state. Thus we diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c index 832a57b6d6..6fdcb13145 100644 --- a/elf/dl-sysdep.c +++ b/elf/dl-sysdep.c @@ -214,10 +214,15 @@ _dl_sysdep_start (void **start_argptr, GLRO(dl_pagesize) = __getpagesize (); #endif -#if defined NEED_DL_SYSINFO - /* Only set the sysinfo value if we also have the vsyscall DSO. */ - if (GLRO(dl_sysinfo_dso) != 0 && new_sysinfo) - GLRO(dl_sysinfo) = new_sysinfo; +#ifdef NEED_DL_SYSINFO + if (new_sysinfo != 0) + { +# ifdef NEED_DL_SYSINFO_DSO + /* Only set the sysinfo value if we also have the vsyscall DSO. */ + if (GLRO(dl_sysinfo_dso) != 0) +# endif + GLRO(dl_sysinfo) = new_sysinfo; + } #endif #ifdef DL_SYSDEP_INIT diff --git a/elf/dl-writev.h b/elf/dl-writev.h new file mode 100644 index 0000000000..0fc0b2b864 --- /dev/null +++ b/elf/dl-writev.h @@ -0,0 +1,56 @@ +/* Message-writing for the dynamic linker. Generic version. + Copyright (C) 2013 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 <sys/uio.h> +#include <ldsodefs.h> +#include <bits/libc-lock.h> + +/* This is used from only one place: dl-misc.c:_dl_debug_vdprintf. + Hence it's in a header with the expectation it will be inlined. + + This is writev, but with a constraint added and others loosened: + + 1. Under RTLD_PRIVATE_ERRNO, it must not clobber the private errno + when another thread holds the dl_load_lock. + 2. It is not obliged to detect and report errors at all. + 3. It's not really obliged to deliver a single atomic write + (though it may be preferable). */ + +static inline void +_dl_writev (int fd, const struct iovec *iov, size_t niov) +{ + /* Note that if __writev is an implementation that calls malloc, + this will cause linking problems building the dynamic linker. */ + +#if RTLD_PRIVATE_ERRNO + /* We have to take this lock just to be sure we don't clobber the private + errno when it's being used by another thread that cares about it. + Yet we must be sure not to try calling the lock functions before + the thread library is fully initialized. */ + if (__builtin_expect (INTUSE (_dl_starting_up), 0)) + __writev (fd, iov, niov); + else + { + __rtld_lock_lock_recursive (GL(dl_load_lock)); + __writev (fd, iov, niov); + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + } +#else + __writev (fd, iov, niov); +#endif +} diff --git a/elf/ldconfig.c b/elf/ldconfig.c index 57c6a6f04d..340c132a83 100644 --- a/elf/ldconfig.c +++ b/elf/ldconfig.c @@ -173,13 +173,17 @@ is_hwcap_platform (const char *name) { int hwcap_idx = _dl_string_hwcap (name); + /* Is this a normal hwcap for the machine e.g. fpu? */ if (hwcap_idx != -1 && ((1 << hwcap_idx) & hwcap_mask)) return 1; + /* ... Or is it a platform pseudo-hwcap e.g. i686? */ hwcap_idx = _dl_string_platform (name); if (hwcap_idx != -1) return 1; + /* ... Or is this one of the extra pseudo-hwcaps that we map beyond + _DL_FIRST_EXTRA e.g. tls, or nosegneg? */ for (hwcap_idx = _DL_FIRST_EXTRA; hwcap_idx < 64; ++hwcap_idx) if (hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA] != NULL && !strcmp (name, hwcap_extra[hwcap_idx - _DL_FIRST_EXTRA])) @@ -1265,6 +1269,8 @@ main (int argc, char **argv) add_dir (argv[i]); } + /* The last entry in hwcap_extra is reserved for the "tls" + pseudo-hwcap which indicates support for TLS. */ hwcap_extra[63 - _DL_FIRST_EXTRA] = "tls"; set_hwcap (); diff --git a/elf/sprof.c b/elf/sprof.c index 54dfebdd5a..5c70ec0473 100644 --- a/elf/sprof.c +++ b/elf/sprof.c @@ -744,7 +744,7 @@ load_profdata (const char *name, struct shobj *shobj) { struct profdata *result; int fd; - struct stat st; + struct stat64 st; void *addr; uint32_t *narcsp; size_t fromlimit; @@ -783,7 +783,7 @@ load_profdata (const char *name, struct shobj *shobj) /* We have found the file, now make sure it is the right one for the data file. */ - if (fstat (fd, &st) < 0) + if (fstat64 (fd, &st) < 0) { error (0, errno, _("while stat'ing profiling data file")); close (fd); |