summaryrefslogtreecommitdiff
path: root/elf/dl-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'elf/dl-lookup.c')
-rw-r--r--elf/dl-lookup.c380
1 files changed, 44 insertions, 336 deletions
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 925f01c102..b05404f815 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -68,14 +68,7 @@ struct sym_val
#endif
-
-/* We have two different situations when looking up a simple: with or
- without versioning. gcc is not able to optimize a single function
- definition serving for both purposes so we define two functions. */
-#define VERSIONED 0
-#include "do-lookup.h"
-
-#define VERSIONED 1
+/* The actual lookup code. */
#include "do-lookup.h"
@@ -208,20 +201,6 @@ add_dependency (struct link_map *undef_map, struct link_map *map)
return result;
}
-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, int flags,
- struct link_map *skip, int type_class);
-static int
-internal_function
-_dl_do_lookup_versioned (const char *undef_name, unsigned long int hash,
- const ElfW(Sym) *ref, struct sym_val *result,
- struct r_scope_elem *scope, size_t i,
- const struct r_found_version *const version,
- struct link_map *skip, int type_class);
-
static void
internal_function
_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
@@ -230,208 +209,51 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
const struct r_found_version *version, int type_class,
int protected);
-/* Search loaded objects' symbol tables for a definition of the symbol
- UNDEF_NAME. */
-
-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 flags)
-{
- const unsigned long int hash = _dl_elf_hash (undef_name);
- struct sym_val current_value = { NULL, NULL };
- struct r_scope_elem **scope;
- int protected;
-
- bump_num_relocations ();
-
- /* 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, flags,
- NULL, type_class))
- break;
-
- if (__builtin_expect (current_value.s == NULL, 0))
- {
- const char *reference_name = undef_map ? undef_map->l_name : NULL;
-
- if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
- /* We could find no value for a strong reference. */
- /* XXX We cannot translate the messages. */
- _dl_signal_cerror (0, (reference_name[0]
- ? reference_name
- : (rtld_progname ?: "<main program>")),
- N_("relocation error"),
- make_string (undefined_msg, undef_name));
- *ref = NULL;
- return 0;
- }
-
- protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
- if (__builtin_expect (protected != 0, 0))
- {
- /* It is very tricky. We need to figure out what value to
- return for the protected symbol. */
- if (type_class == ELF_RTYPE_CLASS_PLT)
- {
- if (current_value.s != NULL && current_value.m != undef_map)
- {
- current_value.s = *ref;
- current_value.m = undef_map;
- }
- }
- else
- {
- struct sym_val protected_value = { NULL, NULL };
-
- for (scope = symbol_scope; *scope; ++scope)
- if (_dl_do_lookup (undef_name, hash, *ref,
- &protected_value, *scope, 0, flags,
- NULL, ELF_RTYPE_CLASS_PLT))
- break;
-
- if (protected_value.s != NULL
- && protected_value.m != undef_map)
- {
- current_value.s = *ref;
- current_value.m = undef_map;
- }
- }
- }
-
- /* We have to check whether this would bind UNDEF_MAP to an object
- in the global scope which was dynamically loaded. In this case
- we have to prevent the latter from being unloaded unless the
- UNDEF_MAP object is also unloaded. */
- if (__builtin_expect (current_value.m->l_type == lt_loaded, 0)
- /* Don't do this for explicit lookups as opposed to implicit
- runtime lookups. */
- && (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
- was just removed. Try finding another definition. */
- return _dl_lookup_symbol (undef_name, undef_map, ref, symbol_scope,
- type_class, flags);
-
- if (__builtin_expect (GLRO(dl_debug_mask)
- & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
- _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
- &current_value, NULL, type_class, protected);
-
- *ref = current_value.s;
- return LOOKUP_VALUE (current_value.m);
-}
-
-/* This function is nearly the same as `_dl_lookup_symbol' but it
- skips in the first list all objects until SKIP_MAP is found. I.e.,
- it only considers objects which were loaded after the described
- object. If there are more search lists the object described by
- SKIP_MAP is only skipped. */
+/* Search loaded objects' symbol tables for a definition of the symbol
+ UNDEF_NAME, perhaps with a requested version for the symbol. */
lookup_t
internal_function
-_dl_lookup_symbol_skip (const char *undef_name,
- struct link_map *undef_map, const ElfW(Sym) **ref,
- struct r_scope_elem *symbol_scope[],
- struct link_map *skip_map)
+_dl_lookup_symbol_x (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 flags, struct link_map *skip_map)
{
const unsigned long int hash = _dl_elf_hash (undef_name);
struct sym_val current_value = { NULL, NULL };
- struct r_scope_elem **scope;
- size_t i;
- int protected;
+ struct r_scope_elem **scope = symbol_scope;
bump_num_relocations ();
- /* Search the relevant loaded objects for a definition. */
- scope = symbol_scope;
- for (i = 0; (*scope)->r_list[i] != skip_map; ++i)
- assert (i < (*scope)->r_nlist);
-
- if (! _dl_do_lookup (undef_name, hash, *ref, &current_value, *scope, i,
- DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
- while (*++scope)
- if (_dl_do_lookup (undef_name, hash, *ref, &current_value, *scope, 0,
- DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
- break;
+ /* No other flag than DL_LOOKUP_ADD_DEPENDENCY is allowed if we look
+ up a versioned symbol. */
+ assert (version == NULL || flags == 0 || flags == DL_LOOKUP_ADD_DEPENDENCY);
- if (__builtin_expect (current_value.s == NULL, 0))
+ size_t i = 0;
+ if (__builtin_expect (skip_map != NULL, 0))
{
- *ref = NULL;
- return 0;
- }
-
- protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
+ /* Search the relevant loaded objects for a definition. */
+ while ((*scope)->r_list[i] != skip_map)
+ ++i;
- if (__builtin_expect (protected != 0, 0))
- {
- /* It is very tricky. We need to figure out what value to
- return for the protected symbol. */
- struct sym_val protected_value = { NULL, NULL };
-
- if (i >= (*scope)->r_nlist
- || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope,
- 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, DL_LOOKUP_RETURN_NEWEST, skip_map,
- ELF_RTYPE_CLASS_PLT))
- break;
-
- if (protected_value.s != NULL && protected_value.m != undef_map)
- {
- current_value.s = *ref;
- current_value.m = undef_map;
- }
+ assert (i < (*scope)->r_nlist);
}
- if (__builtin_expect (GLRO(dl_debug_mask)
- & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
- _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
- &current_value, NULL, 0, protected);
-
- *ref = current_value.s;
- return LOOKUP_VALUE (current_value.m);
-}
-
-
-/* This function works like _dl_lookup_symbol but it takes an
- additional argument with the version number of the requested symbol.
-
- XXX We'll see whether we need this separate function. */
-lookup_t
-internal_function
-_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 flags)
-{
- const unsigned long int hash = _dl_elf_hash (undef_name);
- struct sym_val current_value = { NULL, NULL };
- struct r_scope_elem **scope;
- int protected;
-
- 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)
+ for (size_t start = i; *scope != NULL; start = 0, ++scope)
{
- int res = do_lookup_versioned (undef_name, hash, *ref, &current_value,
- *scope, 0, version, NULL, type_class);
+ int res = do_lookup_x (undef_name, hash, *ref, &current_value, *scope,
+ start, version, flags, skip_map, type_class);
if (res > 0)
break;
- if (__builtin_expect (res, 0) < 0)
+ if (__builtin_expect (res, 0) < 0 && skip_map == NULL)
{
/* Oh, oh. The file named in the relocation entry does not
- contain the needed symbol. */
+ contain the needed symbol. This code is never reached
+ for unversioned lookups. */
+ assert (version != NULL);
const char *reference_name = undef_map ? undef_map->l_name : NULL;
/* XXX We cannot translate the message. */
@@ -453,25 +275,28 @@ _dl_lookup_versioned_symbol (const char *undef_name,
if (__builtin_expect (current_value.s == NULL, 0))
{
- if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ if ((*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
+ && skip_map == NULL)
{
/* We could find no value for a strong reference. */
const char *reference_name = undef_map ? undef_map->l_name : NULL;
+ const char *versionstr = version ? ", version " : "";
+ const char *versionname = (version && version->name
+ ? version->name : "");
/* XXX We cannot translate the message. */
_dl_signal_cerror (0, (reference_name[0]
? reference_name
: (rtld_progname ?: "<main program>")), NULL,
make_string (undefined_msg, undef_name,
- ", version ",
- version->name ?: NULL));
+ versionstr, versionname));
}
*ref = NULL;
return 0;
}
- protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
-
+ int protected = (*ref
+ && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED);
if (__builtin_expect (protected != 0, 0))
{
/* It is very tricky. We need to figure out what value to
@@ -488,11 +313,10 @@ _dl_lookup_versioned_symbol (const char *undef_name,
{
struct sym_val protected_value = { NULL, NULL };
- for (scope = symbol_scope; *scope; ++scope)
- if (_dl_do_lookup_versioned (undef_name, hash, *ref,
- &protected_value,
- *scope, 0, version, NULL,
- ELF_RTYPE_CLASS_PLT))
+ for (scope = symbol_scope; *scope; i = 0, ++scope)
+ if (do_lookup_x (undef_name, hash, *ref, &protected_value,
+ *scope, i, version, flags, skip_map,
+ ELF_RTYPE_CLASS_PLT) != 0)
break;
if (protected_value.s != NULL
@@ -511,14 +335,14 @@ _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. */
- && flags != 0
+ && (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
was just removed. Try finding another definition. */
- return _dl_lookup_versioned_symbol (undef_name, undef_map, ref,
- symbol_scope, version, type_class,
- flags);
+ return _dl_lookup_symbol_x (undef_name, undef_map, ref,
+ symbol_scope, version, type_class,
+ flags, skip_map);
if (__builtin_expect (GLRO(dl_debug_mask)
& (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
@@ -530,92 +354,6 @@ _dl_lookup_versioned_symbol (const char *undef_name,
}
-/* Similar to _dl_lookup_symbol_skip but takes an additional argument
- with the version we are looking for. */
-lookup_t
-internal_function
-_dl_lookup_versioned_symbol_skip (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,
- struct link_map *skip_map)
-{
- const char *reference_name = undef_map->l_name;
- const unsigned long int hash = _dl_elf_hash (undef_name);
- struct sym_val current_value = { NULL, NULL };
- struct r_scope_elem **scope;
- size_t i;
- int protected;
-
- bump_num_relocations ();
-
- /* Search the relevant loaded objects for a definition. */
- scope = symbol_scope;
- for (i = 0; (*scope)->r_list[i] != skip_map; ++i)
- assert (i < (*scope)->r_nlist);
-
- if (! _dl_do_lookup_versioned (undef_name, hash, *ref, &current_value,
- *scope, i, version, skip_map, 0))
- while (*++scope)
- if (_dl_do_lookup_versioned (undef_name, hash, *ref, &current_value,
- *scope, 0, version, skip_map, 0))
- break;
-
- if (__builtin_expect (current_value.s == NULL, 0))
- {
- if (*ref == NULL || ELFW(ST_BIND) ((*ref)->st_info) != STB_WEAK)
- {
- /* We could find no value for a strong reference. */
- const size_t len = strlen (undef_name);
- char buf[sizeof undefined_msg + len];
- __mempcpy (__mempcpy (buf, undefined_msg, sizeof undefined_msg - 1),
- undef_name, len + 1);
- /* XXX We cannot translate the messages. */
- _dl_signal_cerror (0, (reference_name[0]
- ? reference_name
- : (rtld_progname ?: "<main program>")),
- NULL, buf);
- }
- *ref = NULL;
- return 0;
- }
-
- protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
-
- if (__builtin_expect (protected != 0, 0))
- {
- /* It is very tricky. We need to figure out what value to
- return for the protected symbol. */
- struct sym_val protected_value = { NULL, NULL };
-
- if (i >= (*scope)->r_nlist
- || !_dl_do_lookup_versioned (undef_name, hash, *ref,
- &protected_value, *scope, i, version,
- skip_map, ELF_RTYPE_CLASS_PLT))
- while (*++scope)
- if (_dl_do_lookup_versioned (undef_name, hash, *ref,
- &protected_value, *scope, 0, version,
- skip_map, ELF_RTYPE_CLASS_PLT))
- break;
-
- if (protected_value.s != NULL && protected_value.m != undef_map)
- {
- current_value.s = *ref;
- current_value.m = undef_map;
- }
- }
-
- if (__builtin_expect (GLRO(dl_debug_mask)
- & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
- _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
- &current_value, version, 0, protected);
-
- *ref = current_value.s;
- return LOOKUP_VALUE (current_value.m);
-}
-
-
/* Cache the location of MAP's hash table. */
void
@@ -672,14 +410,9 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
{
const unsigned long int hash = _dl_elf_hash (undef_name);
- if (version == 0)
- _dl_do_lookup (undef_name, hash, *ref, &val,
- 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,
- NULL, type_class);
+ do_lookup_x (undef_name, hash, *ref, &val,
+ undef_map->l_local_scope[0], 0, version, 0, NULL,
+ type_class);
if (val.s != value->s || val.m != value->m)
conflict = 1;
@@ -720,28 +453,3 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
}
#endif
}
-
-/* These are here so that we only inline do_lookup{,_versioned} in the common
- case, not everywhere. */
-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, int flags,
- struct link_map *skip, int type_class)
-{
- return do_lookup (undef_name, hash, ref, result, scope, i, flags, skip,
- type_class);
-}
-
-static int __attribute_noinline__
-internal_function
-_dl_do_lookup_versioned (const char *undef_name, unsigned long int hash,
- const ElfW(Sym) *ref, struct sym_val *result,
- struct r_scope_elem *scope, size_t i,
- const struct r_found_version *const version,
- struct link_map *skip, int type_class)
-{
- return do_lookup_versioned (undef_name, hash, ref, result, scope, i,
- version, skip, type_class);
-}