diff options
Diffstat (limited to 'newlib/libc/sys/linux/dl/dl-lookup.c')
-rw-r--r-- | newlib/libc/sys/linux/dl/dl-lookup.c | 654 |
1 files changed, 0 insertions, 654 deletions
diff --git a/newlib/libc/sys/linux/dl/dl-lookup.c b/newlib/libc/sys/linux/dl/dl-lookup.c deleted file mode 100644 index 9fc296cf1..000000000 --- a/newlib/libc/sys/linux/dl/dl-lookup.c +++ /dev/null @@ -1,654 +0,0 @@ -/* Look up a symbol in the loaded objects. - Copyright (C) 1995,96,97,98,99,2000,2001 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 - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#include <alloca.h> -#include <libintl.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <ldsodefs.h> -#include "dl-hash.h" -#include <machine/dl-machine.h> -#include <bits/libc-lock.h> - -#include <assert.h> - -#define VERSTAG(tag) (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (tag)) - -/* We need this string more than once. */ -static const char undefined_msg[] = "undefined symbol: "; - - -struct sym_val - { - const ElfW(Sym) *s; - struct link_map *m; - }; - - -#define make_string(string, rest...) \ - ({ \ - const char *all[] = { string, ## rest }; \ - size_t len, cnt; \ - char *result, *cp; \ - \ - len = 1; \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - len += strlen (all[cnt]); \ - \ - cp = result = alloca (len); \ - for (cnt = 0; cnt < sizeof (all) / sizeof (all[0]); ++cnt) \ - { \ - cp = strcpy (cp, all[cnt]); \ - cp += strlen(all[cnt]); \ - } \ - \ - result; \ - }) - -/* Statistics function. */ -unsigned long int _dl_num_relocations; - - -/* 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 -#include "do-lookup.h" - - -/* Add extra dependency on MAP to UNDEF_MAP. */ -static int -internal_function -add_dependency (struct link_map *undef_map, struct link_map *map) -{ - struct link_map **list; - struct link_map *runp; - unsigned int act; - unsigned int i; - int result = 0; - - /* Avoid self-references. */ - if (undef_map == map) - return 0; - - /* Make sure nobody can unload the object while we are at it. */ -#ifdef HAVE_DD_LOCK - __lock_acquire(_dl_load_lock); -#endif - - - /* Determine whether UNDEF_MAP already has a reference to MAP. First - look in the normal dependencies. */ - if (undef_map->l_searchlist.r_list != NULL) - { - list = undef_map->l_initfini; - - for (i = 0; list[i] != NULL; ++i) - if (list[i] == map) - goto out; - } - - /* No normal dependency. See whether we already had to add it - to the special list of dynamic dependencies. */ - list = undef_map->l_reldeps; - act = undef_map->l_reldepsact; - - for (i = 0; i < act; ++i) - if (list[i] == map) - goto out; - - /* The object is not yet in the dependency list. Before we add - it make sure just one more time the object we are about to - reference is still available. There is a brief period in - which the object could have been removed since we found the - definition. */ - runp = _dl_loaded; - while (runp != NULL && runp != map) - runp = runp->l_next; - - if (runp != NULL) - { - /* The object is still available. Add the reference now. */ - if (__builtin_expect (act >= undef_map->l_reldepsmax, 0)) - { - /* Allocate more memory for the dependency list. Since this - can never happen during the startup phase we can use - `realloc'. */ - void *newp; - - undef_map->l_reldepsmax += 5; - newp = realloc (undef_map->l_reldeps, - undef_map->l_reldepsmax - * sizeof (struct link_map *)); - - if (__builtin_expect (newp != NULL, 1)) - undef_map->l_reldeps = (struct link_map **) newp; - else - /* Correct the addition. */ - undef_map->l_reldepsmax -= 5; - } - - /* If we didn't manage to allocate memory for the list this is - no fatal mistake. We simply increment the use counter of the - referenced object and don't record the dependencies. This - means this increment can never be reverted and the object - will never be unloaded. This is semantically the correct - behaviour. */ - if (__builtin_expect (act < undef_map->l_reldepsmax, 1)) - undef_map->l_reldeps[undef_map->l_reldepsact++] = map; - - if (map->l_searchlist.r_list != NULL) - /* And increment the counter in the referenced object. */ - ++map->l_opencount; - else - /* We have to bump the counts for all dependencies since so far - this object was only a normal or transitive dependency. - Now it might be closed with _dl_close() directly. */ - for (list = map->l_initfini; *list != NULL; ++list) - ++(*list)->l_opencount; - - /* Display information if we are debugging. */ - if (__builtin_expect (_dl_debug_mask & DL_DEBUG_FILES, 0)) - _dl_debug_printf ("\ -\nfile=%s; needed by %s (relocation dependency)\n\n", - map->l_name[0] ? map->l_name : _dl_argv[0], - undef_map->l_name[0] - ? undef_map->l_name : _dl_argv[0]); - } - else - /* Whoa, that was bad luck. We have to search again. */ - result = -1; - - out: - /* Release the lock. */ -#ifdef HAVE_DD_LOCK - __lock_release(_dl_load_lock); -#endif - - - 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, - 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); - - -/* 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 explicit) -{ - unsigned long int hash = _dl_elf_hash (undef_name); - struct sym_val current_value = { NULL, NULL }; - struct r_scope_elem **scope; - int protected; - - ++_dl_num_relocations; - - /* 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)) - { - /* 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. */ - && ! explicit - /* 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, 0); - - 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 && reference_name[0] - ? reference_name - : (_dl_argv[0] ?: "<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 (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) - { - const char *reference_name = undef_map ? undef_map->l_name : NULL; - - _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n", - (reference_name && reference_name[0] - ? reference_name : (_dl_argv[0] ?: "<main program>")), - current_value.m->l_name[0] - ? current_value.m->l_name : _dl_argv[0], - protected ? "protected" : "normal", undef_name); - } - - if (__builtin_expect (protected == 0, 1)) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - else - { - /* It is very tricky. We need to figure out what value to - return for the protected symbol */ - 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, NULL, ELF_RTYPE_CLASS_PLT)) - break; - - if (protected_value.s == NULL || protected_value.m == undef_map) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - - return LOOKUP_VALUE (undef_map); - } -} - - -/* 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. */ -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) -{ - const char *reference_name = undef_map ? undef_map->l_name : NULL; - 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; - - ++_dl_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, ¤t_value, *scope, i, - skip_map, 0)) - while (*++scope) - if (_dl_do_lookup (undef_name, hash, *ref, ¤t_value, *scope, 0, - skip_map, 0)) - break; - - if (__builtin_expect (current_value.s == NULL, 0)) - { - *ref = NULL; - return 0; - } - - protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; - - if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) - _dl_debug_printf ("binding file %s to %s: %s symbol `%s'\n", - (reference_name && reference_name[0] - ? reference_name : (_dl_argv[0] ?: "<main program>")), - current_value.m->l_name[0] - ? current_value.m->l_name : _dl_argv[0], - protected ? "protected" : "normal", undef_name); - - if (__builtin_expect (protected == 0, 1)) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - else - { - /* 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, 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)) - break; - - if (protected_value.s == NULL || protected_value.m == undef_map) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - - return LOOKUP_VALUE (undef_map); - } -} - - -/* This function works like _dl_lookup_symbol but it takes an - additional arguement 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 explicit) -{ - unsigned long int hash = _dl_elf_hash (undef_name); - struct sym_val current_value = { NULL, NULL }; - struct r_scope_elem **scope; - int protected; - - ++_dl_num_relocations; - - /* Search the relevant loaded objects for a definition. */ - for (scope = symbol_scope; *scope; ++scope) - { - int res = do_lookup_versioned (undef_name, hash, *ref, ¤t_value, - *scope, 0, version, NULL, type_class); - if (res > 0) - { - /* 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. */ - && ! explicit - /* 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, 0); - - break; - } - - if (__builtin_expect (res, 0) < 0) - { - /* Oh, oh. The file named in the relocation entry does not - contain the needed symbol. */ - const char *reference_name = undef_map ? undef_map->l_name : NULL; - - /* XXX We cannot translate the message. */ - _dl_signal_cerror (0, (reference_name && reference_name[0] - ? reference_name - : (_dl_argv[0] ?: "<main program>")), - N_("relocation error"), - make_string ("symbol ", undef_name, ", version ", - version->name, - " not defined in file ", - version->filename, - " with link time reference", - res == -2 - ? " (no version symbols)" : "")); - *ref = NULL; - return 0; - } - } - - 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 char *reference_name = undef_map ? undef_map->l_name : NULL; - - /* XXX We cannot translate the message. */ - _dl_signal_cerror (0, (reference_name && reference_name[0] - ? reference_name - : (_dl_argv[0] ?: "<main program>")), NULL, - make_string (undefined_msg, undef_name, - ", version ", - version->name ?: NULL)); - } - *ref = NULL; - return 0; - } - - protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; - - if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) - { - const char *reference_name = undef_map ? undef_map->l_name : NULL; - - _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n", - (reference_name && reference_name[0] - ? reference_name : (_dl_argv[0] ?: "<main program>")), - current_value.m->l_name[0] - ? current_value.m->l_name : _dl_argv[0], - protected ? "protected" : "normal", - undef_name, version->name); - } - - if (__builtin_expect (protected == 0, 1)) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - else - { - /* It is very tricky. We need to figure out what value to - return for the protected symbol */ - 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)) - break; - - if (protected_value.s == NULL || protected_value.m == undef_map) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - - return LOOKUP_VALUE (undef_map); - } -} - - -/* 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 ? undef_map->l_name : NULL; - 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; - - ++_dl_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, ¤t_value, - *scope, i, version, skip_map, 0)) - while (*++scope) - if (_dl_do_lookup_versioned (undef_name, hash, *ref, ¤t_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]; - char *tmp; - tmp = memcpy (buf, undefined_msg, sizeof undefined_msg - 1); - tmp += (sizeof undefined_msg - 1); - - memcpy (tmp, undef_name, len + 1); - - /* XXX We cannot translate the messages. */ - _dl_signal_cerror (0, (reference_name && reference_name[0] - ? reference_name - : (_dl_argv[0] ?: "<main program>")), - NULL, buf); - } - *ref = NULL; - return 0; - } - - protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED; - - if (__builtin_expect (_dl_debug_mask & DL_DEBUG_BINDINGS, 0)) - _dl_debug_printf ("binding file %s to %s: %s symbol `%s' [%s]\n", - (reference_name && reference_name[0] - ? reference_name : (_dl_argv[0] ?: "<main program>")), - current_value.m->l_name[0] - ? current_value.m->l_name : _dl_argv[0], - protected ? "protected" : "normal", - undef_name, version->name); - - if (__builtin_expect (protected == 0, 1)) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - else - { - /* 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) - { - *ref = current_value.s; - return LOOKUP_VALUE (current_value.m); - } - - return LOOKUP_VALUE (undef_map); - } -} - - -/* Cache the location of MAP's hash table. */ - -void -internal_function -_dl_setup_hash (struct link_map *map) -{ - Elf_Symndx *hash; - Elf_Symndx nchain; - - if (!map->l_info[DT_HASH]) - return; - hash = (void *)(map->l_addr + map->l_info[DT_HASH]->d_un.d_ptr); - - map->l_nbuckets = *hash++; - nchain = *hash++; - map->l_buckets = hash; - hash += map->l_nbuckets; - map->l_chain = hash; -} - -/* These are here so that we only inline do_lookup{,_versioned} in the common - case, not everywhere. */ -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 link_map *skip, int type_class) -{ - return do_lookup (undef_name, hash, ref, result, scope, i, skip, - 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) -{ - return do_lookup_versioned (undef_name, hash, ref, result, scope, i, - version, skip, type_class); -} |