]> sourceware.org Git - glibc.git/blobdiff - elf/dl-lookup.c
* elf/dl-lookup.c (_dl_debug_bindings): Print TLS lookups always.
[glibc.git] / elf / dl-lookup.c
index 1284e2b3dc4dc9da169018ad7f31cf9146a10542..e2f55060307e58c869863f499c9d6e8028847256 100644 (file)
@@ -1,23 +1,24 @@
 /* Look up a symbol in the loaded objects.
-   Copyright (C) 1995,96,97,98,99,2000  Free Software Foundation, Inc.
+   Copyright (C) 1995,96,97,98,99,2000,2001,2002 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.
+   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
-   Library General Public License for more details.
+   Lesser 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.  */
+   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>
@@ -25,6 +26,7 @@
 #include "dl-hash.h"
 #include <dl-machine.h>
 #include <bits/libc-lock.h>
+#include <tls.h>
 
 #include <assert.h>
 
@@ -59,131 +61,157 @@ struct sym_val
   })
 
 /* Statistics function.  */
-unsigned long int _dl_num_relocations;
+#ifdef SHARED
+# define bump_num_relocations() ++GL(dl_num_relocations)
+#else
+# define bump_num_relocations() ((void) 0)
+#endif
 
-/* During the program run we must not modify the global data of
-   loaded shared object simultanously in two threads.  Therefore we
-   protect `_dl_open' and `_dl_close' in dl-close.c.
-
-   This must be a recursive lock since the initializer function of
-   the loaded object might as well require a call to this function.
-   At this time it is not anymore a problem to modify the tables.  */
-__libc_lock_define (extern, _dl_load_lock)
 
 
 /* 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
-#define PROTECTED      0
 #include "do-lookup.h"
 
 #define VERSIONED      1
-#define PROTECTED      0
 #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;
+
+  /* Don't create cross-reference between modules which are
+     dynamically loaded by the same dlopen() call.  */
+  if (undef_map->l_opencount == 0 && map->l_opencount == 0)
+    return 0;
+
   /* Make sure nobody can unload the object while we are at it.  */
-  __libc_lock_lock (_dl_load_lock);
+  __libc_lock_lock_recursive (GL(dl_load_lock));
 
   /* Determine whether UNDEF_MAP already has a reference to MAP.  First
      look in the normal dependencies.  */
-  list = undef_map->l_searchlist.r_list;
-  act = undef_map->l_searchlist.r_nlist;
-
-  for (i = 0; i < act; ++i)
-    if (list[i] == map)
-      break;
-
-  if (__builtin_expect (i == act, 1))
+  if (undef_map->l_searchlist.r_list != NULL)
     {
-      /* 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;
+      list = undef_map->l_initfini;
 
-      for (i = 0; i < act; ++i)
+      for (i = 0; list[i] != NULL; ++i)
        if (list[i] == map)
-         break;
+         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;
 
-      if (i == act)
+  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 = GL(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))
        {
-         /* 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.  */
-         struct link_map *runp = _dl_loaded;
-
-         while (runp != NULL && runp != map)
-           runp = runp->l_next;
-
-         if (runp != NULL)
-           {
-             unsigned int j;
-
-             /* 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;
-
-             /* And increment the counter in the referenced object.  */
-             ++map->l_opencount;
-
-             /* Display information if we are debugging.  */
-             if (__builtin_expect (_dl_debug_files, 0))
-               _dl_debug_message (1, "\nfile=",
-                                  map->l_name[0] ? map->l_name : _dl_argv[0],
-                                  ";  needed by ",
-                                  undef_map->l_name[0]
-                                  ? undef_map->l_name : _dl_argv[0],
-                                  " (relocation dependency)\n\n", NULL);
-           }
+         /* 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
-           /* Whoa, that was bad luck.  We have to search again.  */
-           result = -1;
+           /* 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
+        behavior.  */
+      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 (GL(dl_debug_mask) & DL_DEBUG_FILES, 0))
+       INTUSE(_dl_debug_printf) ("\
+\nfile=%s;  needed by %s (relocation dependency)\n\n",
+                                 map->l_name[0] ? map->l_name : rtld_progname,
+                                 undef_map->l_name[0]
+                                 ? undef_map->l_name : rtld_progname);
     }
+  else
+    /* Whoa, that was bad luck.  We have to search again.  */
+    result = -1;
 
+ out:
   /* Release the lock.  */
-  __libc_lock_unlock (_dl_load_lock);
+  __libc_lock_unlock_recursive (GL(dl_load_lock));
 
   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,
+                   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
+                   struct sym_val *value,
+                   const struct r_found_version *version, int type_class,
+                   int protected);
 
 /* Search loaded objects' symbol tables for a definition of the symbol
    UNDEF_NAME.  */
@@ -192,94 +220,80 @@ 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 reloc_type, int explicit)
+                  int type_class, int flags)
 {
-  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;
   int protected;
-  int noexec = elf_machine_lookup_noexec_p (reloc_type);
-  int noplt = elf_machine_lookup_noplt_p (reloc_type);
 
-  ++_dl_num_relocations;
+  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, NULL,
-                  noexec, noplt))
-      {
-       /* 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_global, 0)
-           && (__builtin_expect (current_value.m->l_type, lt_library)
-               == lt_loaded)
-           && undef_map != current_value.m
-           /* Don't do this for explicit lookups as opposed to implicit
-              runtime lookups.  */
-           && __builtin_expect (! explicit, 1)
-           /* 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,
-                                   reloc_type, 0);
-
-       break;
-      }
+    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 && reference_name[0]
+       _dl_signal_cerror (0, (reference_name[0]
                               ? reference_name
-                              : (_dl_argv[0] ?: "<main program>")),
+                              : (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 (_dl_debug_bindings, 0))
-    _dl_debug_message (1, "binding file ",
-                      (reference_name && reference_name[0]
-                       ? reference_name
-                       : (_dl_argv[0] ?: "<main program>")),
-                      " to ", current_value.m->l_name[0]
-                      ? current_value.m->l_name : _dl_argv[0],
-                      ": ", protected ? "protected" : "normal",
-                      " symbol `", undef_name, "'\n", NULL);
-
-  if (__builtin_expect (protected == 0, 1))
+  if (__builtin_expect (protected != 0, 0))
     {
-      *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 */
+      /* 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 (do_lookup (undef_name, hash, *ref, &protected_value, *scope, 0,
-                      NULL, 0, 1))
+       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)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
        {
-         *ref = current_value.s;
-         return LOOKUP_VALUE (current_value.m);
+         current_value.s = *ref;
+         current_value.m = undef_map;
        }
-
-      return LOOKUP_VALUE (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 INTUSE(_dl_lookup_symbol) (undef_name, undef_map, ref,
+                                       symbol_scope, type_class, flags);
+
+  if (__builtin_expect (GL(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);
 }
+INTDEF (_dl_lookup_symbol)
 
 
 /* This function is nearly the same as `_dl_lookup_symbol' but it
@@ -294,26 +308,24 @@ _dl_lookup_symbol_skip (const char *undef_name,
                        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;
+  bump_num_relocations ();
 
   /* Search the relevant loaded objects for a definition.  */
   scope = symbol_scope;
-  for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
-    assert (i < (*scope)->r_nduplist);
+  for (i = 0; (*scope)->r_list[i] != skip_map; ++i)
+    assert (i < (*scope)->r_nlist);
 
-  if (i >= (*scope)->r_nlist
-        || ! do_lookup (undef_name, hash, *ref, &current_value, *scope, i,
-                        skip_map, 0, 0))
+  if (! _dl_do_lookup (undef_name, hash, *ref, &current_value, *scope, i,
+                      DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
     while (*++scope)
-      if (do_lookup (undef_name, hash, *ref, &current_value, *scope, 0,
-                    skip_map, 0, 0))
+      if (_dl_do_lookup (undef_name, hash, *ref, &current_value, *scope, 0,
+                        DL_LOOKUP_RETURN_NEWEST, skip_map, 0))
        break;
 
   if (__builtin_expect (current_value.s == NULL, 0))
@@ -324,43 +336,36 @@ _dl_lookup_symbol_skip (const char *undef_name,
 
   protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
 
-  if (__builtin_expect (_dl_debug_bindings, 0))
-    _dl_debug_message (1, "binding file ",
-                      (reference_name && reference_name[0]
-                       ? reference_name
-                       : (_dl_argv[0] ?: "<main program>")),
-                      " to ", current_value.m->l_name[0]
-                      ? current_value.m->l_name : _dl_argv[0],
-                      ": ", protected ? "protected" : "normal",
-                      " symbol `", undef_name, "'\n", NULL);
-
-  if (__builtin_expect (protected == 0, 1))
-    {
-      *ref = current_value.s;
-      return LOOKUP_VALUE (current_value.m);
-    }
-  else
+  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
-         || !do_lookup (undef_name, hash, *ref, &protected_value, *scope, i,
-                        skip_map, 0, 1))
+         || !_dl_do_lookup (undef_name, hash, *ref, &protected_value, *scope,
+                            i, DL_LOOKUP_RETURN_NEWEST, skip_map,
+                            ELF_RTYPE_CLASS_PLT))
        while (*++scope)
-         if (do_lookup (undef_name, hash, *ref, &protected_value, *scope, 0,
-                        skip_map, 0, 1))
+         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)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
        {
-         *ref = current_value.s;
-         return LOOKUP_VALUE (current_value.m);
+         current_value.s = *ref;
+         current_value.m = undef_map;
        }
-
-      return LOOKUP_VALUE (undef_map);
     }
+
+  if (__builtin_expect (GL(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);
 }
 
 
@@ -375,55 +380,37 @@ _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 reloc_type, int explicit)
+                            int type_class, int flags)
 {
-  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;
   int protected;
-  int noexec = elf_machine_lookup_noexec_p (reloc_type);
-  int noplt = elf_machine_lookup_noplt_p (reloc_type);
 
-  ++_dl_num_relocations;
+  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)
     {
       int res = do_lookup_versioned (undef_name, hash, *ref, &current_value,
-                                    *scope, 0, version, NULL, noexec, noplt);
+                                    *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_global, 0)
-             && (__builtin_expect (current_value.m->l_type, lt_library)
-                 == lt_loaded)
-             && undef_map != current_value.m
-             /* Don't do this for explicit lookups as opposed to implicit
-                runtime lookups.  */
-             && __builtin_expect (! explicit, 1)
-             /* 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,
-                                               reloc_type, 0);
-
-         break;
-       }
+       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]
+         _dl_signal_cerror (0, (reference_name[0]
                                 ? reference_name
-                                : (_dl_argv[0] ?: "<main program>")),
+                                : (rtld_progname ?: "<main program>")),
+                            N_("relocation error"),
                             make_string ("symbol ", undef_name, ", version ",
                                          version->name,
                                          " not defined in file ",
@@ -439,55 +426,68 @@ _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)
-       /* We could find no value for a strong reference.  */
-       /* XXX We cannot translate the message.  */
-       _dl_signal_cerror (0, (reference_name && reference_name[0]
-                              ? reference_name
-                              : (_dl_argv[0] ?: "<main program>")),
-                          make_string (undefined_msg, undef_name,
-                                       ", version ", version->name ?: NULL));
+       {
+         /* 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[0]
+                                ? reference_name
+                                : (rtld_progname ?: "<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_bindings, 0))
-    _dl_debug_message (1, "binding file ",
-                      (reference_name && reference_name[0]
-                       ? reference_name
-                       : (_dl_argv[0] ?: "<main program>")),
-                      " to ", current_value.m->l_name[0]
-                      ? current_value.m->l_name : _dl_argv[0],
-                      ": ", protected ? "protected" : "normal",
-                      " symbol `", undef_name, "' [", version->name,
-                      "]\n", NULL);
-
-  if (__builtin_expect (protected == 0, 1))
+  if (__builtin_expect (protected != 0, 0))
     {
-      *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 */
+      /* 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 (do_lookup_versioned (undef_name, hash, *ref, &protected_value,
-                                *scope, 0, version, NULL, 0, 1))
+       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)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
        {
-         *ref = current_value.s;
-         return LOOKUP_VALUE (current_value.m);
+         current_value.s = *ref;
+         current_value.m = undef_map;
        }
-
-      return LOOKUP_VALUE (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 != 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 INTUSE(_dl_lookup_versioned_symbol) (undef_name, undef_map,
+                                                 ref, symbol_scope,
+                                                 version, type_class, flags);
+
+  if (__builtin_expect (GL(dl_debug_mask)
+                       & (DL_DEBUG_BINDINGS|DL_DEBUG_PRELINK), 0))
+    _dl_debug_bindings (undef_name, undef_map, ref, symbol_scope,
+                       &current_value, version, type_class, protected);
+
+  *ref = current_value.s;
+  return LOOKUP_VALUE (current_value.m);
 }
+INTDEF (_dl_lookup_versioned_symbol)
 
 
 /* Similar to _dl_lookup_symbol_skip but takes an additional argument
@@ -501,26 +501,25 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
                                  const struct r_found_version *version,
                                  struct link_map *skip_map)
 {
-  const char *reference_name = undef_map ? undef_map->l_name : NULL;
+  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;
 
-  ++_dl_num_relocations;
+  bump_num_relocations ();
 
   /* Search the relevant loaded objects for a definition.  */
   scope = symbol_scope;
-  for (i = 0; (*scope)->r_duplist[i] != skip_map; ++i)
-    assert (i < (*scope)->r_nduplist);
+  for (i = 0; (*scope)->r_list[i] != skip_map; ++i)
+    assert (i < (*scope)->r_nlist);
 
-  if (i >= (*scope)->r_nlist
-      || ! do_lookup_versioned (undef_name, hash, *ref, &current_value,
-                               *scope, i, version, skip_map, 0, 0))
+  if (! _dl_do_lookup_versioned (undef_name, hash, *ref, &current_value,
+                                *scope, i, version, skip_map, 0))
     while (*++scope)
-      if (do_lookup_versioned (undef_name, hash, *ref, &current_value, *scope,
-                              0, version, skip_map, 0, 0))
+      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))
@@ -533,9 +532,10 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
          __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 && reference_name[0]
+         _dl_signal_cerror (0, (reference_name[0]
                                 ? reference_name
-                                : (_dl_argv[0] ?: "<main program>")), buf);
+                                : (rtld_progname ?: "<main program>")),
+                            NULL, buf);
        }
       *ref = NULL;
       return 0;
@@ -543,44 +543,36 @@ _dl_lookup_versioned_symbol_skip (const char *undef_name,
 
   protected = *ref && ELFW(ST_VISIBILITY) ((*ref)->st_other) == STV_PROTECTED;
 
-  if (__builtin_expect (_dl_debug_bindings, 0))
-    _dl_debug_message (1, "binding file ",
-                      (reference_name && reference_name[0]
-                       ? reference_name
-                       : (_dl_argv[0] ?: "<main program>")),
-                      " to ", current_value.m->l_name[0]
-                      ? current_value.m->l_name : _dl_argv[0],
-                      ": ", protected ? "protected" : "normal",
-                      " symbol `", undef_name, "' [", version->name,
-                      "]\n", NULL);
-
-  if (__builtin_expect (protected == 0, 1))
+  if (__builtin_expect (protected != 0, 0))
     {
-      *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 */
+      /* 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
-         || !do_lookup_versioned (undef_name, hash, *ref, &protected_value,
-                                  *scope, i, version, skip_map, 0, 1))
+         || !_dl_do_lookup_versioned (undef_name, hash, *ref,
+                                      &protected_value, *scope, i, version,
+                                      skip_map, ELF_RTYPE_CLASS_PLT))
        while (*++scope)
-         if (do_lookup_versioned (undef_name, hash, *ref, &protected_value,
-                                  *scope, 0, version, skip_map, 0, 1))
+         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)
+      if (protected_value.s != NULL && protected_value.m != undef_map)
        {
-         *ref = current_value.s;
-         return LOOKUP_VALUE (current_value.m);
+         current_value.s = *ref;
+         current_value.m = undef_map;
        }
-
-      return LOOKUP_VALUE (undef_map);
     }
+
+  if (__builtin_expect (GL(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);
 }
 
 
@@ -603,3 +595,114 @@ _dl_setup_hash (struct link_map *map)
   hash += map->l_nbuckets;
   map->l_chain = hash;
 }
+
+
+static void
+internal_function
+_dl_debug_bindings (const char *undef_name, struct link_map *undef_map,
+                   const ElfW(Sym) **ref, struct r_scope_elem *symbol_scope[],
+                   struct sym_val *value,
+                   const struct r_found_version *version, int type_class,
+                   int protected)
+{
+  const char *reference_name = undef_map->l_name;
+
+  if (GL(dl_debug_mask) & DL_DEBUG_BINDINGS)
+    {
+      INTUSE(_dl_debug_printf) ("binding file %s to %s: %s symbol `%s'",
+                               (reference_name[0]
+                                ? reference_name
+                                : (rtld_progname ?: "<main program>")),
+                               value->m->l_name[0]
+                               ? value->m->l_name : rtld_progname,
+                               protected ? "protected" : "normal",
+                               undef_name);
+      if (version)
+       _dl_debug_printf_c (" [%s]\n", version->name);
+      else
+       _dl_debug_printf_c ("\n");
+    }
+#ifdef SHARED
+  if (GL(dl_debug_mask) & DL_DEBUG_PRELINK)
+    {
+      int conflict = 0;
+      struct sym_val val = { NULL, NULL };
+
+      if ((GL(dl_trace_prelink_map) == NULL
+          || GL(dl_trace_prelink_map) == GL(dl_loaded))
+         && undef_map != GL(dl_loaded))
+       {
+         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);
+
+         if (val.s != value->s || val.m != value->m)
+           conflict = 1;
+       }
+
+#ifdef USE_TLS
+      if (value->s
+         && (__builtin_expect (ELFW(ST_TYPE) (value->s->st_info)
+                               == STT_TLS, 0)))
+       type_class = 4;
+#endif
+
+      if (conflict
+         || GL(dl_trace_prelink_map) == undef_map
+         || GL(dl_trace_prelink_map) == NULL
+         || type_class == 4)
+       {
+         _dl_printf ("%s 0x%0*Zx 0x%0*Zx -> 0x%0*Zx 0x%0*Zx ",
+                     conflict ? "conflict" : "lookup",
+                     (int) sizeof (ElfW(Addr)) * 2, undef_map->l_map_start,
+                     (int) sizeof (ElfW(Addr)) * 2,
+                     ((ElfW(Addr)) *ref) - undef_map->l_map_start,
+                     (int) sizeof (ElfW(Addr)) * 2,
+                     (ElfW(Addr)) (value->s ? value->m->l_map_start : 0),
+                     (int) sizeof (ElfW(Addr)) * 2,
+                     (ElfW(Addr)) (value->s ? value->s->st_value : 0));
+
+         if (conflict)
+           _dl_printf ("x 0x%0*Zx 0x%0*Zx ",
+                       (int) sizeof (ElfW(Addr)) * 2,
+                       (ElfW(Addr)) (val.s ? val.m->l_map_start : 0),
+                       (int) sizeof (ElfW(Addr)) * 2,
+                       (ElfW(Addr)) (val.s ? val.s->st_value : 0));
+
+         _dl_printf ("/%x %s\n", type_class, undef_name);
+       }
+    }
+#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);
+}
This page took 0.050633 seconds and 5 git commands to generate.