diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | elf/dl-libc.c | 3 | ||||
-rw-r--r-- | elf/dl-lookup.c | 45 | ||||
-rw-r--r-- | elf/dl-reloc.c | 6 | ||||
-rw-r--r-- | elf/dl-runtime.c | 10 | ||||
-rw-r--r-- | elf/dl-sym.c | 10 | ||||
-rw-r--r-- | elf/do-lookup.h | 33 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 13 | ||||
-rw-r--r-- | sysdeps/mips/dl-machine.h | 3 |
9 files changed, 99 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog index 8d296f7239..539d1a4fe2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2002-04-13 Ulrich Drepper <drepper@redhat.com> + + * elf/do-lookup.h [!VERSIONED]: Add new parameter flags. Use it to + check whether the caller prefers getting the most recent version of + a symbol of the earliest version. + * elf/dl-lookup.c: Adjust all callers of do_lookup. Change + _dl_do_lookup to also take the new parameter and pass it on. + Change 'explicit' parameter of _dl_lookup_symbol and + _dl_lookup_versioned_symbol to flags. Adjust tests. + * sysdeps/generic/ldsodefs.h: Adjust prototypes. + * elf/dl-libc.c: Adjust all callers of _dl_lookup_symbol and + _dl_lookup_versioned_symbol. + * elf/dl-reloc.c: Likewise. + * elf/dl-runtime.c: Likewise. + * elf/dl-sym.c: Likewise. + * sysdeps/mips/dl-machine.h: Likewise. + 2002-04-11 Jakub Jelinek <jakub@redhat.com> * sysdeps/unix/sysv/linux/sparc/sparc32/sysdep.h (LOC): Don't paste diff --git a/elf/dl-libc.c b/elf/dl-libc.c index bb32f697e1..938b5d707d 100644 --- a/elf/dl-libc.c +++ b/elf/dl-libc.c @@ -84,7 +84,8 @@ do_dlsym (void *ptr) struct do_dlsym_args *args = (struct do_dlsym_args *) ptr; args->ref = NULL; args->loadbase = _dl_lookup_symbol (args->name, args->map, &args->ref, - args->map->l_local_scope, 0, 1); + args->map->l_local_scope, 0, + DL_LOOKUP_RETURN_NEWEST); } static void diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c index f9a229d8ea..9d1e1f65af 100644 --- a/elf/dl-lookup.c +++ b/elf/dl-lookup.c @@ -190,7 +190,7 @@ static int internal_function _dl_do_lookup (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, struct sym_val *result, - struct r_scope_elem *scope, size_t i, + struct r_scope_elem *scope, size_t i, int flags, struct link_map *skip, int type_class); static int internal_function @@ -215,7 +215,7 @@ lookup_t internal_function _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], - int type_class, int explicit) + int type_class, int flags) { const unsigned long int hash = _dl_elf_hash (undef_name); struct sym_val current_value = { NULL, NULL }; @@ -226,8 +226,8 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, /* Search the relevant loaded objects for a definition. */ for (scope = symbol_scope; *scope; ++scope) - if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, NULL, - type_class)) + if (do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, flags, + NULL, type_class)) { /* We have to check whether this would bind UNDEF_MAP to an object in the global scope which was dynamically loaded. In this case @@ -236,7 +236,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) /* Don't do this for explicit lookups as opposed to implicit runtime lookups. */ - && ! explicit + && (flags & DL_LOOKUP_ADD_DEPENDENCY) != 0 /* Add UNDEF_MAP to the dependencies. */ && add_dependency (undef_map, current_value.m) < 0) /* Something went wrong. Perhaps the object we tried to reference @@ -272,7 +272,7 @@ _dl_lookup_symbol (const char *undef_name, struct link_map *undef_map, for (scope = symbol_scope; *scope; ++scope) if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, - 0, NULL, ELF_RTYPE_CLASS_PLT)) + 0, flags, NULL, ELF_RTYPE_CLASS_PLT)) break; if (protected_value.s != NULL && protected_value.m != undef_map) @@ -319,10 +319,10 @@ _dl_lookup_symbol_skip (const char *undef_name, assert (i < (*scope)->r_nlist); if (! _dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, i, - skip_map, 0)) + DL_LOOKUP_RETURN_NEWEST, skip_map, 0)) while (*++scope) if (_dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, - skip_map, 0)) + DL_LOOKUP_RETURN_NEWEST, skip_map, 0)) break; if (__builtin_expect (current_value.s == NULL, 0)) @@ -341,10 +341,12 @@ _dl_lookup_symbol_skip (const char *undef_name, if (i >= (*scope)->r_nlist || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, - i, skip_map, ELF_RTYPE_CLASS_PLT)) + i, DL_LOOKUP_RETURN_NEWEST, skip_map, + ELF_RTYPE_CLASS_PLT)) while (*++scope) if (_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope, - 0, skip_map, ELF_RTYPE_CLASS_PLT)) + 0, DL_LOOKUP_RETURN_NEWEST, skip_map, + ELF_RTYPE_CLASS_PLT)) break; if (protected_value.s != NULL && protected_value.m != undef_map) @@ -375,7 +377,7 @@ _dl_lookup_versioned_symbol (const char *undef_name, struct link_map *undef_map, const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], const struct r_found_version *version, - int type_class, int explicit) + int type_class, int flags) { const unsigned long int hash = _dl_elf_hash (undef_name); struct sym_val current_value = { NULL, NULL }; @@ -384,6 +386,9 @@ _dl_lookup_versioned_symbol (const char *undef_name, bump_num_relocations (); + /* No other flag than DL_LOOKUP_ADD_DEPENDENCY is allowed. */ + assert (flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY); + /* Search the relevant loaded objects for a definition. */ for (scope = symbol_scope; *scope; ++scope) { @@ -398,14 +403,15 @@ _dl_lookup_versioned_symbol (const char *undef_name, if (__builtin_expect (current_value.m->l_type == lt_loaded, 0) /* Don't do this for explicit lookups as opposed to implicit runtime lookups. */ - && ! explicit + && flags != 0 /* Add UNDEF_MAP to the dependencies. */ && add_dependency (undef_map, current_value.m) < 0) /* Something went wrong. Perhaps the object we tried to reference was just removed. Try finding another definition. */ return INTUSE(_dl_lookup_versioned_symbol) (undef_name, undef_map, ref, symbol_scope, - version, type_class, 0); + version, type_class, + 0); break; } @@ -590,12 +596,14 @@ _dl_setup_hash (struct link_map *map) map->l_chain = hash; } + static void internal_function _dl_debug_bindings (const char *undef_name, struct link_map *undef_map, const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[], - struct sym_val *value, const struct r_found_version *version, - int type_class, int protected) + struct sym_val *value, + const struct r_found_version *version, int type_class, + int protected) { const char *reference_name = undef_map->l_name; @@ -628,7 +636,8 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map, if (version == 0) _dl_do_lookup (undef_name, hash, *ref, &val, - undef_map->l_local_scope[0], 0, NULL, type_class); + undef_map->l_local_scope[0], 0, 0, NULL, + type_class); else _dl_do_lookup_versioned (undef_name, hash, *ref, &val, undef_map->l_local_scope[0], 0, version, @@ -671,10 +680,10 @@ static int __attribute_noinline__ internal_function _dl_do_lookup (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, struct sym_val *result, - struct r_scope_elem *scope, size_t i, + struct r_scope_elem *scope, size_t i, int flags, struct link_map *skip, int type_class) { - return do_lookup (undef_name, hash, ref, result, scope, i, skip, + return do_lookup (undef_name, hash, ref, result, scope, i, flags, skip, type_class); } diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 88bd3b681e..e5fbb440a5 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -131,7 +131,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], l, (ref), scope, \ (version), _tc, 0) \ : INTUSE(_dl_lookup_symbol) (strtab + (*ref)->st_name, l, \ - (ref), scope, _tc, 0)); \ + (ref), scope, _tc, \ + DL_LOOKUP_ADD_DEPENDENCY)); \ l->l_lookup_cache.ret = (*ref); \ l->l_lookup_cache.value = _lr; })) \ : l) @@ -152,7 +153,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], l, (ref), scope, \ (version), _tc, 0) \ : INTUSE(_dl_lookup_symbol) (strtab + (*ref)->st_name, l, \ - (ref), scope, _tc, 0)); \ + (ref), scope, _tc, \ + DL_LOOKUP_ADD_DEPENDENCY)); \ l->l_lookup_cache.ret = (*ref); \ l->l_lookup_cache.value = _lr; })) \ : l->l_addr) diff --git a/elf/dl-runtime.c b/elf/dl-runtime.c index 3cc832512f..ed1c337367 100644 --- a/elf/dl-runtime.c +++ b/elf/dl-runtime.c @@ -98,7 +98,8 @@ fixup ( } case 0: result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym, - l->l_scope, ELF_RTYPE_CLASS_PLT, 0); + l->l_scope, ELF_RTYPE_CLASS_PLT, + DL_LOOKUP_ADD_DEPENDENCY); } /* Currently result contains the base load address (or link map) @@ -192,9 +193,10 @@ profile_fixup ( } } case 0: - result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, &sym, - l->l_scope, ELF_RTYPE_CLASS_PLT, - 0); + result = INTUSE(_dl_lookup_symbol) (strtab + sym->st_name, l, + &sym, l->l_scope, + ELF_RTYPE_CLASS_PLT, + DL_LOOKUP_ADD_DEPENDENCY); } /* Currently result contains the base load address (or link map) diff --git a/elf/dl-sym.c b/elf/dl-sym.c index 8cb5d2f411..3bf8104a4a 100644 --- a/elf/dl-sym.c +++ b/elf/dl-sym.c @@ -51,7 +51,9 @@ _dl_sym (void *handle, const char *name, void *who) if (handle == RTLD_DEFAULT) /* Search the global scope as seen in the caller object. */ - result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0, 0); + result = _dl_lookup_symbol (name, match, &ref, match->l_scope, 0, + DL_LOOKUP_RETURN_NEWEST + | DL_LOOKUP_ADD_DEPENDENCY); else { if (handle != RTLD_NEXT) @@ -60,7 +62,7 @@ _dl_sym (void *handle, const char *name, void *who) struct link_map *map = handle; result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope, - 0, 1); + 0, DL_LOOKUP_RETURN_NEWEST); } else { @@ -132,7 +134,7 @@ _dl_vsym (void *handle, const char *name, const char *version, void *who) if (handle == RTLD_DEFAULT) /* Search the global scope. */ result = _dl_lookup_versioned_symbol (name, match, &ref, match->l_scope, - &vers, 0, 0); + &vers, 0, DL_LOOKUP_ADD_DEPENDENCY); else if (handle == RTLD_NEXT) { if (__builtin_expect (match == GL(dl_loaded), 0)) @@ -157,7 +159,7 @@ RTLD_NEXT used in code not dynamically loaded")); /* Search the scope of the given object. */ struct link_map *map = handle; result = _dl_lookup_versioned_symbol (name, map, &ref, - map->l_local_scope, &vers, 0, 1); + map->l_local_scope, &vers, 0, 0); } if (ref != NULL) diff --git a/elf/do-lookup.h b/elf/do-lookup.h index bebdb0c09f..be75fb7b00 100644 --- a/elf/do-lookup.h +++ b/elf/do-lookup.h @@ -19,10 +19,10 @@ #if VERSIONED # define FCT do_lookup_versioned -# define ARG const struct r_found_version *const version, +# define ARG const struct r_found_version *const version #else # define FCT do_lookup -# define ARG +# define ARG int flags #endif /* Inner part of the lookup functions. We return a value > 0 if we @@ -30,7 +30,7 @@ something bad happened. */ static inline int FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, - struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG + struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG, struct link_map *skip, int type_class) { struct link_map **list = scope->r_list; @@ -129,19 +129,34 @@ FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, continue; } #else - /* No specific version is selected. When the object file - also does not define a version we have a match. - Otherwise we accept the default version, or in case there - is only one version defined, this one version. */ + /* No specific version is selected. There are two ways we + can got here: + + - a binary which does not include versioning information + is loaded + + - dlsym() instead of dlvsym() is used to get a symbol which + might exist in more than one form + + If the library does not provide symbol version + information there is no problem at at: we simply use the + symbol if it is defined. + + These two lookups need to be handled differently if the + library defines versions. In the case of the old + unversioned application the oldest (default) version + should be used. In case of a dlsym() call the latest and + public interface should be returned. */ if (verstab != NULL) { - ElfW(Half) ndx = verstab[symidx] & 0x7fff; - if (ndx >= 2) /* map->l_versions[ndx].hash != 0) */ + if ((verstab[symidx] & 0x7fff) + >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3)) { /* Don't accept hidden symbols. */ if ((verstab[symidx] & 0x8000) == 0 && num_versions++ == 0) /* No version so far. */ versioned_sym = sym; + continue; } } diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index 011391865f..5f586f2e3c 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -532,15 +532,24 @@ extern lookup_t _dl_lookup_symbol (const char *undef, struct link_map *undef_map, const ElfW(Sym) **sym, struct r_scope_elem *symbol_scope[], - int type_class, int explicit) + int type_class, int flags) internal_function; extern lookup_t _dl_lookup_symbol_internal (const char *undef, struct link_map *undef_map, const ElfW(Sym) **sym, struct r_scope_elem *symbol_scope[], - int type_class, int explicit) + int type_class, int flags) internal_function; +enum + { + /* If necessary add dependency between user and provider object. */ + DL_LOOKUP_ADD_DEPENDENCY = 1, + /* Return most recent version instead of default version for + unversioned lookup. */ + DL_LOOKUP_RETURN_NEWEST = 2 + }; + /* Lookup versioned symbol. */ extern lookup_t _dl_lookup_versioned_symbol (const char *undef, struct link_map *undef_map, diff --git a/sysdeps/mips/dl-machine.h b/sysdeps/mips/dl-machine.h index fcf37f6569..bc5e84fd86 100644 --- a/sysdeps/mips/dl-machine.h +++ b/sysdeps/mips/dl-machine.h @@ -307,7 +307,8 @@ __dl_runtime_resolve (ElfW(Word) sym_index, \ } \ case 0: \ value = _dl_lookup_symbol (strtab + sym->st_name, l, &sym, \ - l->l_scope, ELF_RTYPE_CLASS_PLT, 0); \ + l->l_scope, ELF_RTYPE_CLASS_PLT, \ + DL_LOOKUP_ADD_DEPENDENCY); \ } \ \ /* Currently value contains the base load address of the object \ |