aboutsummaryrefslogtreecommitdiff
path: root/elf/dl-lookup.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2010-03-24 10:14:22 -0700
committerUlrich Drepper <drepper@redhat.com>2010-03-24 10:14:22 -0700
commit4ad43b62d6b893e73d5af72565f23c064b9c59b5 (patch)
tree16f1d6f45ddbed3a8a17a8f8f29db240ef13b063 /elf/dl-lookup.c
parent9ac9129d496d27b93c6fdfe0a22b68b3e4ee55df (diff)
downloadglibc-4ad43b62d6b893e73d5af72565f23c064b9c59b5.tar
glibc-4ad43b62d6b893e73d5af72565f23c064b9c59b5.tar.gz
glibc-4ad43b62d6b893e73d5af72565f23c064b9c59b5.tar.bz2
glibc-4ad43b62d6b893e73d5af72565f23c064b9c59b5.zip
Fix handling of STB_GNU_UNIQUE in LD_TRACE_PRELINKING
Diffstat (limited to 'elf/dl-lookup.c')
-rw-r--r--elf/dl-lookup.c54
1 files changed, 52 insertions, 2 deletions
diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c
index 763ec16fa4..78c8669e30 100644
--- a/elf/dl-lookup.c
+++ b/elf/dl-lookup.c
@@ -1,5 +1,6 @@
/* Look up a symbol in the loaded objects.
- Copyright (C) 1995-2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 1995-2005, 2006, 2007, 2009, 2010
+ 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
@@ -414,6 +415,20 @@ do_lookup_x (const char *undef_name, uint_fast32_t new_hash,
assert (!RTLD_CHECK_FOREIGN_CALL);
#endif
+#ifdef SHARED
+ /* If tab->entries is NULL, but tab->size is not, it means
+ this is the second, conflict finding, lookup for
+ LD_TRACE_PRELINKING in _dl_debug_bindings. Don't
+ allocate anything and don't enter anything into the
+ hash table. */
+ if (__builtin_expect (tab->size, 0))
+ {
+ assert (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK);
+ __rtld_lock_unlock_recursive (tab->lock);
+ goto success;
+ }
+#endif
+
#define INITIAL_NUNIQUE_SYM_TABLE 31
size = INITIAL_NUNIQUE_SYM_TABLE;
entries = calloc (sizeof (struct unique_sym), size);
@@ -917,13 +932,48 @@ _dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
{
const uint_fast32_t new_hash = dl_new_hash (undef_name);
unsigned long int old_hash = 0xffffffff;
+ struct unique_sym *saved_entries
+ = GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries;
+ GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = NULL;
do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val,
undef_map->l_local_scope[0], 0, version, 0, NULL,
type_class, undef_map);
-
if (val.s != value->s || val.m != value->m)
conflict = 1;
+ else if (__builtin_expect (undef_map->l_symbolic_in_local_scope, 0)
+ && val.s
+ && __builtin_expect (ELFW(ST_BIND) (val.s->st_info),
+ STB_GLOBAL) == STB_GNU_UNIQUE)
+ {
+ /* If it is STB_GNU_UNIQUE and undef_map's l_local_scope
+ contains any DT_SYMBOLIC libraries, unfortunately there
+ can be conflicts even if the above is equal. As symbol
+ resolution goes from the last library to the first and
+ if a STB_GNU_UNIQUE symbol is found in some late DT_SYMBOLIC
+ library, it would be the one that is looked up. */
+ struct sym_val val2 = { NULL, NULL };
+ size_t n;
+ struct r_scope_elem *scope = undef_map->l_local_scope[0];
+
+ for (n = 0; n < scope->r_nlist; n++)
+ if (scope->r_list[n] == val.m)
+ break;
+
+ for (n++; n < scope->r_nlist; n++)
+ if (scope->r_list[n]->l_info[DT_SYMBOLIC] != NULL
+ && do_lookup_x (undef_name, new_hash, &old_hash, *ref,
+ &val2,
+ &scope->r_list[n]->l_symbolic_searchlist,
+ 0, version, 0, NULL, type_class,
+ undef_map) > 0)
+ {
+ conflict = 1;
+ val = val2;
+ break;
+ }
+ }
+ GL(dl_ns)[LM_ID_BASE]._ns_unique_sym_table.entries = saved_entries;
}
if (value->s)