aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--elf/dl-lookup.c10
-rw-r--r--elf/do-lookup.h202
3 files changed, 212 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 52e78ae..7b92046 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
1999-02-20 Ulrich Drepper <drepper@cygnus.com>
+ * elf/dl-lookup.c (_dl_lookup_symbol_skip): Before first do_lookup
+ call test whether there is any scope left.
+ (_dl_lookup_versioned_symbol_skip): Likewise.
+
* elf/Makefile (distribute): Add do-lookup.h.
* elf/do-lookup.h: New file. Split out from dl-lookup.c.
* elf/dl-lookup.c: Move do_lookup function in separate file and
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index dba9243..9a691b7 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -142,8 +142,9 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->r_nduplist);
- if (! do_lookup (undef_name, hash, *ref, &current_value,
- *scope, i, reference_name, skip_map, 0))
+ if (i >= (*scope)->r_nlist
+ || ! do_lookup (undef_name, hash, *ref, &current_value,
+ *scope, i, reference_name, skip_map, 0))
while (*++scope)
if (do_lookup (undef_name, hash, *ref, &current_value,
*scope, 0, reference_name, skip_map, 0))
@@ -263,8 +264,9 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
assert (i < (*scope)->r_nduplist);
- if (! do_lookup_versioned (undef_name, hash, *ref, &current_value,
- *scope, i, reference_name, version, skip_map, 0))
+ if (i >= (*scope)->r_nlist
+ || ! do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
+ i, reference_name, version, skip_map, 0))
while (*++scope)
if (do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
0, reference_name, version, skip_map, 0))
diff --git a/elf/do-lookup.h b/elf/do-lookup.h
new file mode 100644
index 0000000..1a833be
--- /dev/null
+++ b/elf/do-lookup.h
@@ -0,0 +1,202 @@
+/* Look up a symbol in the loaded objects.
+ Copyright (C) 1995, 1996, 1997, 1998, 1999 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 Library General Public License as
+ published by the Free Software Foundation; either version 2 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#if VERSIONED
+# define FCT do_lookup_versioned
+# define ARG const struct r_found_version *const version,
+#else
+# define FCT do_lookup
+# define ARG
+#endif
+
+/* Inner part of the lookup functions. We return a value > 0 if we
+ found the symbol, the value 0 if nothing is found and < 0 if
+ 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, const char *reference_name,
+ ARG struct link_map *skip, int reloc_type)
+{
+ struct link_map **list = scope->r_list;
+ size_t n = scope->r_nlist;
+ struct link_map *map;
+
+ do
+ {
+ const ElfW(Sym) *symtab;
+ const char *strtab;
+ const ElfW(Half) *verstab;
+ ElfW(Symndx) symidx;
+ const ElfW(Sym) *sym;
+#if ! VERSIONED
+ int num_versions = 0;
+ const ElfW(Sym) *versioned_sym = NULL;
+#endif
+
+ map = list[i];
+
+ /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */
+ if (skip != NULL && map == skip)
+ continue;
+
+ /* Skip objects that could not be opened, which can occur in trace
+ mode. */
+ if (map->l_opencount == 0)
+ continue;
+
+ /* Don't search the executable when resolving a copy reloc. */
+ if (elf_machine_lookup_noexec_p (reloc_type)
+ && map->l_type == lt_executable)
+ continue;
+
+ /* Skip objects without symbol tables. */
+ if (map->l_info[DT_SYMTAB] == NULL)
+ continue;
+
+ /* Print some debugging info if wanted. */
+ if (_dl_debug_symbols)
+ _dl_debug_message (1, "symbol=", undef_name, "; lookup in file=",
+ map->l_name[0] ? map->l_name : _dl_argv[0],
+ "\n", NULL);
+
+ symtab = (const void *) map->l_info[DT_SYMTAB]->d_un.d_ptr;
+ strtab = (const void *) map->l_info[DT_STRTAB]->d_un.d_ptr;
+ verstab = map->l_versyms;
+
+ /* Search the appropriate hash bucket in this object's symbol table
+ for a definition for the same symbol name. */
+ for (symidx = map->l_buckets[hash % map->l_nbuckets];
+ symidx != STN_UNDEF;
+ symidx = map->l_chain[symidx])
+ {
+ sym = &symtab[symidx];
+
+ if (sym->st_value == 0 || /* No value. */
+ (elf_machine_lookup_noplt_p (reloc_type) /* Reject PLT entry. */
+ && sym->st_shndx == SHN_UNDEF))
+ continue;
+
+ if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC)
+ /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC entries
+ since these are no code/data definitions. */
+ continue;
+
+ if (sym != ref && strcmp (strtab + sym->st_name, undef_name))
+ /* Not the symbol we are looking for. */
+ continue;
+
+#if VERSIONED
+ if (verstab == NULL)
+ {
+ /* We need a versioned system but haven't found any. If
+ this is the object which is referenced in the verneed
+ entry it is a bug in the library since a symbol must
+ not simply disappear. */
+ if (version->filename != NULL
+ && _dl_name_match_p (version->filename, map))
+ return -2;
+ /* Otherwise we accept the symbol. */
+ }
+ else
+ {
+ /* We can match the version information or use the
+ default one if it is not hidden. */
+ ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+ if ((map->l_versions[ndx].hash != version->hash
+ || strcmp (map->l_versions[ndx].name, version->name))
+ && (version->hidden || map->l_versions[ndx].hash
+ || (verstab[symidx] & 0x8000)))
+ /* It's not the version we want. */
+ 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. */
+ if (verstab != NULL)
+ {
+ ElfW(Half) ndx = verstab[symidx] & 0x7fff;
+ if (ndx > 2) /* map->l_versions[ndx].hash != 0) */
+ {
+ /* Don't accept hidden symbols. */
+ if ((verstab[symidx] & 0x8000) == 0 && num_versions++ == 0)
+ /* No version so far. */
+ versioned_sym = sym;
+ continue;
+ }
+ }
+#endif
+
+ /* There cannot be another entry for this symbol so stop here. */
+ goto found_it;
+ }
+
+ /* If we have seen exactly one versioned symbol while we are
+ looking for an unversioned symbol and the version is not the
+ default version we still accept this symbol since there are
+ no possible ambiguities. */
+#if VERSIONED
+ sym = NULL;
+#else
+ sym = num_versions == 1 ? versioned_sym : NULL;
+#endif
+
+ if (sym != NULL)
+ {
+ found_it:
+ switch (ELFW(ST_BIND) (sym->st_info))
+ {
+ case STB_GLOBAL:
+ /* Global definition. Just what we need. */
+ result->s = sym;
+ result->m = map;
+ return 1;
+ case STB_WEAK:
+ /* Weak definition. Use this value if we don't find another. */
+ if (! result->s)
+ {
+ result->s = sym;
+ result->m = map;
+ }
+ break;
+ default:
+ /* Local symbols are ignored. */
+ break;
+ }
+ }
+
+#if VERSIONED
+ /* If this current map is the one mentioned in the verneed entry
+ and we have not found a weak entry, it is a bug. */
+ if (symidx == STN_UNDEF && version->filename != NULL
+ && _dl_name_match_p (version->filename, map))
+ return -1;
+#endif
+ }
+ while (++i < n);
+
+ /* We have not found anything until now. */
+ return 0;
+}
+
+#undef FCT
+#undef ARG
+#undef VERSIONED