diff options
Diffstat (limited to 'elf/dl-open.c')
-rw-r--r-- | elf/dl-open.c | 139 |
1 files changed, 37 insertions, 102 deletions
diff --git a/elf/dl-open.c b/elf/dl-open.c index 32e7caa..c997521 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -1,5 +1,5 @@ /* Load a shared object at runtime, relocate it, and run its initializer. - Copyright (C) 1996-2004, 2005, 2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1996-2004, 2005, 2006 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 @@ -32,7 +32,6 @@ #include <bp-sym.h> #include <caller.h> #include <sysdep-cancel.h> -#include <tls.h> #include <dl-dst.h> @@ -98,17 +97,17 @@ add_to_global (struct link_map *new) in an realloc() call. Therefore we allocate a completely new array the first time we have to add something to the locale scope. */ - struct link_namespaces *ns = &GL(dl_ns)[new->l_ns]; - if (ns->_ns_global_scope_alloc == 0) + if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0) { /* This is the first dynamic object given global scope. */ - ns->_ns_global_scope_alloc - = ns->_ns_main_searchlist->r_nlist + to_add + 8; + GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8; new_global = (struct link_map **) - malloc (ns->_ns_global_scope_alloc * sizeof (struct link_map *)); + malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + * sizeof (struct link_map *)); if (new_global == NULL) { - ns->_ns_global_scope_alloc = 0; + GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0; nomem: _dl_signal_error (ENOMEM, new->l_libname->name, NULL, N_("cannot extend global scope")); @@ -116,39 +115,29 @@ add_to_global (struct link_map *new) } /* Copy over the old entries. */ - ns->_ns_main_searchlist->r_list - = memcpy (new_global, ns->_ns_main_searchlist->r_list, - (ns->_ns_main_searchlist->r_nlist + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list + = memcpy (new_global, + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list, + (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist * sizeof (struct link_map *))); } - else if (ns->_ns_main_searchlist->r_nlist + to_add - > ns->_ns_global_scope_alloc) + else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + > GL(dl_ns)[new->l_ns]._ns_global_scope_alloc) { /* We have to extend the existing array of link maps in the main map. */ - struct link_map **old_global - = GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list; - size_t new_nalloc = ((ns->_ns_global_scope_alloc + to_add) * 2); - new_global = (struct link_map **) - malloc (new_nalloc * sizeof (struct link_map *)); + realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list, + ((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8) + * sizeof (struct link_map *))); if (new_global == NULL) goto nomem; - memcpy (new_global, old_global, - ns->_ns_global_scope_alloc * sizeof (struct link_map *)); - - ns->_ns_global_scope_alloc = new_nalloc; - ns->_ns_main_searchlist->r_list = new_global; - - if (!RTLD_SINGLE_THREAD_P) - THREAD_GSCOPE_WAIT (); - - free (old_global); + GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8; + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global; } /* Now add the new entries. */ - unsigned int new_nlist = ns->_ns_main_searchlist->r_nlist; for (cnt = 0; cnt < new->l_searchlist.r_nlist; ++cnt) { struct link_map *map = new->l_searchlist.r_list[cnt]; @@ -156,49 +145,15 @@ add_to_global (struct link_map *new) if (map->l_global == 0) { map->l_global = 1; - ns->_ns_main_searchlist->r_list[new_nlist++] = map; + GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist] + = map; + ++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist; } } - atomic_write_barrier (); - ns->_ns_main_searchlist->r_nlist = new_nlist; return 0; } -int -_dl_scope_free (struct r_scope_elem **old) -{ - struct dl_scope_free_list *fsl; -#define DL_SCOPE_FREE_LIST_SIZE (sizeof (fsl->list) / sizeof (fsl->list[0])) - - if (RTLD_SINGLE_THREAD_P) - free (old); - else if ((fsl = GL(dl_scope_free_list)) == NULL) - { - GL(dl_scope_free_list) = fsl = malloc (sizeof (*fsl)); - if (fsl == NULL) - { - THREAD_GSCOPE_WAIT (); - free (old); - return 1; - } - else - { - fsl->list[0] = old; - fsl->count = 1; - } - } - else if (fsl->count < DL_SCOPE_FREE_LIST_SIZE) - fsl->list[fsl->count++] = old; - else - { - THREAD_GSCOPE_WAIT (); - while (fsl->count > 0) - free (fsl->list[--fsl->count]); - return 1; - } - return 0; -} static void dl_open_worker (void *a) @@ -206,12 +161,10 @@ dl_open_worker (void *a) struct dl_open_args *args = a; const char *file = args->file; int mode = args->mode; - struct link_map *new; + struct link_map *new, *l; int lazy; unsigned int i; -#ifdef USE_TLS bool any_tls = false; -#endif struct link_map *call_map = NULL; /* Check whether _dl_open() has been called from a valid DSO. */ @@ -233,14 +186,13 @@ dl_open_worker (void *a) By default we assume this is the main application. */ call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded; - struct link_map *l; for (Lmid_t ns = 0; ns < DL_NNS; ++ns) for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next) if (caller_dlopen >= (const void *) l->l_map_start - && caller_dlopen < (const void *) l->l_map_end - && (l->l_contiguous - || _dl_addr_inside_object (l, (ElfW(Addr)) caller_dlopen))) + && caller_dlopen < (const void *) l->l_map_end) { + /* There must be exactly one DSO for the range of the virtual + memory. Otherwise something is really broken. */ assert (ns == l->l_ns); call_map = l; goto found_caller; @@ -373,7 +325,7 @@ dl_open_worker (void *a) /* Relocate the objects loaded. We do this in reverse order so that copy relocs of earlier objects overwrite the data written by later objects. */ - struct link_map *l = new; + l = new; while (l->l_next) l = l->l_next; while (1) @@ -465,10 +417,17 @@ dl_open_worker (void *a) memcpy (newp, imap->l_scope, cnt * sizeof (imap->l_scope[0])); struct r_scope_elem **old = imap->l_scope; - imap->l_scope = newp; + if (RTLD_SINGLE_THREAD_P) + imap->l_scope = newp; + else + { + __rtld_mrlock_change (imap->l_scope_lock); + imap->l_scope = newp; + __rtld_mrlock_done (imap->l_scope_lock); + } if (old != imap->l_scope_mem) - _dl_scope_free (old); + free (old); imap->l_scope_max = new_size; } @@ -480,7 +439,6 @@ dl_open_worker (void *a) atomic_write_barrier (); imap->l_scope[cnt] = &new->l_searchlist; } -#if USE_TLS /* Only add TLS memory if this object is loaded now and therefore is not yet initialized. */ else if (! imap->l_init_called @@ -495,11 +453,11 @@ dl_open_worker (void *a) if (imap->l_need_tls_init) { imap->l_need_tls_init = 0; -# ifdef SHARED +#ifdef SHARED /* Update the slot information data for at least the generation of the DSO we are allocating data for. */ _dl_update_slotinfo (imap->l_tls_modid); -# endif +#endif GL(dl_init_static_tls) (imap); assert (imap->l_need_tls_init == 0); @@ -508,15 +466,12 @@ dl_open_worker (void *a) /* We have to bump the generation counter. */ any_tls = true; } -#endif } -#if USE_TLS /* Bump the generation number if necessary. */ if (any_tls && __builtin_expect (++GL(dl_tls_generation) == 0, 0)) _dl_fatal_printf (N_("\ TLS generation counter wrapped! Please report this.")); -#endif /* Run the initializer functions of new objects. */ _dl_init (new, args->argc, args->argv, args->env); @@ -613,7 +568,6 @@ no more namespaces available for dlmopen()")); state if relocation failed, for example. */ if (args.map) { -#ifdef USE_TLS /* Maybe some of the modules which were loaded use TLS. Since it will be removed in the following _dl_close call we have to mark the dtv array as having gaps to fill the @@ -623,7 +577,6 @@ no more namespaces available for dlmopen()")); up. */ if ((mode & __RTLD_AUDIT) == 0) GL(dl_tls_dtv_gaps) = true; -#endif _dl_close_worker (args.map); } @@ -697,21 +650,3 @@ show_scope (struct link_map *new) } } #endif - -#ifdef IS_IN_rtld -/* Return non-zero if ADDR lies within one of L's segments. */ -int -internal_function -_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr) -{ - int n = l->l_phnum; - const ElfW(Addr) reladdr = addr - l->l_addr; - - while (--n >= 0) - if (l->l_phdr[n].p_type == PT_LOAD - && reladdr - l->l_phdr[n].p_vaddr >= 0 - && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz) - return 1; - return 0; -} -#endif |