diff options
author | Ulrich Drepper <drepper@redhat.com> | 2005-01-06 22:40:27 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2005-01-06 22:40:27 +0000 |
commit | 9dcafc559763e339d4a79580c333127033e39c11 (patch) | |
tree | 342441fed429693bc69d95addc588e10a7d021c4 /sysdeps/generic | |
parent | f14038f2e295e7994e2317127cdea1cb26db6be1 (diff) | |
download | glibc-9dcafc559763e339d4a79580c333127033e39c11.tar.gz glibc-9dcafc559763e339d4a79580c333127033e39c11.tar.xz 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.h | 5 | ||||
-rw-r--r-- | sysdeps/generic/bits/linkmap.h | 4 | ||||
-rw-r--r-- | sysdeps/generic/dl-lookupcfg.h | 16 | ||||
-rw-r--r-- | sysdeps/generic/dl-tls.c | 402 | ||||
-rw-r--r-- | sysdeps/generic/dl-trampoline.c | 1 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 114 | ||||
-rw-r--r-- | sysdeps/generic/libc-start.c | 24 | ||||
-rw-r--r-- | sysdeps/generic/libc-tls.c | 11 | ||||
-rw-r--r-- | sysdeps/generic/unsecvars.h | 17 |
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" \ |