Fix handling of STB_GNU_UNIQUE in LD_TRACE_PRELINKING
authorUlrich Drepper <drepper@redhat.com>
Wed, 24 Mar 2010 17:14:22 +0000 (10:14 -0700)
committerUlrich Drepper <drepper@redhat.com>
Wed, 24 Mar 2010 17:14:22 +0000 (10:14 -0700)
ChangeLog
elf/dl-deps.c
elf/dl-lookup.c
include/link.h

index 6bf4fdc..9a2b2ca 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2010-03-23  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-lookup.c (do_lookup_x): If tab->entries is NULL,
+       but tab->size != 0, just unlock and goto success, without
+       allocating anything or entering anything into the hash table.
+       (_dl_debug_bindings): Temporarily set tab->entries to NULL
+       around do_lookup_x in undef_map->l_local_scope[0].  If
+       undef_map->l_symbolic_in_local_scope, lookup also in
+       symbolic_searchlist of following libraries in l_local_scope
+       that have DT_SYMBOLIC set.
+       * elf/dl-deps.c (_dl_map_object_deps): Compute
+       l_symbolic_in_local_scope.
+       * include/link.h (struct link_map): Add l_symbolic_in_local_scope
+       bitfield.
+
 2010-03-24  Ulrich Drepper  <drepper@redhat.com>
 
        [BZ #11410]
index 34c6024..a58de5c 100644 (file)
@@ -1,5 +1,5 @@
 /* Load the dependencies of a mapped object.
-   Copyright (C) 1996-2003, 2004, 2005, 2006, 2007
+   Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010
    Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -554,7 +554,12 @@ Filters not supported with LD_TRACE_PRELINKING"));
          cnt = _dl_build_local_scope (l_initfini, l);
          assert (cnt <= nlist);
          for (j = 0; j < cnt; j++)
-           l_initfini[j]->l_reserved = 0;
+           {
+             l_initfini[j]->l_reserved = 0;
+             if (j && __builtin_expect (l_initfini[j]->l_info[DT_SYMBOLIC]
+                                        != NULL, 0))
+               l->l_symbolic_in_local_scope = true;
+           }
 
          l->l_local_scope[0] =
            (struct r_scope_elem *) malloc (sizeof (struct r_scope_elem)
index 763ec16..78c8669 100644 (file)
@@ -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)
index 26c6743..9d1fc1a 100644 (file)
@@ -1,6 +1,6 @@
 /* Data structure for communication from the run-time dynamic linker for
    loaded ELF shared objects.
-   Copyright (C) 1995-2006, 2007, 2009 Free Software Foundation, Inc.
+   Copyright (C) 1995-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
@@ -188,6 +188,10 @@ struct link_map
     unsigned int l_contiguous:1; /* Nonzero if inter-segment holes are
                                    mprotected or if no holes are present at
                                    all.  */
+    unsigned int l_symbolic_in_local_scope:1; /* Nonzero if l_local_scope
+                                                during LD_TRACE_PRELINKING=1
+                                                contains any DT_SYMBOLIC
+                                                libraries.  */
 
     /* Collected information about own RPATH directories.  */
     struct r_search_path_struct l_rpath_dirs;