diff options
-rw-r--r-- | ChangeLog | 8 | ||||
-rw-r--r-- | dlfcn/dlsym.c | 13 | ||||
-rw-r--r-- | dlfcn/dlvsym.c | 13 | ||||
-rw-r--r-- | elf/dl-addr.c | 122 | ||||
-rw-r--r-- | elf/dl-fini.c | 16 |
5 files changed, 106 insertions, 66 deletions
diff --git a/ChangeLog b/ChangeLog index 1fe409850d..2dcb477744 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2004-02-20 Ulrich Drepper <drepper@redhat.com> + + * dlfcn/dlsym.c: Get ld.so loading lock before the call into ld.so. + * dlfcn/dlvsym.c: Likewise. + * elf/dl-addr.c: Get loading lock while using _dl_loaded data. + * elf/dl-fini.c: Likewise. + Patch by Shunichi Sagawa <s-sagawa@jp.fujitsu.com>. + 2004-02-20 Jakub Jelinek <jakub@redhat.com> * sysdeps/sparc/sparc32/fpu/libm-test-ulps: Add ulps for the diff --git a/dlfcn/dlsym.c b/dlfcn/dlsym.c index ec071d9de8..76dda5973f 100644 --- a/dlfcn/dlsym.c +++ b/dlfcn/dlsym.c @@ -1,5 +1,5 @@ /* Look up a symbol in a shared object loaded by `dlopen'. - Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. + Copyright (C) 1995-2000, 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 @@ -20,6 +20,8 @@ #include <dlfcn.h> #include <stddef.h> +#include <ldsodefs.h> + struct dlsym_args { /* The arguments to dlsym_doit. */ @@ -48,5 +50,12 @@ dlsym (void *handle, const char *name) args.handle = handle; args.name = name; - return (_dlerror_run (dlsym_doit, &args) ? NULL : args.sym); + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + + void *result = (_dlerror_run (dlsym_doit, &args) ? NULL : args.sym); + + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + return result; } diff --git a/dlfcn/dlvsym.c b/dlfcn/dlvsym.c index 62415feaac..24868456e9 100644 --- a/dlfcn/dlvsym.c +++ b/dlfcn/dlvsym.c @@ -1,5 +1,5 @@ /* Look up a versioned symbol in a shared object loaded by `dlopen'. - Copyright (C) 1995, 96, 97, 98, 99, 2000 Free Software Foundation, Inc. + Copyright (C) 1995-2000, 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 @@ -20,6 +20,8 @@ #include <dlfcn.h> #include <stddef.h> +#include <ldsodefs.h> + struct dlvsym_args { /* The arguments to dlvsym_doit. */ @@ -51,6 +53,13 @@ __dlvsym (void *handle, const char *name, const char *version_str) args.who = RETURN_ADDRESS (0); args.version = version_str; - return (_dlerror_run (dlvsym_doit, &args) ? NULL : args.sym); + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + + void *result = (_dlerror_run (dlvsym_doit, &args) ? NULL : args.sym); + + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + return result; } weak_alias (__dlvsym, dlvsym) diff --git a/elf/dl-addr.c b/elf/dl-addr.c index 0b8328bf4d..ae97398bad 100644 --- a/elf/dl-addr.c +++ b/elf/dl-addr.c @@ -1,5 +1,5 @@ /* Locate the shared object symbol nearest a given address. - Copyright (C) 1996-2000,2001,2002,2003 Free Software Foundation, Inc. + Copyright (C) 1996-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 @@ -33,6 +33,9 @@ _dl_addr (const void *address, Dl_info *info, const char *strtab; ElfW(Word) strtabsize; + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + /* Find the highest-addressed object that ADDRESS is not below. */ match = NULL; for (l = GL(dl_loaded); l; l = l->l_next) @@ -56,62 +59,71 @@ _dl_addr (const void *address, Dl_info *info, break; } - if (match == NULL) - return 0; - - /* Now we know what object the address lies in. */ - info->dli_fname = match->l_name; - info->dli_fbase = (void *) match->l_map_start; - - /* If this is the main program the information is incomplete. */ - if (__builtin_expect (l->l_name[0], 'a') == '\0' - && l->l_type == lt_executable) - info->dli_fname = _dl_argv[0]; - - symtab = (const void *) D_PTR (match, l_info[DT_SYMTAB]); - strtab = (const void *) D_PTR (match, l_info[DT_STRTAB]); - - strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; - - if (match->l_info[DT_HASH] != NULL) - symtabend = symtab + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]; - else - /* There is no direct way to determine the number of symbols in the - dynamic symbol table and no hash table is present. The ELF - binary is ill-formed but what shall we do? Use the beginning of - the string table which generally follows the symbol table. */ - symtabend = (const ElfW(Sym) *) strtab; - - /* We assume that the string table follows the symbol table, because - there is no way in ELF to know the size of the dynamic symbol table!! */ - for (matchsym = NULL; (void *) symtab < (void *) symtabend; ++symtab) - if (addr >= match->l_addr + symtab->st_value - && ((symtab->st_size == 0 && addr == match->l_addr + symtab->st_value) - || addr < match->l_addr + symtab->st_value + symtab->st_size) - && symtab->st_name < strtabsize - && (matchsym == NULL || matchsym->st_value < symtab->st_value) - && (ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL - || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)) - matchsym = (ElfW(Sym) *) symtab; - - if (mapp) - *mapp = match; - if (symbolp) - *symbolp = matchsym; - - if (matchsym) - { - /* We found a symbol close by. Fill in its name and exact address. */ - info->dli_sname = strtab + matchsym->st_name; - info->dli_saddr = (void *) (match->l_addr + matchsym->st_value); - } - else + int result = 0; + if (match != NULL) { - /* No symbol matches. We return only the containing object. */ - info->dli_sname = NULL; - info->dli_saddr = NULL; + /* Now we know what object the address lies in. */ + info->dli_fname = match->l_name; + info->dli_fbase = (void *) match->l_map_start; + + /* If this is the main program the information is incomplete. */ + if (__builtin_expect (l->l_name[0], 'a') == '\0' + && l->l_type == lt_executable) + info->dli_fname = _dl_argv[0]; + + symtab = (const void *) D_PTR (match, l_info[DT_SYMTAB]); + strtab = (const void *) D_PTR (match, l_info[DT_STRTAB]); + + strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; + + if (match->l_info[DT_HASH] != NULL) + symtabend = (symtab + + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]); + else + /* There is no direct way to determine the number of symbols in the + dynamic symbol table and no hash table is present. The ELF + binary is ill-formed but what shall we do? Use the beginning of + the string table which generally follows the symbol table. */ + symtabend = (const ElfW(Sym) *) strtab; + + /* We assume that the string table follows the symbol table, + because there is no way in ELF to know the size of the + dynamic symbol table!! */ + for (matchsym = NULL; (void *) symtab < (void *) symtabend; ++symtab) + if (addr >= match->l_addr + symtab->st_value + && ((symtab->st_size == 0 + && addr == match->l_addr + symtab->st_value) + || addr < match->l_addr + symtab->st_value + symtab->st_size) + && symtab->st_name < strtabsize + && (matchsym == NULL || matchsym->st_value < symtab->st_value) + && (ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL + || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK)) + matchsym = (ElfW(Sym) *) symtab; + + if (mapp) + *mapp = match; + if (symbolp) + *symbolp = matchsym; + + if (matchsym) + { + /* We found a symbol close by. Fill in its name and exact + address. */ + info->dli_sname = strtab + matchsym->st_name; + info->dli_saddr = (void *) (match->l_addr + matchsym->st_value); + } + else + { + /* No symbol matches. We return only the containing object. */ + info->dli_sname = NULL; + info->dli_saddr = NULL; + } + + result = 1; } - return 1; + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + + return result; } libc_hidden_def (_dl_addr) diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 46202734a7..7115efb85a 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -1,5 +1,5 @@ /* Call the termination functions of loaded shared objects. - Copyright (C) 1995,96,98,99,2000,2001,2002 Free Software Foundation, Inc. + Copyright (C) 1995,96,1998-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 @@ -46,6 +46,9 @@ _dl_fini (void) struct link_map *l; struct link_map **maps; + /* Protect against concurrent loads and unloads. */ + __rtld_lock_lock_recursive (GL(dl_load_lock)); + /* XXX Could it be (in static binaries) that there is no object loaded? */ assert (GL(dl_nloaded) > 0); @@ -71,7 +74,7 @@ _dl_fini (void) unsigned int j; unsigned int k; - /* Find the place in the `maps' array. */ + /* Find the place in the 'maps' array. */ for (j = 1; maps[j] != l; ++j) ; @@ -79,9 +82,7 @@ _dl_fini (void) move the found object (if necessary) in front. */ for (k = j + 1; k < GL(dl_nloaded); ++k) { - struct link_map **runp; - - runp = maps[k]->l_initfini; + struct link_map **runp = maps[k]->l_initfini; if (runp != NULL) { while (*runp != NULL) @@ -120,13 +121,12 @@ _dl_fini (void) break; } - } } } } - /* `maps' now contains the objects in the right order. Now call the + /* 'maps' now contains the objects in the right order. Now call the destructors. We have to process this array from the front. */ for (i = 0; i < GL(dl_nloaded); ++i) { @@ -172,6 +172,8 @@ _dl_fini (void) --l->l_opencount; } + __rtld_lock_unlock_recursive (GL(dl_load_lock)); + if (__builtin_expect (GL(dl_debug_mask) & DL_DEBUG_STATISTICS, 0)) { INTUSE(_dl_debug_printf) ("\nruntime linker statistics:\n"); |