+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
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
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
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 };
/* 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
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
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)
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))
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)
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 };
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)
{
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;
}
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;
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,
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);
}
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, (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)
}
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)
}
}
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)
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)
struct link_map *map = handle;
result = _dl_lookup_symbol (name, match, &ref, map->l_local_scope,
- 0, 1);
+ 0, DL_LOOKUP_RETURN_NEWEST);
}
else
{
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))
/* 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)
#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
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;
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;
}
}
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,
} \
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 \