aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog17
-rw-r--r--elf/dl-libc.c3
-rw-r--r--elf/dl-lookup.c45
-rw-r--r--elf/dl-reloc.c6
-rw-r--r--elf/dl-runtime.c10
-rw-r--r--elf/dl-sym.c10
-rw-r--r--elf/do-lookup.h33
-rw-r--r--sysdeps/generic/ldsodefs.h13
-rw-r--r--sysdeps/mips/dl-machine.h3
9 files changed, 99 insertions, 41 deletions
diff --git a/ChangeLog b/ChangeLog
index 8d296f7..539d1a4 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 bb32f69..938b5d7 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 f9a229d..9d1e1f6 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, &current_value, *scope, 0, NULL,
- type_class))
+ if (do_lookup (undef_name, hash, *ref, &current_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, &current_value, *scope, i,
- skip_map, 0))
+ DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
while (*++scope)
if (_dl_do_lookup (undef_name, hash, *ref, &current_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 88bd3b6..e5fbb44 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 3cc8325..ed1c337 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 8cb5d2f..3bf8104 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 bebdb0c..be75fb7 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 0113918..5f586f2 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 fcf37f6..bc5e84f 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 \