aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/generic
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2005-01-06 22:40:27 +0000
committerUlrich Drepper <drepper@redhat.com>2005-01-06 22:40:27 +0000
commit9dcafc559763e339d4a79580c333127033e39c11 (patch)
tree342441fed429693bc69d95addc588e10a7d021c4 /sysdeps/generic
parentf14038f2e295e7994e2317127cdea1cb26db6be1 (diff)
downloadglibc-9dcafc559763e339d4a79580c333127033e39c11.tar
glibc-9dcafc559763e339d4a79580c333127033e39c11.tar.gz
glibc-9dcafc559763e339d4a79580c333127033e39c11.tar.bz2
glibc-9dcafc559763e339d4a79580c333127033e39c11.zip
* csu/elf-init.c (__libc_csu_fini): Don't do anything here.
* sysdeps/generic/libc-start.c: Don't register program destructor here. * dlfcn/Makefile: Add rules to build dlfcn.c. (LDFLAGS-dl.so): Removed. * dlfcn/dlclose.c: _dl_close is now in ld.so, use function pointer table. * dlfcn/dlmopen.c: Likewise for _dl_open. * dlfcn/dlopen.c: Likewise. * dlfcn/dlopenold.c: Likewise. * elf/dl-libc.c: Likewise for _dl_open and _dl_close. * elf/Makefile (routines): Remove dl-open and dl-close. (dl-routines): Add dl-open, dl-close, and dl-trampoline. Add rules to build and run tst-audit1. * elf/tst-audit1.c: New file. * elf/tst-auditmod1.c: New file. * elf/Versions [libc]: Remove _dl_open and _dl_close. * elf/dl-close.c: Change for use inside ld.so instead of libc.so. * elf/dl-open.c: Likewise. * elf/dl-debug.c (_dl_debug_initialize): Allow reinitialization, signaled by nonzero parameter. * elf/dl-init.c: Fix use of r_state. * elf/dl-load.c: Likewise. * elf/dl-close.c: Add auditing checkpoints. * elf/dl-open.c: Likewise. * elf/dl-fini.c: Likewise. * elf/dl-load.c: Likewise. * elf/dl-sym.c: Likewise. * sysdeps/generic/libc-start.c: Likewise. * elf/dl-object.c: Allocate memory for auditing information. * elf/dl-reloc.c: Remove RESOLV. We now always need the map. Correctly initialize slotinfo. * elf/dynamic-link.h: Adjust after removal of RESOLV. * sysdeps/hppa/dl-lookupcfg.h: Likewise. * sysdeps/ia64/dl-lookupcfg.h: Likewise. * sysdeps/powerpc/powerpc64/dl-lookupcfg.h: Removed. * elf/dl-runtime.c (_dl_fixup): Little cleanup. (_dl_profile_fixup): New parameters to point to register struct and variable for frame size. Add auditing checkpoints. (_dl_call_pltexit): New function. Don't define trampoline code here. * elf/rtld.c: Recognize LD_AUDIT. Load modules on startup. Remove all the functions from _rtld_global_ro which only _dl_open and _dl_close needed. Add auditing checkpoints. * elf/link.h: Define symbols for auditing interfaces. * include/link.h: Likewise. * include/dlfcn.h: Define __RTLD_AUDIT. Remove prototypes for _dl_open and _dl_close. Adjust access to argc and argv in libdl. * dlfcn/dlfcn.c: New file. * sysdeps/generic/dl-lookupcfg.h: Remove all content now that RESOLVE is gone. * sysdeps/generic/ldsodefs.h: Add definitions for auditing interfaces. * sysdeps/generic/unsecvars.h: Add LD_AUDIT. * sysdeps/i386/dl-machine.h: Remove trampoline code here. Adjust for removal of RESOLVE. * sysdeps/x86_64/dl-machine.h: Likewise. * sysdeps/generic/dl-trampoline.c: New file. * sysdeps/i386/dl-trampoline.c: New file. * sysdeps/x86_64/dl-trampoline.c: New file. * sysdeps/generic/dl-tls.c: Cleanups. Fixup for dtv_t change. Fix updating of DTV. * sysdeps/generic/libc-tls.c: Likewise. * sysdeps/arm/bits/link.h: Renamed to ... * sysdeps/arm/buts/linkmap.h: ...this. * sysdeps/generic/bits/link.h: Renamed to... * sysdeps/generic/bits/linkmap.h: ...this. * sysdeps/hppa/bits/link.h: Renamed to... * sysdeps/hppa/bits/linkmap.h: ...this. * sysdeps/hppa/i386/link.h: Renamed to... * sysdeps/hppa/i386/linkmap.h: ...this. * sysdeps/hppa/ia64/link.h: Renamed to... * sysdeps/hppa/ia64/linkmap.h: ...this. * sysdeps/hppa/s390/link.h: Renamed to... * sysdeps/hppa/s390/linkmap.h: ...this. * sysdeps/hppa/sh/link.h: Renamed to... * sysdeps/hppa/sh/linkmap.h: ...this. * sysdeps/hppa/x86_64/link.h: Renamed to... * sysdeps/hppa/x86_64/linkmap.h: ...this. 2005-01-06 Ulrich Drepper <drepper@redhat.com> * allocatestack.c (init_one_static_tls): Adjust initialization of DTV entry for static tls deallocation fix. * sysdeps/alpha/tls.h (dtv_t): Change pointer type to be struct which also contains information whether the memory pointed to is static TLS or not. * sysdeps/i386/tls.h: Likewise. * sysdeps/ia64/tls.h: Likewise. * sysdeps/powerpc/tls.h: Likewise. * sysdeps/s390/tls.h: Likewise. * sysdeps/sh/tls.h: Likewise. * sysdeps/sparc/tls.h: Likewise. * sysdeps/x86_64/tls.h: Likewise.
Diffstat (limited to 'sysdeps/generic')
-rw-r--r--sysdeps/generic/bits/link.h5
-rw-r--r--sysdeps/generic/bits/linkmap.h4
-rw-r--r--sysdeps/generic/dl-lookupcfg.h16
-rw-r--r--sysdeps/generic/dl-tls.c402
-rw-r--r--sysdeps/generic/dl-trampoline.c1
-rw-r--r--sysdeps/generic/ldsodefs.h114
-rw-r--r--sysdeps/generic/libc-start.c24
-rw-r--r--sysdeps/generic/libc-tls.c11
-rw-r--r--sysdeps/generic/unsecvars.h17
9 files changed, 367 insertions, 227 deletions
diff --git a/sysdeps/generic/bits/link.h b/sysdeps/generic/bits/link.h
index 470b4d3e5f..6b4f811c25 100644
--- a/sysdeps/generic/bits/link.h
+++ b/sysdeps/generic/bits/link.h
@@ -1,4 +1 @@
-struct link_map_machine
- {
- /* empty by default */
- };
+#error "Architecture-specific definition needed."
diff --git a/sysdeps/generic/bits/linkmap.h b/sysdeps/generic/bits/linkmap.h
new file mode 100644
index 0000000000..470b4d3e5f
--- /dev/null
+++ b/sysdeps/generic/bits/linkmap.h
@@ -0,0 +1,4 @@
+struct link_map_machine
+ {
+ /* empty by default */
+ };
diff --git a/sysdeps/generic/dl-lookupcfg.h b/sysdeps/generic/dl-lookupcfg.h
index f48cb0a844..39c430b41e 100644
--- a/sysdeps/generic/dl-lookupcfg.h
+++ b/sysdeps/generic/dl-lookupcfg.h
@@ -1,5 +1,5 @@
/* Configuration of lookup functions.
- Copyright (C) 2002 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2004 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,16 +17,4 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-/* Some platforms need more information from the symbol lookup function
- than just the address. But this is not generally the case.
-
- However, because of how _dl_sym and _dl_tls_symaddr are written, every
- platform needs it when we support TLS. */
-
-#include <tls.h> /* Defines USE_TLS (or doesn't). */
-
-#ifdef USE_TLS
-# define DL_LOOKUP_RETURNS_MAP
-#else
-# undef DL_LOOKUP_RETURNS_MAP
-#endif
+/* Nothing special. */
diff --git a/sysdeps/generic/dl-tls.c b/sysdeps/generic/dl-tls.c
index 2282dda9cc..10b7f2c65a 100644
--- a/sysdeps/generic/dl-tls.c
+++ b/sysdeps/generic/dl-tls.c
@@ -1,5 +1,5 @@
/* Thread-local storage handling in the ELF dynamic linker. Generic version.
- Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004, 2005 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
@@ -18,6 +18,8 @@
02111-1307 USA. */
#include <assert.h>
+#include <errno.h>
+#include <libintl.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
@@ -116,10 +118,9 @@ void
internal_function
_dl_determine_tlsoffset (void)
{
- struct dtv_slotinfo *slotinfo;
size_t max_align = TLS_TCB_ALIGN;
- size_t offset, freetop = 0, freebottom = 0;
- size_t cnt;
+ size_t freetop = 0;
+ size_t freebottom = 0;
/* The first element of the dtv slot info list is allocated. */
assert (GL(dl_tls_dtv_slotinfo_list) != NULL);
@@ -127,7 +128,7 @@ _dl_determine_tlsoffset (void)
dl_tls_dtv_slotinfo_list list. */
assert (GL(dl_tls_dtv_slotinfo_list)->next == NULL);
- slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
+ struct dtv_slotinfo *slotinfo = GL(dl_tls_dtv_slotinfo_list)->slotinfo;
/* Determining the offset of the various parts of the static TLS
block has several dependencies. In addition we have to work
@@ -159,9 +160,9 @@ _dl_determine_tlsoffset (void)
# if TLS_TCB_AT_TP
/* We simply start with zero. */
- offset = 0;
+ size_t offset = 0;
- for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
+ for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
{
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
@@ -206,9 +207,9 @@ _dl_determine_tlsoffset (void)
+ TLS_TCB_SIZE);
# elif TLS_DTV_AT_TP
/* The TLS blocks start right after the TCB. */
- offset = TLS_TCB_SIZE;
+ size_t offset = TLS_TCB_SIZE;
- for (cnt = 1; slotinfo[cnt].map != NULL; ++cnt)
+ for (size_t cnt = 0; slotinfo[cnt].map != NULL; ++cnt)
{
assert (cnt < GL(dl_tls_dtv_slotinfo_list)->len);
@@ -225,8 +226,8 @@ _dl_determine_tlsoffset (void)
if (off + slotinfo[cnt].map->l_tls_blocksize - firstbyte <= freetop)
{
slotinfo[cnt].map->l_tls_offset = off - firstbyte;
- freebottom = off + slotinfo[cnt].map->l_tls_blocksize
- - firstbyte;
+ freebottom = (off + slotinfo[cnt].map->l_tls_blocksize
+ - firstbyte);
continue;
}
}
@@ -357,14 +358,14 @@ _dl_allocate_tls_storage (void)
/* Clear the TCB data structure. We can't ask the caller (i.e.
libpthread) to do it, because we will initialize the DTV et al. */
- memset (result, 0, TLS_TCB_SIZE);
+ memset (result, '\0', TLS_TCB_SIZE);
# elif TLS_DTV_AT_TP
result = (char *) result + size - GL(dl_tls_static_size);
/* Clear the TCB data structure and TLS_PRE_TCB_SIZE bytes before it.
We can't ask the caller (i.e. libpthread) to do it, because we will
initialize the DTV et al. */
- memset ((char *) result - TLS_PRE_TCB_SIZE, 0,
+ memset ((char *) result - TLS_PRE_TCB_SIZE, '\0',
TLS_PRE_TCB_SIZE + TLS_TCB_SIZE);
# endif
@@ -388,10 +389,11 @@ _dl_allocate_tls_init (void *result)
dtv_t *dtv = GET_DTV (result);
struct dtv_slotinfo_list *listp;
size_t total = 0;
+ size_t maxgen = 0;
- /* We have to look prepare the dtv for all currently loaded
- modules using TLS. For those which are dynamically loaded we
- add the values indicating deferred allocation. */
+ /* We have to prepare the dtv for all currently loaded modules using
+ TLS. For those which are dynamically loaded we add the values
+ indicating deferred allocation. */
listp = GL(dl_tls_dtv_slotinfo_list);
while (1)
{
@@ -411,11 +413,16 @@ _dl_allocate_tls_init (void *result)
/* Unused entry. */
continue;
+ /* Keep track of the maximum generation number. This might
+ not be the generation counter. */
+ maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
+
if (map->l_tls_offset == NO_TLS_OFFSET)
{
/* For dynamically loaded modules we simply store
the value indicating deferred allocation. */
- dtv[map->l_tls_modid].pointer = TLS_DTV_UNALLOCATED;
+ dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
+ dtv[map->l_tls_modid].pointer.is_static = false;
continue;
}
@@ -431,7 +438,8 @@ _dl_allocate_tls_init (void *result)
# endif
/* Copy the initialization image and clear the BSS part. */
- dtv[map->l_tls_modid].pointer = dest;
+ dtv[map->l_tls_modid].pointer.val = dest;
+ dtv[map->l_tls_modid].pointer.is_static = true;
memset (__mempcpy (dest, map->l_tls_initimage,
map->l_tls_initimage_size), '\0',
map->l_tls_blocksize - map->l_tls_initimage_size);
@@ -445,6 +453,9 @@ _dl_allocate_tls_init (void *result)
assert (listp != NULL);
}
+ /* The DTV version is up-to-date now. */
+ dtv[0].counter = maxgen;
+
return result;
}
rtld_hidden_def (_dl_allocate_tls_init)
@@ -466,6 +477,12 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
{
dtv_t *dtv = GET_DTV (tcb);
+ /* We need to free the memory allocated for non-static TLS. */
+ 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);
+
/* The array starts with dtv[-1]. */
#ifdef SHARED
if (dtv != GL(dl_initial_dtv))
@@ -524,166 +541,172 @@ allocate_and_init (struct link_map *map)
}
-/* The generic dynamic and local dynamic model cannot be used in
- statically linked applications. */
-void *
-__tls_get_addr (GET_ADDR_ARGS)
+struct link_map *
+_dl_update_slotinfo (unsigned long int req_modid)
{
- dtv_t *dtv = THREAD_DTV ();
struct link_map *the_map = NULL;
- void *p;
+ dtv_t *dtv = THREAD_DTV ();
- if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
+ /* The global dl_tls_dtv_slotinfo array contains for each module
+ index the generation counter current when the entry was created.
+ This array never shrinks so that all module indices which were
+ valid at some time can be used to access it. Before the first
+ use of a new module index in this function the array was extended
+ appropriately. Access also does not have to be guarded against
+ modifications of the array. It is assumed that pointer-size
+ values can be read atomically even in SMP environments. It is
+ possible that other threads at the same time dynamically load
+ code and therefore add to the slotinfo list. This is a problem
+ since we must not pick up any information about incomplete work.
+ The solution to this is to ignore all dtv slots which were
+ created after the one we are currently interested. We know that
+ dynamic loading for this module is completed and this is the last
+ load operation we know finished. */
+ unsigned long int idx = req_modid;
+ struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
+
+ while (idx >= listp->len)
{
- struct dtv_slotinfo_list *listp;
- size_t idx;
-
- /* The global dl_tls_dtv_slotinfo array contains for each module
- index the generation counter current when the entry was
- created. This array never shrinks so that all module indices
- which were valid at some time can be used to access it.
- Before the first use of a new module index in this function
- the array was extended appropriately. Access also does not
- have to be guarded against modifications of the array. It is
- assumed that pointer-size values can be read atomically even
- in SMP environments. It is possible that other threads at
- the same time dynamically load code and therefore add to the
- slotinfo list. This is a problem since we must not pick up
- any information about incomplete work. The solution to this
- is to ignore all dtv slots which were created after the one
- we are currently interested. We know that dynamic loading
- for this module is completed and this is the last load
- operation we know finished. */
- idx = GET_ADDR_MODULE;
- listp = GL(dl_tls_dtv_slotinfo_list);
- while (idx >= listp->len)
- {
- idx -= listp->len;
- listp = listp->next;
- }
+ idx -= listp->len;
+ listp = listp->next;
+ }
- if (dtv[0].counter < listp->slotinfo[idx].gen)
+ if (dtv[0].counter < listp->slotinfo[idx].gen)
+ {
+ /* The generation counter for the slot is higher than what the
+ current dtv implements. We have to update the whole dtv but
+ only those entries with a generation counter <= the one for
+ the entry we need. */
+ size_t new_gen = listp->slotinfo[idx].gen;
+ size_t total = 0;
+
+ /* We have to look through the entire dtv slotinfo list. */
+ listp = GL(dl_tls_dtv_slotinfo_list);
+ do
{
- /* The generation counter for the slot is higher than what
- the current dtv implements. We have to update the whole
- dtv but only those entries with a generation counter <=
- the one for the entry we need. */
- size_t new_gen = listp->slotinfo[idx].gen;
- size_t total = 0;
-
- /* We have to look through the entire dtv slotinfo list. */
- listp = GL(dl_tls_dtv_slotinfo_list);
- do
+ for (size_t cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
{
- size_t cnt;
-
- for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
+ size_t gen = listp->slotinfo[cnt].gen;
+
+ if (gen > new_gen)
+ /* This is a slot for a generation younger than the
+ one we are handling now. It might be incompletely
+ set up so ignore it. */
+ continue;
+
+ /* If the entry is older than the current dtv layout we
+ know we don't have to handle it. */
+ if (gen <= dtv[0].counter)
+ continue;
+
+ /* If there is no map this means the entry is empty. */
+ struct link_map *map = listp->slotinfo[cnt].map;
+ if (map == NULL)
{
- size_t gen = listp->slotinfo[cnt].gen;
- struct link_map *map;
- size_t modid;
-
- if (gen > new_gen)
- /* This is a slot for a generation younger than
- the one we are handling now. It might be
- incompletely set up so ignore it. */
- continue;
-
- /* If the entry is older than the current dtv layout
- we know we don't have to handle it. */
- if (gen <= dtv[0].counter)
- continue;
-
- /* If there is no map this means the entry is empty. */
- 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 this modid was used at some point the memory
- might still be allocated. */
- if (dtv[total + cnt].pointer != TLS_DTV_UNALLOCATED)
- {
- free (dtv[total + cnt].pointer);
- dtv[total + cnt].pointer = TLS_DTV_UNALLOCATED;
- }
-
- continue;
+ free (dtv[total + cnt].pointer.val);
+ dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
}
- /* Check whether the current dtv array is large enough. */
- modid = map->l_tls_modid;
- assert (total + cnt == modid);
- if (dtv[-1].counter < modid)
+ continue;
+ }
+
+ /* 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. */
+ dtv_t *newp;
+ size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
+ size_t oldsize = dtv[-1].counter;
+
+ assert (map->l_tls_modid <= newsize);
+
+ if (dtv == GL(dl_initial_dtv))
{
- /* Reallocate the dtv. */
- dtv_t *newp;
- size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
- size_t oldsize = dtv[-1].counter;
-
- assert (map->l_tls_modid <= newsize);
-
- if (dtv == GL(dl_initial_dtv))
- {
- /* 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
- free it, we have to abandon the old storage. */
-
- newp = malloc ((2 + newsize) * sizeof (dtv_t));
- if (newp == NULL)
- oom ();
- memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t));
- }
- else
- {
- newp = realloc (&dtv[-1],
- (2 + newsize) * sizeof (dtv_t));
- if (newp == NULL)
- oom ();
- }
-
- newp[0].counter = newsize;
-
- /* Clear the newly allocated part. */
- memset (newp + 2 + oldsize, '\0',
- (newsize - oldsize) * sizeof (dtv_t));
-
- /* Point dtv to the generation counter. */
- dtv = &newp[1];
-
- /* Install this new dtv in the thread data
- structures. */
- INSTALL_NEW_DTV (dtv);
+ /* 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
+ free it, we have to abandon the old storage. */
+
+ newp = malloc ((2 + newsize) * sizeof (dtv_t));
+ if (newp == NULL)
+ oom ();
+ memcpy (newp, &dtv[-1], oldsize * sizeof (dtv_t));
}
+ else
+ {
+ newp = realloc (&dtv[-1],
+ (2 + newsize) * sizeof (dtv_t));
+ if (newp == NULL)
+ oom ();
+ }
+
+ newp[0].counter = newsize;
+
+ /* Clear the newly allocated part. */
+ memset (newp + 2 + oldsize, '\0',
+ (newsize - oldsize) * sizeof (dtv_t));
+
+ /* Point dtv to the generation counter. */
+ dtv = &newp[1];
- /* If there is currently memory allocate for this
- dtv entry free it. */
- /* XXX Ideally we will at some point create a memory
- pool. */
- if (dtv[modid].pointer != TLS_DTV_UNALLOCATED)
- /* Note that free is called for NULL is well. We
- 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);
-
- /* This module is loaded dynamically- We defer
- memory allocation. */
- dtv[modid].pointer = TLS_DTV_UNALLOCATED;
-
- if (modid == GET_ADDR_MODULE)
- the_map = map;
+ /* Install this new dtv in the thread data
+ structures. */
+ INSTALL_NEW_DTV (dtv);
}
- total += listp->len;
+ /* If there is currently memory allocate for this
+ dtv entry free it. */
+ /* XXX Ideally we will at some point create a memory
+ pool. */
+ if (! dtv[modid].pointer.is_static
+ && dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
+ /* Note that free is called for NULL is well. We
+ 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);
+
+ /* This module is loaded dynamically- We defer memory
+ allocation. */
+ dtv[modid].pointer.is_static = false;
+ dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
+
+ if (modid == req_modid)
+ the_map = map;
}
- while ((listp = listp->next) != NULL);
- /* This will be the new maximum generation counter. */
- dtv[0].counter = new_gen;
+ total += listp->len;
}
+ while ((listp = listp->next) != NULL);
+
+ /* This will be the new maximum generation counter. */
+ dtv[0].counter = new_gen;
}
- p = dtv[GET_ADDR_MODULE].pointer;
+ return the_map;
+}
+
+
+/* The generic dynamic and local dynamic model cannot be used in
+ statically linked applications. */
+void *
+__tls_get_addr (GET_ADDR_ARGS)
+{
+ dtv_t *dtv = THREAD_DTV ();
+ struct link_map *the_map = NULL;
+ void *p;
+
+ if (__builtin_expect (dtv[0].counter != GL(dl_tls_generation), 0))
+ the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+
+ p = dtv[GET_ADDR_MODULE].pointer.val;
if (__builtin_expect (p == TLS_DTV_UNALLOCATED, 0))
{
@@ -703,11 +726,74 @@ __tls_get_addr (GET_ADDR_ARGS)
the_map = listp->slotinfo[idx].map;
}
- p = dtv[GET_ADDR_MODULE].pointer = allocate_and_init (the_map);
+ p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
+ dtv[GET_ADDR_MODULE].pointer.is_static = false;
}
return (char *) p + GET_ADDR_OFFSET;
}
# endif
+
+
+void
+_dl_add_to_slotinfo (struct link_map *l)
+{
+ /* Now that we know the object is loaded successfully add
+ modules containing TLS data to the dtv info table. We
+ might have to increase its size. */
+ struct dtv_slotinfo_list *listp;
+ struct dtv_slotinfo_list *prevp;
+ size_t idx = l->l_tls_modid;
+
+ /* Find the place in the dtv slotinfo list. */
+ listp = GL(dl_tls_dtv_slotinfo_list);
+ prevp = NULL; /* Needed to shut up gcc. */
+ do
+ {
+ /* Does it fit in the array of this list element? */
+ if (idx < listp->len)
+ break;
+ idx -= listp->len;
+ prevp = listp;
+ listp = listp->next;
+ }
+ while (listp != NULL);
+
+ if (listp == NULL)
+ {
+ /* When we come here it means we have to add a new element
+ to the slotinfo list. And the new module must be in
+ the first slot. */
+ assert (idx == 0);
+
+ listp = prevp->next = (struct dtv_slotinfo_list *)
+ malloc (sizeof (struct dtv_slotinfo_list)
+ + TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+ if (listp == NULL)
+ {
+ /* We ran out of memory. We will simply fail this
+ call but don't undo anything we did so far. The
+ application will crash or be terminated anyway very
+ soon. */
+
+ /* We have to do this since some entries in the dtv
+ slotinfo array might already point to this
+ generation. */
+ ++GL(dl_tls_generation);
+
+ _dl_signal_error (ENOMEM, "dlopen", NULL, N_("\
+cannot create TLS data structures"));
+ }
+
+ listp->len = TLS_SLOTINFO_SURPLUS;
+ listp->next = NULL;
+ memset (listp->slotinfo, '\0',
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
+ }
+
+ /* Add the information into the slotinfo data structure. */
+ listp->slotinfo[idx].map = l;
+ listp->slotinfo[idx].gen = GL(dl_tls_generation) + 1;
+}
#endif /* use TLS */
diff --git a/sysdeps/generic/dl-trampoline.c b/sysdeps/generic/dl-trampoline.c
new file mode 100644
index 0000000000..3ca89f3879
--- /dev/null
+++ b/sysdeps/generic/dl-trampoline.c
@@ -0,0 +1 @@
+#error "Architecture specific PLT trampolines must be defined."
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index ec68e1a565..4a181f4009 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -52,23 +52,15 @@ __BEGIN_DECLS
most architectures the entry is already relocated - but for some not
and we need to relocate at access time. */
#ifdef DL_RO_DYN_SECTION
-# define D_PTR(map,i) (map->i->d_un.d_ptr + map->l_addr)
+# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr)
#else
-# define D_PTR(map,i) map->i->d_un.d_ptr
+# define D_PTR(map, i) (map)->i->d_un.d_ptr
#endif
-/* On some platforms more information than just the address of the symbol
- is needed from the lookup functions. In this case we return the whole
- link map. */
-#ifdef DL_LOOKUP_RETURNS_MAP
+/* Result of the lookup functions and how to retrieve the base address. */
typedef struct link_map *lookup_t;
# define LOOKUP_VALUE(map) map
-# define LOOKUP_VALUE_ADDRESS(map) (map ? map->l_addr : 0)
-#else
-typedef ElfW(Addr) lookup_t;
-# define LOOKUP_VALUE(map) map->l_addr
-# define LOOKUP_VALUE_ADDRESS(address) address
-#endif
+# define LOOKUP_VALUE_ADDRESS(map) ((map) ? (map)->l_addr : 0)
/* on some architectures a pointer to a function is not just a pointer
to the actual code of the function but rather an architecture
@@ -182,6 +174,55 @@ enum allowmask
};
+/* Type for list of auditing interfaces. */
+struct La_i86_regs;
+struct La_i86_retval;
+struct La_x86_64_regs;
+struct La_x86_64_retval;
+
+
+struct audit_ifaces
+{
+ void (*activity) (uintptr_t *, unsigned int);
+ char *(*objsearch) (const char *, uintptr_t *, unsigned int);
+ unsigned int (*objopen) (struct link_map *, Lmid_t, uintptr_t *);
+ void (*preinit) (uintptr_t *);
+ union
+ {
+ uintptr_t (*symbind32) (Elf32_Sym *, unsigned int, uintptr_t *,
+ uintptr_t *, unsigned int *, const char *);
+ uintptr_t (*symbind64) (Elf64_Sym *, unsigned int, uintptr_t *,
+ uintptr_t *, unsigned int *, const char *);
+ };
+ union
+ {
+ uintptr_t (*i86_gnu_pltenter) (Elf32_Sym *, unsigned int, uintptr_t *,
+ uintptr_t *, const struct La_i86_regs *,
+ unsigned int *, const char *name,
+ long int *framesizep);
+ uintptr_t (*x86_64_gnu_pltenter) (Elf64_Sym *, unsigned int, uintptr_t *,
+ uintptr_t *,
+ const struct La_x86_64_regs *,
+ unsigned int *, const char *name,
+ long int *framesizep);
+ };
+ union
+ {
+ unsigned int (*i86_gnu_pltexit) (Elf32_Sym *, unsigned int, uintptr_t *,
+ uintptr_t *, const struct La_i86_regs *,
+ struct La_i86_retval *, const char *);
+ unsigned int (*x86_64_gnu_pltexit) (Elf64_Sym *, unsigned int, uintptr_t *,
+ uintptr_t *,
+ const struct La_x86_64_regs *,
+ struct La_x86_64_retval *,
+ const char *);
+ };
+ unsigned int (*objclose) (uintptr_t *);
+
+ struct audit_ifaces *next;
+};
+
+
/* Test whether given NAME matches any of the names of the given object. */
extern int _dl_name_match_p (const char *__name, struct link_map *__map)
internal_function;
@@ -224,7 +265,7 @@ struct rtld_global
#endif
EXTERN struct link_namespaces
{
- /* And a pointer to the map for the main map. */
+ /* A pointer to the map for the main map. */
struct link_map *_ns_loaded;
/* Number of object in the _dl_loaded list. */
unsigned int _ns_nloaded;
@@ -277,8 +318,12 @@ struct rtld_global
EXTERN void **(*_dl_error_catch_tsd) (void) __attribute__ ((const));
#endif
- /* Structure describing the dynamic linker itself. */
+ /* Structure describing the dynamic linker itself. We need to
+ reserve memory for the data the audit libraries need. */
EXTERN struct link_map _dl_rtld_map;
+#ifdef SHARED
+ struct auditstate audit_data[DL_NNS];
+#endif
#if defined SHARED && defined _LIBC_REENTRANT \
&& defined __rtld_lock_default_lock_recursive
@@ -311,6 +356,7 @@ struct rtld_global
struct dtv_slotinfo
{
size_t gen;
+ bool is_static;
struct link_map *map;
} slotinfo[0];
} *_dl_tls_dtv_slotinfo_list;
@@ -483,32 +529,12 @@ struct rtld_global_ro
call the function instead of going through the PLT. The result
is that we can avoid exporting the functions and we do not jump
PLT relocations in libc.so. */
- const char *(*_dl_get_origin) (void);
- size_t (*_dl_dst_count) (const char *, int);
- char *(*_dl_dst_substitute) (struct link_map *, const char *, char *, int);
- struct link_map *(internal_function *_dl_map_object) (struct link_map *,
- const char *, int,
- int, int, int, Lmid_t);
- void (internal_function *_dl_map_object_deps) (struct link_map *,
- struct link_map **,
- unsigned int, int, int);
- void (*_dl_relocate_object) (struct link_map *, struct r_scope_elem *[],
- int, int);
- int (internal_function *_dl_check_map_versions) (struct link_map *, int,
- int);
- void (internal_function *_dl_init) (struct link_map *, int, char **,
- char **);
- void (*_dl_debug_state) (void);
-#ifndef MAP_COPY
- void (*_dl_unload_cache) (void);
-#endif
void (*_dl_debug_printf) (const char *, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
int (internal_function *_dl_catch_error) (const char **, const char **,
void (*) (void *), void *);
void (internal_function *_dl_signal_error) (int, const char *, const char *,
const char *);
- void (internal_function *_dl_start_profile) (void);
void (*_dl_mcount) (ElfW(Addr) frompc, ElfW(Addr) selfpc);
lookup_t (internal_function *_dl_lookup_symbol_x) (const char *,
struct link_map *,
@@ -518,7 +544,13 @@ struct rtld_global_ro
int, int,
struct link_map *);
int (*_dl_check_caller) (const void *, enum allowmask);
+ void *(*_dl_open) (const char *file, int mode, const void *caller_dlopen,
+ Lmid_t nsid, int argc, char *argv[], char *env[]);
+ void (*_dl_close) (void *map);
+ /* List of auditing interfaces. */
+ struct audit_ifaces *_dl_audit;
+ unsigned int _dl_naudit;
};
# define __rtld_global_attribute__
# ifdef IS_IN_rtld
@@ -911,6 +943,20 @@ extern char *_dl_dst_substitute (struct link_map *l, const char *name,
extern int _dl_check_caller (const void *caller, enum allowmask mask)
attribute_hidden;
+/* Open the shared object NAME, relocate it, and run its initializer if it
+ hasn't already been run. MODE is as for `dlopen' (see <dlfcn.h>). If
+ the object is already opened, returns its existing map. */
+extern void *_dl_open (const char *name, int mode, const void *caller,
+ Lmid_t nsid, int argc, char *argv[], char *env[])
+ attribute_hidden;
+
+/* Add module to slot information data. */
+extern void _dl_add_to_slotinfo (struct link_map *l) attribute_hidden;
+
+/* Update slot information data for at least the generation of the
+ module with the given index. */
+extern struct link_map *_dl_update_slotinfo (unsigned long int req_modid);
+
__END_DECLS
#endif /* ldsodefs.h */
diff --git a/sysdeps/generic/libc-start.c b/sysdeps/generic/libc-start.c
index ad5ebe0911..5bb8a9b352 100644
--- a/sysdeps/generic/libc-start.c
+++ b/sysdeps/generic/libc-start.c
@@ -80,6 +80,10 @@ STATIC int LIBC_START_MAIN (int (*main) (int, char **, char **
void *__unbounded stack_end)
__attribute__ ((noreturn));
+
+/* Note: the fini parameter is ignored here. It used to be registered
+ with __cxa_atexit. This had the disadvantage that finalizers were
+ called in more than one place. */
STATIC int
LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
int argc, char *__unbounded *__unbounded ubp_av,
@@ -158,10 +162,6 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
__libc_init_first (argc, argv, __environ);
#endif
- /* Register the destructor of the program, if any. */
- if (fini)
- __cxa_atexit ((void (*) (void *)) fini, NULL, NULL);
-
#ifndef SHARED
/* Some security at this point. Prevent starting a SUID binary where
the standard file descriptors are not opened. We have to do this
@@ -184,6 +184,22 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
);
#ifdef SHARED
+ /* Auditing checkpoint: we have a new object. */
+ if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
+ {
+ struct audit_ifaces *afct = GLRO(dl_audit);
+ struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+ for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
+ {
+ if (afct->preinit != NULL)
+ afct->preinit (&head->l_audit[cnt].cookie);
+
+ afct = afct->next;
+ }
+ }
+#endif
+
+#ifdef SHARED
if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, 0))
GLRO(dl_debug_printf) ("\ntransferring control: %s\n\n", argv[0]);
#endif
diff --git a/sysdeps/generic/libc-tls.c b/sysdeps/generic/libc-tls.c
index b5ecc36436..b88ede06a2 100644
--- a/sysdeps/generic/libc-tls.c
+++ b/sysdeps/generic/libc-tls.c
@@ -1,5 +1,5 @@
/* Initialization code for TLS in statically linked application.
- Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+ Copyright (C) 2002, 2003, 2004 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
@@ -178,17 +178,18 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
/* Initialize the TLS block. */
# if TLS_TCB_AT_TP
- static_dtv[2].pointer = ((char *) tlsblock + tcb_offset
- - roundup (memsz, align ?: 1));
+ static_dtv[2].pointer.val = ((char *) tlsblock + tcb_offset
+ - roundup (memsz, align ?: 1));
static_map.l_tls_offset = roundup (memsz, align ?: 1);
# elif TLS_DTV_AT_TP
- static_dtv[2].pointer = (char *) tlsblock + tcb_offset;
+ static_dtv[2].pointer.val = (char *) tlsblock + tcb_offset;
static_map.l_tls_offset = tcb_offset;
# else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif
+ static_dtv[2].pointer.is_static = true;
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
- memcpy (static_dtv[2].pointer, initimage, filesz);
+ memcpy (static_dtv[2].pointer.val, initimage, filesz);
/* Install the pointer to the dtv. */
diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h
index eb77b260d8..a7378b742f 100644
--- a/sysdeps/generic/unsecvars.h
+++ b/sysdeps/generic/unsecvars.h
@@ -2,18 +2,19 @@
all stuffed in a single string which means they have to be terminated
with a '\0' explicitly. */
#define UNSECURE_ENVVARS \
- "LD_PRELOAD\0" \
- "LD_LIBRARY_PATH\0" \
- "LD_ORIGIN_PATH\0" \
+ "GCONV_PATH\0" \
+ "GETCONF_DIR\0" \
+ "HOSTALIASES\0" \
+ "LD_AUDIT\0" \
"LD_DEBUG\0" \
"LD_DEBUG_OUTPUT\0" \
- "LD_PROFILE\0" \
- "LD_USE_LOAD_BIAS\0" \
"LD_DYNAMIC_WEAK\0" \
+ "LD_LIBRARY_PATH\0" \
+ "LD_ORIGIN_PATH\0" \
+ "LD_PRELOAD\0" \
+ "LD_PROFILE\0" \
"LD_SHOW_AUXV\0" \
- "GCONV_PATH\0" \
- "GETCONF_DIR\0" \
- "HOSTALIASES\0" \
+ "LD_USE_LOAD_BIAS\0" \
"LOCALDOMAIN\0" \
"LOCPATH\0" \
"MALLOC_TRACE\0" \