diff options
author | Ulrich Drepper <drepper@redhat.com> | 2006-10-10 00:51:29 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2006-10-10 00:51:29 +0000 |
commit | 1100f84983f22e570a5081cbe79b0ef8fe4952d7 (patch) | |
tree | 3472df1372abf7816fb10f02573ba114c5b5a003 /elf/dl-sym.c | |
parent | 7484f797e4d4f9c174d4391f59d208e83027b285 (diff) | |
download | glibc-1100f84983f22e570a5081cbe79b0ef8fe4952d7.zip glibc-1100f84983f22e570a5081cbe79b0ef8fe4952d7.tar.gz glibc-1100f84983f22e570a5081cbe79b0ef8fe4952d7.tar.bz2 |
Jakub Jelinek <jakub@redhat.com>
Implement reference counting of scope records.
* elf/dl-close.c (_dl_close): Remove all scopes from removed objects
from the list in objects which remain. Always allocate new scope
record.
* elf/dl-open.c (dl_open_worker): When growing array for scopes,
don't resize, allocate a new one.
* elf/dl-runtime.c: Update reference counters before using a scope
array.
* elf/dl-sym.c: Likewise.
* elf/dl-libc.c: Adjust for l_scope name change.
* elf/dl-load.c: Likewise.
* elf/dl-object.c: Likewise.
* elf/rtld.c: Likewise.
* include/link.h: Inlcude <rtld-lowlevel.h>. Define struct
r_scoperec. Replace r_scope with pointer to r_scoperec structure.
Add l_scoperec_lock.
* sysdeps/generic/ldsodefs.h: Include <rtld-lowlevel.h>.
* sysdeps/generic/rtld-lowlevel.h: New file.
* include/atomic.h: Rename atomic_and to atomic_and_val and
atomic_or to atomic_or_val. Define new macros atomic_and and
atomic_or which do not return values.
* sysdeps/x86_64/bits/atomic.h: Define atomic_and and atomic_or.
Various cleanups.
* sysdeps/i386/i486/bits/atomic.h: Likewise.
Diffstat (limited to 'elf/dl-sym.c')
-rw-r--r-- | elf/dl-sym.c | 85 |
1 files changed, 81 insertions, 4 deletions
diff --git a/elf/dl-sym.c b/elf/dl-sym.c index d2b0ec0..1c66310 100644 --- a/elf/dl-sym.c +++ b/elf/dl-sym.c @@ -17,6 +17,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <assert.h> #include <stddef.h> #include <setjmp.h> #include <libintl.h> @@ -58,6 +59,30 @@ _dl_tls_symaddr (struct link_map *map, const ElfW(Sym) *ref) #endif +struct call_dl_lookup_args +{ + /* Arguments to do_dlsym. */ + struct link_map *map; + const char *name; + struct r_scope_elem **scope; + struct r_found_version *vers; + int flags; + + /* Return values of do_dlsym. */ + lookup_t loadbase; + const ElfW(Sym) **refp; +}; + +static void +call_dl_lookup (void *ptr) +{ + struct call_dl_lookup_args *args = (struct call_dl_lookup_args *) ptr; + args->map = GLRO(dl_lookup_symbol_x) (args->name, args->map, args->refp, + args->scope, args->vers, 0, + args->flags, NULL); +} + + static void * internal_function do_sym (void *handle, const char *name, void *who, @@ -84,10 +109,62 @@ do_sym (void *handle, const char *name, void *who, } if (handle == RTLD_DEFAULT) - /* Search the global scope. */ - result = GLRO(dl_lookup_symbol_x) (name, match, &ref, match->l_scope, - vers, 0, flags|DL_LOOKUP_ADD_DEPENDENCY, - NULL); + { + /* Search the global scope. We have the simple case where + we look up in the scope of an object which was part of + the initial binary. And then the more complex part + where the object is dynamically loaded and the scope + array can change. */ + if (match->l_type != lt_loaded) + result = GLRO(dl_lookup_symbol_x) (name, match, &ref, + match->l_scoperec->scope, vers, 0, + flags | DL_LOOKUP_ADD_DEPENDENCY, + NULL); + else + { + __rtld_mrlock_lock (match->l_scoperec_lock); + struct r_scoperec *scoperec = match->l_scoperec; + atomic_increment (&scoperec->nusers); + __rtld_mrlock_unlock (match->l_scoperec_lock); + + struct call_dl_lookup_args args; + args.name = name; + args.map = match; + args.scope = scoperec->scope; + args.vers = vers; + args.flags = flags | DL_LOOKUP_ADD_DEPENDENCY; + args.refp = &ref; + + const char *objname; + const char *errstring = NULL; + bool malloced; + int err = GLRO(dl_catch_error) (&objname, &errstring, &malloced, + call_dl_lookup, &args); + + if (atomic_decrement_val (&scoperec->nusers) == 0 + && __builtin_expect (scoperec->remove_after_use, 0)) + { + if (scoperec->notify) + __rtld_notify (scoperec->nusers); + else + free (scoperec); + } + + if (__builtin_expect (errstring != NULL, 0)) + { + /* The lookup was unsuccessful. Rethrow the error. */ + char *errstring_dup = strdupa (errstring); + char *objname_dup = strdupa (objname); + if (malloced) + free ((char *) errstring); + + GLRO(dl_signal_error) (err, objname_dup, NULL, errstring_dup); + /* NOTREACHED */ + } + + result = args.map; + } + } else if (handle == RTLD_NEXT) { if (__builtin_expect (match == GL(dl_ns)[LM_ID_BASE]._ns_loaded, 0)) |