summaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
authorThomas Schwinge <thomas@codesourcery.com>2013-12-20 09:29:29 +0100
committerThomas Schwinge <thomas@codesourcery.com>2013-12-20 09:29:29 +0100
commita65dd355fb80a05215e15ae97649de52aec885e3 (patch)
tree81701bb0c6b648630f2bf1729a85d7f5eb49e67b /elf
parent296a5732f94abe4d5699dc981e4ccfb950b48cee (diff)
parentb4578bab30f72cddd2cf38abfb39f9c8dc892249 (diff)
Merge branch 'baseline' into refs/top-bases/tschwinge/Roger_Whittaker
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile17
-rw-r--r--elf/Versions1
-rw-r--r--elf/cache.c9
-rw-r--r--elf/dl-close.c5
-rw-r--r--elf/dl-deps.c1
-rw-r--r--elf/dl-error.c72
-rw-r--r--elf/dl-fini.c2
-rw-r--r--elf/dl-init.c8
-rw-r--r--elf/dl-libc.c1
-rw-r--r--elf/dl-load.c26
-rw-r--r--elf/dl-lookup.c2
-rw-r--r--elf/dl-misc.c142
-rw-r--r--elf/dl-object.c8
-rw-r--r--elf/dl-support.c6
-rw-r--r--elf/dl-tls.c44
-rw-r--r--elf/elf.h141
-rw-r--r--elf/ldd.bash.in25
-rw-r--r--elf/rtld.c11
-rw-r--r--elf/tlsdeschtab.h6
-rw-r--r--elf/tst-auxv.c69
-rw-r--r--elf/tst-ptrguard1-static.c1
-rw-r--r--elf/tst-ptrguard1.c202
-rw-r--r--elf/tst-tls-dlinfo.c2
-rw-r--r--elf/tst-tls1.c2
-rw-r--r--elf/tst-tls10.h1
-rw-r--r--elf/tst-tls14.c2
-rw-r--r--elf/tst-tls2.c2
-rw-r--r--elf/tst-tls3.c2
-rw-r--r--elf/tst-tls4.c2
-rw-r--r--elf/tst-tls5.c2
-rw-r--r--elf/tst-tls6.c1
-rw-r--r--elf/tst-tls7.c1
-rw-r--r--elf/tst-tls8.c1
-rw-r--r--elf/tst-tls9.c1
-rw-r--r--elf/tst-tlsmod1.c2
-rw-r--r--elf/tst-tlsmod13.c2
-rw-r--r--elf/tst-tlsmod13a.c2
-rw-r--r--elf/tst-tlsmod14a.c2
-rw-r--r--elf/tst-tlsmod16a.c2
-rw-r--r--elf/tst-tlsmod16b.c2
-rw-r--r--elf/tst-tlsmod2.c2
-rw-r--r--elf/tst-tlsmod3.c2
-rw-r--r--elf/tst-tlsmod4.c2
-rw-r--r--elf/tst-tlsmod5.c2
-rw-r--r--elf/tst-tlsmod6.c2
45 files changed, 705 insertions, 135 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 3b58649de5..c6626e14bf 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -59,7 +59,7 @@ before-compile = $(objpfx)trusted-dirs.h
generated := trusted-dirs.h trusted-dirs.st for-renamed/renamed.so
generated-dirs := for-renamed
-ifeq ($(versioning),yes)
+ifeq ($(build-shared),yes)
ld-map = $(common-objpfx)ld.map
endif
@@ -119,9 +119,11 @@ $(inst_auditdir)/sotruss-lib.so: $(objpfx)sotruss-lib.so $(+force)
endif
tests = tst-tls1 tst-tls2 tst-tls9 tst-leaks1 \
- tst-array1 tst-array2 tst-array3 tst-array4 tst-array5
+ tst-array1 tst-array2 tst-array3 tst-array4 tst-array5 \
+ tst-auxv
tests-static = tst-tls1-static tst-tls2-static tst-stackguard1-static \
- tst-leaks1-static tst-array1-static tst-array5-static
+ tst-leaks1-static tst-array1-static tst-array5-static \
+ tst-ptrguard1-static
ifeq (yes,$(build-shared))
tests-static += tst-tls9-static
tst-tls9-static-ENV = \
@@ -145,7 +147,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
tst-audit1 tst-audit2 tst-audit8 \
tst-stackguard1 tst-addr1 tst-thrlock \
tst-unique1 tst-unique2 tst-unique3 tst-unique4 \
- tst-initorder tst-initorder2 tst-relsort1 tst-null-argv
+ tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \
+ tst-ptrguard1
# reldep9
test-srcs = tst-pathopt
selinux-enabled := $(shell cat /selinux/enforce 2> /dev/null)
@@ -1016,6 +1019,12 @@ LDFLAGS-order2mod2.so = $(no-as-needed)
tst-stackguard1-ARGS = --command "$(host-test-program-cmd) --child"
tst-stackguard1-static-ARGS = --command "$(objpfx)tst-stackguard1-static --child"
+tst-ptrguard1-ARGS = --command "$(host-test-program-cmd) --child"
+# When built statically, the pointer guard interface uses
+# __pointer_chk_guard_local.
+CFLAGS-tst-ptrguard1-static.c = -DPTRGUARD_LOCAL
+tst-ptrguard1-static-ARGS = --command "$(objpfx)tst-ptrguard1-static --child"
+
$(objpfx)tst-leaks1: $(libdl)
$(objpfx)tst-leaks1-mem: $(objpfx)tst-leaks1.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1.mtrace > $@
diff --git a/elf/Versions b/elf/Versions
index 238399232d..01b7a59d5e 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -53,6 +53,7 @@ ld {
_dl_allocate_tls; _dl_allocate_tls_init;
_dl_argv; _dl_find_dso_for_object; _dl_get_tls_static_info;
_dl_deallocate_tls; _dl_make_stack_executable; _dl_out_of_memory;
+ _dl_clear_dtv;
_dl_rtld_di_serinfo; _dl_starting_up; _dl_tls_setup;
_rtld_global; _rtld_global_ro;
diff --git a/elf/cache.c b/elf/cache.c
index 9bf261cd29..1a43dd7765 100644
--- a/elf/cache.c
+++ b/elf/cache.c
@@ -105,6 +105,15 @@ print_entry (const char *lib, int flag, unsigned int osversion,
case FLAG_ARM_LIBSF:
fputs (",soft-float", stdout);
break;
+ case FLAG_MIPS_LIB32_NAN2008:
+ fputs (",nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN32_NAN2008:
+ fputs (",N32,nan2008", stdout);
+ break;
+ case FLAG_MIPS64_LIBN64_NAN2008:
+ fputs (",64bit,nan2008", stdout);
+ break;
case 0:
break;
default:
diff --git a/elf/dl-close.c b/elf/dl-close.c
index fe3014cca3..407926bade 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -274,9 +274,8 @@ _dl_close_worker (struct link_map *map)
/* Next try the old-style destructor. */
if (imap->l_info[DT_FINI] != NULL)
- (*(void (*) (void)) DL_DT_FINI_ADDRESS
- (imap, ((void *) imap->l_addr
- + imap->l_info[DT_FINI]->d_un.d_ptr))) ();
+ DL_CALL_DT_FINI (imap, ((void *) imap->l_addr
+ + imap->l_info[DT_FINI]->d_un.d_ptr));
}
#ifdef SHARED
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index 1c36f501bc..6652f6d0cd 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -595,7 +595,6 @@ Filters not supported with LD_TRACE_PRELINKING"));
if (list[i]->l_reserved)
{
/* Need to allocate new array of relocation dependencies. */
- struct link_map_reldeps *l_reldeps;
l_reldeps = malloc (sizeof (*l_reldeps)
+ map->l_reldepsmax
* sizeof (struct link_map *));
diff --git a/elf/dl-error.c b/elf/dl-error.c
index 8257c17030..79e3fa38f2 100644
--- a/elf/dl-error.c
+++ b/elf/dl-error.c
@@ -28,10 +28,11 @@
_dl_signal_error. */
struct catch
{
- const char *objname; /* Object/File name. */
- const char *errstring; /* Error detail filled in here. */
- bool malloced; /* Nonzero if the string is malloced
+ const char **objname; /* Object/File name. */
+ const char **errstring; /* Error detail filled in here. */
+ bool *malloced; /* Nonzero if the string is malloced
by the libc malloc. */
+ volatile int *errcode; /* Return value of _dl_signal_error. */
jmp_buf env; /* longjmp here on error. */
};
@@ -86,33 +87,36 @@ _dl_signal_error (int errcode, const char *objname, const char *occation,
size_t len_objname = strlen (objname) + 1;
size_t len_errstring = strlen (errstring) + 1;
- lcatch->errstring = (char *) malloc (len_objname + len_errstring);
- if (lcatch->errstring != NULL)
+ char *errstring_copy = malloc (len_objname + len_errstring);
+ if (errstring_copy != NULL)
{
/* Make a copy of the object file name and the error string. */
- lcatch->objname = memcpy (__mempcpy ((char *) lcatch->errstring,
- errstring, len_errstring),
- objname, len_objname);
+ *lcatch->objname = memcpy (__mempcpy (errstring_copy,
+ errstring, len_errstring),
+ objname, len_objname);
+ *lcatch->errstring = errstring_copy;
/* If the main executable is relocated it means the libc's malloc
is used. */
+ bool malloced = true;
#ifdef SHARED
- lcatch->malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
- && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated
- != 0));
-#else
- lcatch->malloced = true;
+ malloced = (GL(dl_ns)[LM_ID_BASE]._ns_loaded != NULL
+ && (GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_relocated != 0));
#endif
+ *lcatch->malloced = malloced;
}
else
{
/* This is better than nothing. */
- lcatch->objname = "";
- lcatch->errstring = _dl_out_of_memory;
- lcatch->malloced = false;
+ *lcatch->objname = "";
+ *lcatch->errstring = _dl_out_of_memory;
+ *lcatch->malloced = false;
}
+
+ *lcatch->errcode = errcode;
+
/* We do not restore the signal mask because none was saved. */
- __longjmp (lcatch->env[0].__jmpbuf, errcode ?: -1);
+ __longjmp (lcatch->env[0].__jmpbuf, 1);
}
else
{
@@ -157,23 +161,29 @@ internal_function
_dl_catch_error (const char **objname, const char **errstring,
bool *mallocedp, void (*operate) (void *), void *args)
{
- int errcode;
- struct catch *volatile old;
- struct catch c;
/* We need not handle `receiver' since setting a `catch' is handled
before it. */
- /* Some systems (e.g., SPARC) handle constructors to local variables
- inefficient. So we initialize `c' by hand. */
- c.errstring = NULL;
+ /* Only this needs to be marked volatile, because it is the only local
+ variable that gets changed between the setjmp invocation and the
+ longjmp call. All others are just set here (before setjmp) and read
+ in _dl_signal_error (before longjmp). */
+ volatile int errcode;
+
+ struct catch c;
+ /* Don't use an initializer since we don't need to clear C.env. */
+ c.objname = objname;
+ c.errstring = errstring;
+ c.malloced = mallocedp;
+ c.errcode = &errcode;
struct catch **const catchp = &CATCH_HOOK;
- old = *catchp;
+ struct catch *const old = *catchp;
+ *catchp = &c;
+
/* Do not save the signal mask. */
- errcode = __sigsetjmp (c.env, 0);
- if (__builtin_expect (errcode, 0) == 0)
+ if (__builtin_expect (__sigsetjmp (c.env, 0), 0) == 0)
{
- *catchp = &c;
(*operate) (args);
*catchp = old;
*objname = NULL;
@@ -182,12 +192,10 @@ _dl_catch_error (const char **objname, const char **errstring,
return 0;
}
- /* We get here only if we longjmp'd out of OPERATE. */
+ /* We get here only if we longjmp'd out of OPERATE. _dl_signal_error has
+ already stored values into *OBJNAME, *ERRSTRING, and *MALLOCEDP. */
*catchp = old;
- *objname = c.objname;
- *errstring = c.errstring;
- *mallocedp = c.malloced;
- return errcode == -1 ? 0 : errcode;
+ return errcode;
}
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index 6b245f0022..db5269c82f 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -254,7 +254,7 @@ _dl_fini (void)
/* Next try the old-style destructor. */
if (l->l_info[DT_FINI] != NULL)
- ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
+ DL_CALL_DT_FINI(l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr);
}
#ifdef SHARED
diff --git a/elf/dl-init.c b/elf/dl-init.c
index a657eb6c40..40783684f2 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -61,13 +61,7 @@ call_init (struct link_map *l, int argc, char **argv, char **env)
- the others in the DT_INIT_ARRAY.
*/
if (l->l_info[DT_INIT] != NULL)
- {
- init_t init = (init_t) DL_DT_INIT_ADDRESS
- (l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr);
-
- /* Call the function. */
- init (argc, argv, env);
- }
+ DL_CALL_DT_INIT(l, l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr, argc, argv, env);
/* Next see whether there is an array with initialization functions. */
ElfW(Dyn) *init_array = l->l_info[DT_INIT_ARRAY];
diff --git a/elf/dl-libc.c b/elf/dl-libc.c
index aba0d1af19..397d898993 100644
--- a/elf/dl-libc.c
+++ b/elf/dl-libc.c
@@ -286,6 +286,7 @@ libc_freeres_fn (free_mem)
/* Free the initfini dependency list. */
if (l->l_free_initfini)
free (l->l_initfini);
+ l->l_initfini = NULL;
}
if (__builtin_expect (GL(dl_ns)[ns]._ns_global_scope_alloc, 0) != 0
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 6a73f27345..d3e1cf8f9c 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -481,14 +481,19 @@ static size_t max_dirnamelen;
static struct r_search_path_elem **
fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
- int check_trusted, const char *what, const char *where)
+ int check_trusted, const char *what, const char *where,
+ struct link_map *l)
{
char *cp;
size_t nelems = 0;
+ char *to_free;
while ((cp = __strsep (&rpath, sep)) != NULL)
{
struct r_search_path_elem *dirp;
+
+ to_free = cp = expand_dynamic_string_token (l, cp, 1);
+
size_t len = strlen (cp);
/* `strsep' can pass an empty string. This has to be
@@ -509,7 +514,10 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
/* Make sure we don't use untrusted directories if we run SUID. */
if (__builtin_expect (check_trusted, 0) && !is_trusted_path (cp, len))
- continue;
+ {
+ free (to_free);
+ continue;
+ }
/* See if this directory is already known. */
for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
@@ -570,6 +578,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
/* Put it in the result array. */
result[nelems++] = dirp;
}
+ free (to_free);
}
/* Terminate the array. */
@@ -625,9 +634,8 @@ decompose_rpath (struct r_search_path_struct *sps,
while (*inhp != '\0');
}
- /* Make a writable copy. At the same time expand possible dynamic
- string tokens. */
- copy = expand_dynamic_string_token (l, rpath, 1);
+ /* Make a writable copy. */
+ copy = local_strdup (rpath);
if (copy == NULL)
{
errstring = N_("cannot create RUNPATH/RPATH copy");
@@ -660,7 +668,7 @@ decompose_rpath (struct r_search_path_struct *sps,
_dl_signal_error (ENOMEM, NULL, NULL, errstring);
}
- fillin_rpath (copy, result, ":", 0, what, where);
+ fillin_rpath (copy, result, ":", 0, what, where, l);
/* Free the copied RPATH string. `fillin_rpath' make own copies if
necessary. */
@@ -708,9 +716,7 @@ _dl_init_paths (const char *llp)
const char *strp;
struct r_search_path_elem *pelem, **aelem;
size_t round_size;
-#ifdef SHARED
- struct link_map *l;
-#endif
+ struct link_map __attribute__ ((unused)) *l = NULL;
/* Initialize to please the compiler. */
const char *errstring = NULL;
@@ -865,7 +871,7 @@ _dl_init_paths (const char *llp)
(void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH",
- NULL);
+ NULL, l);
if (env_path_list.dirs[0] == NULL)
{
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 39f463eae1..f869dcfa96 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -746,7 +746,7 @@ _dl_lookup_symbol_x (const char *undef_name, struct link_map *undef_map,
contain the needed symbol. This code is never reached
for unversioned lookups. */
assert (version != NULL);
- const char *reference_name = undef_map ? undef_map->l_name : NULL;
+ const char *reference_name = undef_map ? undef_map->l_name : "";
/* XXX We cannot translate the message. */
_dl_signal_cerror (0, DSO_FILENAME (reference_name),
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
index 5fc13a44a4..b529af3f4b 100644
--- a/elf/dl-misc.c
+++ b/elf/dl-misc.c
@@ -19,6 +19,7 @@
#include <assert.h>
#include <fcntl.h>
#include <ldsodefs.h>
+#include <libc-symbols.h>
#include <limits.h>
#include <link.h>
#include <stdarg.h>
@@ -364,3 +365,144 @@ _dl_higher_prime_number (unsigned long int n)
return *low;
}
+
+/* To support accessing TLS variables from signal handlers, we need an
+ async signal safe memory allocator. These routines are never
+ themselves invoked reentrantly (all calls to them are surrounded by
+ signal masks) but may be invoked concurrently from many threads.
+ The current implementation is not particularly performant nor space
+ efficient, but it will be used rarely (and only in binaries that use
+ dlopen.) The API matches that of malloc() and friends. */
+
+struct __signal_safe_allocator_header
+{
+ size_t size;
+ void *start;
+};
+
+static inline struct __signal_safe_allocator_header *
+ptr_to_signal_safe_allocator_header (void *ptr)
+{
+ return (struct __signal_safe_allocator_header *)
+ ((char *) (ptr) - sizeof (struct __signal_safe_allocator_header));
+}
+
+void *weak_function
+__signal_safe_memalign (size_t boundary, size_t size)
+{
+ struct __signal_safe_allocator_header *header;
+
+ if (boundary < sizeof (*header))
+ boundary = sizeof (*header);
+
+ /* Boundary must be a power of two. */
+ if (!powerof2 (boundary))
+ return NULL;
+
+ size_t pg = GLRO (dl_pagesize);
+ size_t padded_size;
+ if (boundary <= pg)
+ {
+ /* We'll get a pointer certainly aligned to boundary, so just
+ add one more boundary-sized chunk to hold the header. */
+ padded_size = roundup (size, boundary) + boundary;
+ }
+ else
+ {
+ /* If we want K pages aligned to a J-page boundary, K+J+1 pages
+ contains at least one such region that isn't directly at the start
+ (so we can place the header.) This is wasteful, but you're the one
+ who wanted 64K-aligned TLS. */
+ padded_size = roundup (size, pg) + boundary + pg;
+ }
+
+
+ size_t actual_size = roundup (padded_size, pg);
+ void *actual = mmap (NULL, actual_size, PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ if (actual == MAP_FAILED)
+ return NULL;
+
+ if (boundary <= pg)
+ {
+ header = actual + boundary - sizeof (*header);
+ }
+ else
+ {
+ intptr_t actual_pg = ((intptr_t) actual) / pg;
+ intptr_t boundary_pg = boundary / pg;
+ intptr_t start_pg = actual_pg + boundary_pg;
+ start_pg -= start_pg % boundary_pg;
+ if (start_pg > (actual_pg + 1))
+ {
+ int ret = munmap (actual, (start_pg - actual_pg - 1) * pg);
+ assert (ret == 0);
+ actual = (void *) ((start_pg - 1) * pg);
+ }
+ char *start = (void *) (start_pg * pg);
+ header = ptr_to_signal_safe_allocator_header (start);
+ }
+
+ header->size = actual_size;
+ header->start = actual;
+ void *ptr = header;
+ ptr += sizeof (*header);
+ if (((intptr_t) ptr) % boundary != 0)
+ _dl_fatal_printf ("__signal_safe_memalign produced incorrect alignment\n");
+ return ptr;
+}
+
+void * weak_function
+__signal_safe_malloc (size_t size)
+{
+ return __signal_safe_memalign (1, size);
+}
+
+void weak_function
+__signal_safe_free (void *ptr)
+{
+ if (ptr == NULL)
+ return;
+
+ struct __signal_safe_allocator_header *header
+ = ptr_to_signal_safe_allocator_header (ptr);
+ int ret = munmap (header->start, header->size);
+
+ assert (ret == 0);
+}
+
+void * weak_function
+__signal_safe_realloc (void *ptr, size_t size)
+{
+ if (size == 0)
+ {
+ __signal_safe_free (ptr);
+ return NULL;
+ }
+ if (ptr == NULL)
+ return __signal_safe_malloc (size);
+
+ struct __signal_safe_allocator_header *header
+ = ptr_to_signal_safe_allocator_header (ptr);
+ size_t old_size = header->size;
+ if (old_size - sizeof (*header) >= size)
+ return ptr;
+
+ void *new_ptr = __signal_safe_malloc (size);
+ if (new_ptr == NULL)
+ return NULL;
+
+ memcpy (new_ptr, ptr, old_size);
+ __signal_safe_free (ptr);
+
+ return new_ptr;
+}
+
+void * weak_function
+__signal_safe_calloc (size_t nmemb, size_t size)
+{
+ void *ptr = __signal_safe_malloc (nmemb * size);
+ if (ptr == NULL)
+ return NULL;
+ return memset (ptr, 0, nmemb * size);
+}
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 0f594d25e6..26d4f44375 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -88,7 +88,13 @@ _dl_new_object (char *realname, const char *libname, int type,
/* newname->next = NULL; We use calloc therefore not necessary. */
newname->dont_free = 1;
- new->l_name = realname;
+ /* When we create the executable link map, or a VDSO link map, we start
+ with "" for the l_name. In these cases "" points to ld.so rodata
+ and won't get dumped during core file generation. Therefore to assist
+ gdb and to create more self-contained core files we adjust l_name to
+ point at the newly allocated copy (which will get dumped) instead of
+ the ld.so rodata copy. */
+ new->l_name = *realname ? realname : (char *) newname->name + libname_len - 1;
new->l_type = type;
/* If we set the bit now since we know it is never used we avoid
dirtying the cache line later. */
diff --git a/elf/dl-support.c b/elf/dl-support.c
index e551078df1..c17fbf9a7b 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -167,6 +167,9 @@ size_t _dl_phnum;
uint64_t _dl_hwcap __attribute__ ((nocommon));
uint64_t _dl_hwcap2 __attribute__ ((nocommon));
+/* The value of the FPU control word the kernel will preset in hardware. */
+fpu_control_t _dl_fpu_control = _FPU_DEFAULT;
+
/* This is not initialized to HWCAP_IMPORTANT, matching the definition
of _dl_important_hwcaps, below, where no hwcap strings are ever
used. This mask is still used to mediate the lookups in the cache
@@ -254,6 +257,9 @@ _dl_aux_init (ElfW(auxv_t) *av)
case AT_HWCAP2:
GLRO(dl_hwcap2) = (unsigned long int) av->a_un.a_val;
break;
+ case AT_FPUCW:
+ GLRO(dl_fpu_control) = av->a_un.a_val;
+ break;
#ifdef NEED_DL_SYSINFO
case AT_SYSINFO:
GL(dl_sysinfo) = av->a_un.a_val;
diff --git a/elf/dl-tls.c b/elf/dl-tls.c
index 576d9a1465..12e6e8f3e0 100644
--- a/elf/dl-tls.c
+++ b/elf/dl-tls.c
@@ -293,7 +293,7 @@ allocate_dtv (void *result)
initial set of modules. This should avoid in most cases expansions
of the dtv. */
dtv_length = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
- dtv = calloc (dtv_length + 2, sizeof (dtv_t));
+ dtv = __signal_safe_calloc (dtv_length + 2, sizeof (dtv_t));
if (dtv != NULL)
{
/* This is the initial length of the dtv. */
@@ -463,6 +463,18 @@ _dl_allocate_tls (void *mem)
}
rtld_hidden_def (_dl_allocate_tls)
+void
+internal_function
+_dl_clear_dtv (dtv_t *dtv)
+{
+ for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
+ if (! dtv[1 + cnt].pointer.is_static
+ && dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
+ __signal_safe_free (dtv[1 + cnt].pointer.val);
+ memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
+}
+
+rtld_hidden_def (_dl_clear_dtv)
#ifndef SHARED
extern dtv_t _dl_static_dtv[];
@@ -479,11 +491,11 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
if (! dtv[1 + cnt].pointer.is_static
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
- free (dtv[1 + cnt].pointer.val);
+ __signal_safe_free (dtv[1 + cnt].pointer.val);
/* The array starts with dtv[-1]. */
if (dtv != GL(dl_initial_dtv))
- free (dtv - 1);
+ __signal_safe_free (dtv - 1);
if (dealloc_tcb)
{
@@ -525,8 +537,7 @@ static void *
allocate_and_init (struct link_map *map)
{
void *newp;
-
- newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
+ newp = __signal_safe_memalign (map->l_tls_align, map->l_tls_blocksize);
if (newp == NULL)
oom ();
@@ -596,25 +607,27 @@ _dl_update_slotinfo (unsigned long int req_modid)
if (gen <= dtv[0].counter)
continue;
+ size_t modid = total + cnt;
+
/* If there is no map this means the entry is empty. */
struct link_map *map = listp->slotinfo[cnt].map;
if (map == NULL)
{
/* If this modid was used at some point the memory
might still be allocated. */
- if (! dtv[total + cnt].pointer.is_static
- && dtv[total + cnt].pointer.val != TLS_DTV_UNALLOCATED)
+ if (dtv[-1].counter >= modid
+ && !dtv[modid].pointer.is_static
+ && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
{
- free (dtv[total + cnt].pointer.val);
- dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
+ __signal_safe_free (dtv[modid].pointer.val);
+ dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
}
continue;
}
+ assert (modid == map->l_tls_modid);
/* Check whether the current dtv array is large enough. */
- size_t modid = map->l_tls_modid;
- assert (total + cnt == modid);
if (dtv[-1].counter < modid)
{
/* Reallocate the dtv. */
@@ -628,17 +641,18 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
/* This is the initial dtv that was allocated
during rtld startup using the dl-minimal.c
- malloc instead of the real malloc. We can't
+ malloc instead of the real allocator. We can't
free it, we have to abandon the old storage. */
- newp = malloc ((2 + newsize) * sizeof (dtv_t));
+ newp = __signal_safe_malloc (
+ (2 + newsize) * sizeof (dtv_t));
if (newp == NULL)
oom ();
memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
}
else
{
- newp = realloc (&dtv[-1],
+ newp = __signal_safe_realloc (&dtv[-1],
(2 + newsize) * sizeof (dtv_t));
if (newp == NULL)
oom ();
@@ -668,7 +682,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
deallocate even if it is this dtv entry we are
supposed to load. The reason is that we call
memalign and not malloc. */
- free (dtv[modid].pointer.val);
+ __signal_safe_free (dtv[modid].pointer.val);
/* This module is loaded dynamically- We defer memory
allocation. */
diff --git a/elf/elf.h b/elf/elf.h
index fe55c928cd..08b4ed8893 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1383,6 +1383,7 @@ typedef struct
#define EF_MIPS_64BIT_WHIRL 16
#define EF_MIPS_ABI2 32
#define EF_MIPS_ABI_ON32 64
+#define EF_MIPS_NAN2008 1024 /* Uses IEEE 754-2008 NaN encoding. */
#define EF_MIPS_ARCH 0xf0000000 /* MIPS architecture level. */
/* Legal values for MIPS architecture level. */
@@ -2251,6 +2252,17 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_PPC64_DTPREL16_HIGHERA 104 /* half16 (sym+add)@dtprel@highera */
#define R_PPC64_DTPREL16_HIGHEST 105 /* half16 (sym+add)@dtprel@highest */
#define R_PPC64_DTPREL16_HIGHESTA 106 /* half16 (sym+add)@dtprel@highesta */
+#define R_PPC64_TLSGD 107 /* none (sym+add)@tlsgd */
+#define R_PPC64_TLSLD 108 /* none (sym+add)@tlsld */
+#define R_PPC64_TOCSAVE 109 /* none */
+
+/* Added when HA and HI relocs were changed to report overflows. */
+#define R_PPC64_ADDR16_HIGH 110
+#define R_PPC64_ADDR16_HIGHA 111
+#define R_PPC64_TPREL16_HIGH 112
+#define R_PPC64_TPREL16_HIGHA 113
+#define R_PPC64_DTPREL16_HIGH 114
+#define R_PPC64_DTPREL16_HIGHA 115
/* GNU extension to support local ifunc. */
#define R_PPC64_JMP_IREL 247
@@ -2260,12 +2272,29 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_PPC64_REL16_HI 251 /* half16 (sym+add-.)@h */
#define R_PPC64_REL16_HA 252 /* half16 (sym+add-.)@ha */
+/* e_flags bits specifying ABI.
+ 1 for original function descriptor using ABI,
+ 2 for revised ABI without function descriptors,
+ 0 for unspecified or not using any features affected by the differences. */
+#define EF_PPC64_ABI 3
+
/* PowerPC64 specific values for the Dyn d_tag field. */
#define DT_PPC64_GLINK (DT_LOPROC + 0)
#define DT_PPC64_OPD (DT_LOPROC + 1)
#define DT_PPC64_OPDSZ (DT_LOPROC + 2)
+#define DT_PPC64_OPT (DT_LOPROC + 3)
#define DT_PPC64_NUM 3
+/* PowerPC64 specific values for the DT_PPC64_OPT Dyn entry. */
+#define PPC64_OPT_TLS 1
+#define PPC64_OPT_MULTI_TOC 2
+
+/* PowerPC64 specific values for the Elf64_Sym st_other field. */
+#define STO_PPC64_LOCAL_BIT 5
+#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
+#define PPC64_LOCAL_ENTRY_OFFSET(other) \
+ (((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
+
/* ARM specific declarations */
@@ -2335,6 +2364,117 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_AARCH64_NONE 0 /* No relocation. */
#define R_AARCH64_ABS64 257 /* Direct 64 bit. */
#define R_AARCH64_ABS32 258 /* Direct 32 bit. */
+#define R_AARCH64_ABS16 259 /* Direct 16-bit. */
+#define R_AARCH64_PREL64 260 /* PC-relative 64-bit. */
+#define R_AARCH64_PREL32 261 /* PC-relative 32-bit. */
+#define R_AARCH64_PREL16 262 /* PC-relative 16-bit. */
+#define R_AARCH64_MOVW_UABS_G0 263 /* Dir. MOVZ imm. from bits 15:0. */
+#define R_AARCH64_MOVW_UABS_G0_NC 264 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G1 265 /* Dir. MOVZ imm. from bits 31:16. */
+#define R_AARCH64_MOVW_UABS_G1_NC 266 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G2 267 /* Dir. MOVZ imm. from bits 47:32. */
+#define R_AARCH64_MOVW_UABS_G2_NC 268 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_UABS_G3 269 /* Dir. MOV{K,Z} imm. from 63:48. */
+#define R_AARCH64_MOVW_SABS_G0 270 /* Dir. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_SABS_G1 271 /* Dir. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_SABS_G2 272 /* Dir. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_LD_PREL_LO19 273 /* PC-rel. LD imm. from bits 20:2. */
+#define R_AARCH64_ADR_PREL_LO21 274 /* PC-rel. ADR imm. from bits 20:0. */
+#define R_AARCH64_ADR_PREL_PG_HI21 275 /* Page-rel. ADRP imm. from 32:12. */
+#define R_AARCH64_ADR_PREL_PG_HI21_NC 276 /* Likewise; no overflow check. */
+#define R_AARCH64_ADD_ABS_LO12_NC 277 /* Dir. ADD imm. from bits 11:0. */
+#define R_AARCH64_LDST8_ABS_LO12_NC 278 /* Likewise for LD/ST; no check. */
+#define R_AARCH64_TSTBR14 279 /* PC-rel. TBZ/TBNZ imm. from 15:2. */
+#define R_AARCH64_CONDBR19 280 /* PC-rel. cond. br. imm. from 20:2. */
+#define R_AARCH64_JUMP26 282 /* PC-rel. B imm. from bits 27:2. */
+#define R_AARCH64_CALL26 283 /* Likewise for CALL. */
+#define R_AARCH64_LDST16_ABS_LO12_NC 284 /* Dir. ADD imm. from bits 11:1. */
+#define R_AARCH64_LDST32_ABS_LO12_NC 285 /* Likewise for bits 11:2. */
+#define R_AARCH64_LDST64_ABS_LO12_NC 286 /* Likewise for bits 11:3. */
+#define R_AARCH64_MOVW_PREL_G0 287 /* PC-rel. MOV{N,Z} imm. from 15:0. */
+#define R_AARCH64_MOVW_PREL_G0_NC 288 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G1 289 /* PC-rel. MOV{N,Z} imm. from 31:16. */
+#define R_AARCH64_MOVW_PREL_G1_NC 290 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G2 291 /* PC-rel. MOV{N,Z} imm. from 47:32. */
+#define R_AARCH64_MOVW_PREL_G2_NC 292 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_PREL_G3 293 /* PC-rel. MOV{N,Z} imm. from 63:48. */
+#define R_AARCH64_LDST128_ABS_LO12_NC 299 /* Dir. ADD imm. from bits 11:4. */
+#define R_AARCH64_MOVW_GOTOFF_G0 300 /* GOT-rel. off. MOV{N,Z} imm. 15:0. */
+#define R_AARCH64_MOVW_GOTOFF_G0_NC 301 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G1 302 /* GOT-rel. o. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_MOVW_GOTOFF_G1_NC 303 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G2 304 /* GOT-rel. o. MOV{N,Z} imm. 47:32. */
+#define R_AARCH64_MOVW_GOTOFF_G2_NC 305 /* Likewise for MOVK; no check. */
+#define R_AARCH64_MOVW_GOTOFF_G3 306 /* GOT-rel. o. MOV{N,Z} imm. 63:48. */
+#define R_AARCH64_GOTREL64 307 /* GOT-relative 64-bit. */
+#define R_AARCH64_GOTREL32 308 /* GOT-relative 32-bit. */
+#define R_AARCH64_GOT_LD_PREL19 309 /* PC-rel. GOT off. load imm. 20:2. */
+#define R_AARCH64_LD64_GOTOFF_LO15 310 /* GOT-rel. off. LD/ST imm. 14:3. */
+#define R_AARCH64_ADR_GOT_PAGE 311 /* P-page-rel. GOT off. ADRP 32:12. */
+#define R_AARCH64_LD64_GOT_LO12_NC 312 /* Dir. GOT off. LD/ST imm. 11:3. */
+#define R_AARCH64_LD64_GOTPAGE_LO15 313 /* GOT-page-rel. GOT off. LD/ST 14:3 */
+#define R_AARCH64_TLSGD_ADR_PREL21 512 /* PC-relative ADR imm. 20:0. */
+#define R_AARCH64_TLSGD_ADR_PAGE21 513 /* page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSGD_ADD_LO12_NC 514 /* direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSGD_MOVW_G1 515 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSGD_MOVW_G0_NC 516 /* GOT-rel. MOVK imm. 15:0. */
+#define R_AARCH64_TLSLD_ADR_PREL21 517 /* Like 512; local dynamic model. */
+#define R_AARCH64_TLSLD_ADR_PAGE21 518 /* Like 513; local dynamic model. */
+#define R_AARCH64_TLSLD_ADD_LO12_NC 519 /* Like 514; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G1 520 /* Like 515; local dynamic model. */
+#define R_AARCH64_TLSLD_MOVW_G0_NC 521 /* Like 516; local dynamic model. */
+#define R_AARCH64_TLSLD_LD_PREL19 522 /* TLS PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G2 523 /* TLS DTP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1 524 /* TLS DTP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC 525 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0 526 /* TLS DTP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC 527 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_HI12 528 /* DTP-rel. ADD imm. from 23:12. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12 529 /* DTP-rel. ADD imm. from 11:0. */
+#define R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC 530 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12 531 /* DTP-rel. LD/ST imm. 11:0. */
+#define R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC 532 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12 533 /* DTP-rel. LD/ST imm. 11:1. */
+#define R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC 534 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12 535 /* DTP-rel. LD/ST imm. 11:2. */
+#define R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC 536 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12 537 /* DTP-rel. LD/ST imm. 11:3. */
+#define R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC 538 /* Likewise; no check. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G1 539 /* GOT-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC 540 /* GOT-rel. MOVK 15:0. */
+#define R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 541 /* Page-rel. ADRP 32:12. */
+#define R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC 542 /* Direct LD off. 11:3. */
+#define R_AARCH64_TLSIE_LD_GOTTPREL_PREL19 543 /* PC-rel. load imm. 20:2. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G2 544 /* TLS TP-rel. MOV{N,Z} 47:32. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1 545 /* TLS TP-rel. MOV{N,Z} 31:16. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G1_NC 546 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0 547 /* TLS TP-rel. MOV{N,Z} 15:0. */
+#define R_AARCH64_TLSLE_MOVW_TPREL_G0_NC 548 /* Likewise; MOVK; no check. */
+#define R_AARCH64_TLSLE_ADD_TPREL_HI12 549 /* TP-rel. ADD imm. 23:12. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12 550 /* TP-rel. ADD imm. 11:0. */
+#define R_AARCH64_TLSLE_ADD_TPREL_LO12_NC 551 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12 552 /* TP-rel. LD/ST off. 11:0. */
+#define R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC 553 /* Likewise; no ovfl. check. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12 554 /* TP-rel. LD/ST off. 11:1. */
+#define R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC 555 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12 556 /* TP-rel. LD/ST off. 11:2. */
+#define R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC 557 /* Likewise; no check. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12 558 /* TP-rel. LD/ST off. 11:3. */
+#define R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC 559 /* Likewise; no check. */
+#define R_AARCH64_TLSDESC_LD_PREL19 560 /* PC-rel. load immediate 20:2. */
+#define R_AARCH64_TLSDESC_ADR_PREL21 561 /* PC-rel. ADR immediate 20:0. */
+#define R_AARCH64_TLSDESC_ADR_PAGE21 562 /* Page-rel. ADRP imm. 32:12. */
+#define R_AARCH64_TLSDESC_LD64_LO12 563 /* Direct LD off. from 11:3. */
+#define R_AARCH64_TLSDESC_ADD_LO12 564 /* Direct ADD imm. from 11:0. */
+#define R_AARCH64_TLSDESC_OFF_G1 565 /* GOT-rel. MOV{N,Z} imm. 31:16. */
+#define R_AARCH64_TLSDESC_OFF_G0_NC 566 /* GOT-rel. MOVK imm. 15:0; no ck. */
+#define R_AARCH64_TLSDESC_LDR 567 /* Relax LDR. */
+#define R_AARCH64_TLSDESC_ADD 568 /* Relax ADD. */
+#define R_AARCH64_TLSDESC_CALL 569 /* Relax BLR. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12 570 /* TP-rel. LD/ST off. 11:4. */
+#define R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC 571 /* Likewise; no check. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12 572 /* DTP-rel. LD/ST imm. 11:4. */
+#define R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC 573 /* Likewise; no check. */
#define R_AARCH64_COPY 1024 /* Copy symbol at runtime. */
#define R_AARCH64_GLOB_DAT 1025 /* Create GOT entry. */
#define R_AARCH64_JUMP_SLOT 1026 /* Create PLT entry. */
@@ -2343,6 +2483,7 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_AARCH64_TLS_DTPREL64 1029 /* Module-relative offset, 64 bit. */
#define R_AARCH64_TLS_TPREL64 1030 /* TP-relative offset, 64 bit. */
#define R_AARCH64_TLSDESC 1031 /* TLS Descriptor. */
+#define R_AARCH64_IRELATIVE 1032 /* STT_GNU_IFUNC relocation. */
/* ARM relocs. */
diff --git a/elf/ldd.bash.in b/elf/ldd.bash.in
index 39aeca249d..c4a1a15139 100644
--- a/elf/ldd.bash.in
+++ b/elf/ldd.bash.in
@@ -106,19 +106,18 @@ if test "$unused" = yes; then
add_env="$add_env LD_DEBUG=\"$LD_DEBUG${LD_DEBUG:+,}unused\""
fi
-# The following use of cat is needed to make ldd work in SELinux
-# environments where the executed program might not have permissions
-# to write to the console/tty. But only bash 3.x supports the pipefail
-# option, and we don't bother to handle the case for older bash versions.
-if set -o pipefail 2> /dev/null; then
- try_trace() {
- eval $add_env '"$@"' | cat
- }
-else
- try_trace() {
- eval $add_env '"$@"'
- }
-fi
+# The following command substitution is needed to make ldd work in SELinux
+# environments where the RTLD might not have permission to write to the
+# terminal. The extra "x" character prevents the shell from trimming trailing
+# newlines from command substitution results. This function is defined as a
+# subshell compound list (using "(...)") to prevent parameter assignments from
+# affecting the calling shell execution environment.
+try_trace() (
+ output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $rc)
+ rc=$?
+ printf '%s' "${output%x}"
+ return $rc
+)
case $# in
0)
diff --git a/elf/rtld.c b/elf/rtld.c
index a0bda1d165..30cd6bb3dd 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -816,8 +816,8 @@ do_preload (char *fname, struct link_map *main_map, const char *where)
if (__builtin_expect (err_str != NULL, 0))
{
_dl_error_printf ("\
-ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
- fname, where);
+ERROR: ld.so: object '%s' from %s cannot be preloaded (%s): ignored.\n",
+ fname, where, err_str);
/* No need to call free, this is still before
the libc's malloc is used. */
}
@@ -1118,6 +1118,9 @@ of this helper program; chances are you did not intend to run this program.\n\
case AT_ENTRY:
av->a_un.a_val = *user_entry;
break;
+ case AT_EXECFN:
+ av->a_un.a_val = (uintptr_t) _dl_argv[0];
+ break;
}
#endif
}
@@ -2217,10 +2220,6 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
_dl_start_profile ();
}
-#ifndef NONTLS_INIT_TP
-# define NONTLS_INIT_TP do { } while (0)
-#endif
-
if (!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
++GL(dl_tls_generation);
diff --git a/elf/tlsdeschtab.h b/elf/tlsdeschtab.h
index 155f4fdd9b..8ce8249b92 100644
--- a/elf/tlsdeschtab.h
+++ b/elf/tlsdeschtab.h
@@ -102,6 +102,12 @@ _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
test.tlsinfo.ti_module = map->l_tls_modid;
test.tlsinfo.ti_offset = ti_offset;
entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
+ if (! entry)
+ {
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+ return 0;
+ }
+
if (*entry)
{
td = *entry;
diff --git a/elf/tst-auxv.c b/elf/tst-auxv.c
new file mode 100644
index 0000000000..0fb3ad5345
--- /dev/null
+++ b/elf/tst-auxv.c
@@ -0,0 +1,69 @@
+/* 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 <elf.h>
+#include <errno.h>
+#include <link.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <misc/sys/auxv.h>
+
+static int
+do_test (int argc, char *argv[])
+{
+ errno = 0;
+ const char *execfn = (const char *) getauxval (AT_NULL);
+
+ if (errno != ENOENT)
+ {
+ printf ("errno is %d rather than %d (ENOENT) on failure\n", errno,
+ ENOENT);
+ return 1;
+ }
+
+ if (execfn != NULL)
+ {
+ printf ("getauxval return value is nonzero on failure\n");
+ return 1;
+ }
+
+ errno = 0;
+ execfn = (const char *) getauxval (AT_EXECFN);
+
+ if (execfn == NULL)
+ {
+ printf ("No AT_EXECFN found, AT_EXECFN test skipped\n");
+ return 0;
+ }
+
+ if (errno != 0)
+ {
+ printf ("errno erroneously set to %d on success\n", errno);
+ return 1;
+ }
+
+ if (strcmp (argv[0], execfn) != 0)
+ {
+ printf ("Mismatch: argv[0]: %s vs. AT_EXECFN: %s\n", argv[0], execfn);
+ return 1;
+ }
+
+ return 0;
+}
+
+#include "../test-skeleton.c"
diff --git a/elf/tst-ptrguard1-static.c b/elf/tst-ptrguard1-static.c
new file mode 100644
index 0000000000..7aff3b7b5d
--- /dev/null
+++ b/elf/tst-ptrguard1-static.c
@@ -0,0 +1 @@
+#include "tst-ptrguard1.c"
diff --git a/elf/tst-ptrguard1.c b/elf/tst-ptrguard1.c
new file mode 100644
index 0000000000..c344a04db1
--- /dev/null
+++ b/elf/tst-ptrguard1.c
@@ -0,0 +1,202 @@
+/* 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 <errno.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/wait.h>
+#include <stackguard-macros.h>
+#include <tls.h>
+#include <unistd.h>
+
+#ifndef POINTER_CHK_GUARD
+extern uintptr_t __pointer_chk_guard;
+# define POINTER_CHK_GUARD __pointer_chk_guard
+#endif
+
+static const char *command;
+static bool child;
+static uintptr_t ptr_chk_guard_copy;
+static bool ptr_chk_guard_copy_set;
+static int fds[2];
+
+static void __attribute__ ((constructor))
+con (void)
+{
+ ptr_chk_guard_copy = POINTER_CHK_GUARD;
+ ptr_chk_guard_copy_set = true;
+}
+
+static int
+uintptr_t_cmp (const void *a, const void *b)
+{
+ if (*(uintptr_t *) a < *(uintptr_t *) b)
+ return 1;
+ if (*(uintptr_t *) a > *(uintptr_t *) b)
+ return -1;
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ if (!ptr_chk_guard_copy_set)
+ {
+ puts ("constructor has not been run");
+ return 1;
+ }
+
+ if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
+ {
+ puts ("POINTER_CHK_GUARD changed between constructor and do_test");
+ return 1;
+ }
+
+ if (child)
+ {
+ write (2, &ptr_chk_guard_copy, sizeof (ptr_chk_guard_copy));
+ return 0;
+ }
+
+ if (command == NULL)
+ {
+ puts ("missing --command or --child argument");
+ return 1;
+ }
+
+#define N 16
+ uintptr_t child_ptr_chk_guards[N + 1];
+ child_ptr_chk_guards[N] = ptr_chk_guard_copy;
+ int i;
+ for (i = 0; i < N; ++i)
+ {
+ if (pipe (fds) < 0)
+ {
+ printf ("couldn't create pipe: %m\n");
+ return 1;
+ }
+
+ pid_t pid = fork ();
+ if (pid < 0)
+ {
+ printf ("fork failed: %m\n");
+ return 1;
+ }
+
+ if (!pid)
+ {
+ if (ptr_chk_guard_copy != POINTER_CHK_GUARD)
+ {
+ puts ("POINTER_CHK_GUARD changed after fork");
+ exit (1);
+ }
+
+ close (fds[0]);
+ close (2);
+ dup2 (fds[1], 2);
+ close (fds[1]);
+
+ system (command);
+ exit (0);
+ }
+
+ close (fds[1]);
+
+ if (TEMP_FAILURE_RETRY (read (fds[0], &child_ptr_chk_guards[i],
+ sizeof (uintptr_t))) != sizeof (uintptr_t))
+ {
+ puts ("could not read ptr_chk_guard value from child");
+ return 1;
+ }
+
+ close (fds[0]);
+
+ pid_t termpid;
+ int status;
+ termpid = TEMP_FAILURE_RETRY (waitpid (pid, &status, 0));
+ if (termpid == -1)
+ {
+ printf ("waitpid failed: %m\n");
+ return 1;
+ }
+ else if (termpid != pid)
+ {
+ printf ("waitpid returned %ld != %ld\n",
+ (long int) termpid, (long int) pid);
+ return 1;
+ }
+ else if (!WIFEXITED (status) || WEXITSTATUS (status))
+ {
+ puts ("child hasn't exited with exit status 0");
+ return 1;
+ }
+ }
+
+ qsort (child_ptr_chk_guards, N + 1, sizeof (uintptr_t), uintptr_t_cmp);
+
+ /* The default pointer guard is the same as the default stack guard.
+ They are only set to default if dl_random is NULL. */
+ uintptr_t default_guard = 0;
+ unsigned char *p = (unsigned char *) &default_guard;
+ p[sizeof (uintptr_t) - 1] = 255;
+ p[sizeof (uintptr_t) - 2] = '\n';
+ p[0] = 0;
+
+ /* Test if the pointer guard canaries are either randomized,
+ or equal to the default pointer guard value.
+ Even with randomized pointer guards it might happen
+ that the random number generator generates the same
+ values, but if that happens in more than half from
+ the 16 runs, something is very wrong. */
+ int ndifferences = 0;
+ int ndefaults = 0;
+ for (i = 0; i < N; ++i)
+ {
+ if (child_ptr_chk_guards[i] != child_ptr_chk_guards[i+1])
+ ndifferences++;
+ else if (child_ptr_chk_guards[i] == default_guard)
+ ndefaults++;
+ }
+
+ printf ("differences %d defaults %d\n", ndifferences, ndefaults);
+
+ if (ndifferences < N / 2 && ndefaults < N / 2)
+ {
+ puts ("pointer guard values are not randomized enough");
+ puts ("nor equal to the default value");
+ return 1;
+ }
+
+ return 0;
+}
+
+#define OPT_COMMAND 10000
+#define OPT_CHILD 10001
+#define CMDLINE_OPTIONS \
+ { "command", required_argument, NULL, OPT_COMMAND }, \
+ { "child", no_argument, NULL, OPT_CHILD },
+#define CMDLINE_PROCESS \
+ case OPT_COMMAND: \
+ command = optarg; \
+ break; \
+ case OPT_CHILD: \
+ child = true; \
+ break;
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/elf/tst-tls-dlinfo.c b/elf/tst-tls-dlinfo.c
index 26c2811178..28661b19c2 100644
--- a/elf/tst-tls-dlinfo.c
+++ b/elf/tst-tls-dlinfo.c
@@ -2,8 +2,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <tls.h>
-
#define TEST_FUNCTION do_test ()
static int
diff --git a/elf/tst-tls1.c b/elf/tst-tls1.c
index 3b9b10f9aa..bec0a2ff26 100644
--- a/elf/tst-tls1.c
+++ b/elf/tst-tls1.c
@@ -1,8 +1,6 @@
/* glibc test for TLS in ld.so. */
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
diff --git a/elf/tst-tls10.h b/elf/tst-tls10.h
index 2b5709af72..7c8c6a6391 100644
--- a/elf/tst-tls10.h
+++ b/elf/tst-tls10.h
@@ -1,4 +1,3 @@
-#include <tls.h>
#include <stdlib.h>
struct A
diff --git a/elf/tst-tls14.c b/elf/tst-tls14.c
index ffd31e97be..6bacb599dd 100644
--- a/elf/tst-tls14.c
+++ b/elf/tst-tls14.c
@@ -4,8 +4,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <tls.h>
-
#define AL 4096
struct foo
{
diff --git a/elf/tst-tls2.c b/elf/tst-tls2.c
index 3d13272c08..d0b6d51402 100644
--- a/elf/tst-tls2.c
+++ b/elf/tst-tls2.c
@@ -1,8 +1,6 @@
/* glibc test for TLS in ld.so. */
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
diff --git a/elf/tst-tls3.c b/elf/tst-tls3.c
index c5e501eb4e..ca96c6a073 100644
--- a/elf/tst-tls3.c
+++ b/elf/tst-tls3.c
@@ -1,8 +1,6 @@
/* glibc test for TLS in ld.so. */
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
diff --git a/elf/tst-tls4.c b/elf/tst-tls4.c
index 4ae33db24d..63170c3478 100644
--- a/elf/tst-tls4.c
+++ b/elf/tst-tls4.c
@@ -2,8 +2,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <tls.h>
-
#define TEST_FUNCTION do_test ()
static int
diff --git a/elf/tst-tls5.c b/elf/tst-tls5.c
index 27b18294fb..76905c56db 100644
--- a/elf/tst-tls5.c
+++ b/elf/tst-tls5.c
@@ -2,8 +2,6 @@
#include <stdio.h>
#include <stdlib.h>
-#include <tls.h>
-
#define TEST_FUNCTION do_test ()
static int
diff --git a/elf/tst-tls6.c b/elf/tst-tls6.c
index 021622d9c7..9e6235f1d3 100644
--- a/elf/tst-tls6.c
+++ b/elf/tst-tls6.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
#include <link.h>
-#include <tls.h>
#define TEST_FUNCTION do_test ()
diff --git a/elf/tst-tls7.c b/elf/tst-tls7.c
index 1edc2b6356..23a16e4489 100644
--- a/elf/tst-tls7.c
+++ b/elf/tst-tls7.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
#include <link.h>
-#include <tls.h>
#define TEST_FUNCTION do_test ()
diff --git a/elf/tst-tls8.c b/elf/tst-tls8.c
index 36b1baca63..4bf3e3ffb5 100644
--- a/elf/tst-tls8.c
+++ b/elf/tst-tls8.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
#include <link.h>
-#include <tls.h>
#define TEST_FUNCTION do_test ()
diff --git a/elf/tst-tls9.c b/elf/tst-tls9.c
index 12078518fa..6306fb5658 100644
--- a/elf/tst-tls9.c
+++ b/elf/tst-tls9.c
@@ -3,7 +3,6 @@
#include <stdlib.h>
#include <link.h>
-#include <tls.h>
#define TEST_FUNCTION do_test ()
static int
diff --git a/elf/tst-tlsmod1.c b/elf/tst-tlsmod1.c
index 4d966c9472..8d9156791b 100644
--- a/elf/tst-tlsmod1.c
+++ b/elf/tst-tlsmod1.c
@@ -1,7 +1,5 @@
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
diff --git a/elf/tst-tlsmod13.c b/elf/tst-tlsmod13.c
index 76da630a05..7712d8b8c8 100644
--- a/elf/tst-tlsmod13.c
+++ b/elf/tst-tlsmod13.c
@@ -1,5 +1,3 @@
-#include <tls.h>
-
__thread int a[2] __attribute__ ((tls_model ("initial-exec")));
int
diff --git a/elf/tst-tlsmod13a.c b/elf/tst-tlsmod13a.c
index d5515d4a15..ca4eaccbff 100644
--- a/elf/tst-tlsmod13a.c
+++ b/elf/tst-tlsmod13a.c
@@ -1,5 +1,3 @@
-#include <tls.h>
-
__thread int b[2] __attribute__ ((tls_model ("initial-exec")));
extern int foo (void);
diff --git a/elf/tst-tlsmod14a.c b/elf/tst-tlsmod14a.c
index 6806d3403c..824c06d1f9 100644
--- a/elf/tst-tlsmod14a.c
+++ b/elf/tst-tlsmod14a.c
@@ -1,8 +1,6 @@
#include <stdint.h>
#include <stdio.h>
-#include <tls.h>
-
#define AL 4096
struct foo
{
diff --git a/elf/tst-tlsmod16a.c b/elf/tst-tlsmod16a.c
index c16e603c8b..4ec6a6c37d 100644
--- a/elf/tst-tlsmod16a.c
+++ b/elf/tst-tlsmod16a.c
@@ -1,3 +1 @@
-#include <tls.h>
-
int __thread tlsvar;
diff --git a/elf/tst-tlsmod16b.c b/elf/tst-tlsmod16b.c
index 7268c56bcb..1ecba26dbe 100644
--- a/elf/tst-tlsmod16b.c
+++ b/elf/tst-tlsmod16b.c
@@ -1,5 +1,3 @@
-#include <tls.h>
-
extern __thread int tlsvar __attribute__((tls_model("initial-exec")));
void *
diff --git a/elf/tst-tlsmod2.c b/elf/tst-tlsmod2.c
index 981923313c..40eb1407f8 100644
--- a/elf/tst-tlsmod2.c
+++ b/elf/tst-tlsmod2.c
@@ -1,7 +1,5 @@
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
diff --git a/elf/tst-tlsmod3.c b/elf/tst-tlsmod3.c
index 5c456ee2da..6d186c47ee 100644
--- a/elf/tst-tlsmod3.c
+++ b/elf/tst-tlsmod3.c
@@ -1,7 +1,5 @@
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
extern int in_dso (int n, int *caller_foop);
diff --git a/elf/tst-tlsmod4.c b/elf/tst-tlsmod4.c
index dd95486618..86889aac7e 100644
--- a/elf/tst-tlsmod4.c
+++ b/elf/tst-tlsmod4.c
@@ -1,7 +1,5 @@
#include <stdio.h>
-#include <tls.h>
-
#include "tls-macros.h"
diff --git a/elf/tst-tlsmod5.c b/elf/tst-tlsmod5.c
index 00d3a9d920..a97c7e5e0c 100644
--- a/elf/tst-tlsmod5.c
+++ b/elf/tst-tlsmod5.c
@@ -1,5 +1,3 @@
-#include <tls.h>
-
#include "tls-macros.h"
COMMON_INT_DEF(foo);
diff --git a/elf/tst-tlsmod6.c b/elf/tst-tlsmod6.c
index 244d9ae485..e968596dd4 100644
--- a/elf/tst-tlsmod6.c
+++ b/elf/tst-tlsmod6.c
@@ -1,5 +1,3 @@
-#include <tls.h>
-
#include "tls-macros.h"
COMMON_INT_DEF(bar);