]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Update.
authorUlrich Drepper <drepper@redhat.com>
Sun, 6 Sep 1998 09:16:53 +0000 (09:16 +0000)
committerUlrich Drepper <drepper@redhat.com>
Sun, 6 Sep 1998 09:16:53 +0000 (09:16 +0000)
1998-09-06 09:00  Ulrich Drepper  <drepper@cygnus.com>

* version.h (VERSION): Bump to 2.0.96.

Rewrite runtime linker to be truly thread-safe.  There is now no
global variable specifying the scope.  We create all needed
scopes at the time the link maps are created.
* elf/Versions [GLIBC_2.1]: Add _dl_loaded and _dl_main_searchlist.
* elf/link.h: Add struct r_scope_elem and use this for l_searchlist,
l_symbolic_searchlist, l_scope, and l_local_scope elements in
struct link_map.
* elf/dl-close.c: Rewritten accordingly.
* elf/dl-deps.c: Likewise.
* elf/dl-error.c: Likewise.
* elf/dl-init.c: Likewise.
* elf/dl-load.c: Likewise.
* elf/dl-lookup.c: Likewise.
* elf/dl-object.c: Likewise.
* elf/dl-open.c: Likewise.
* elf/dl-reloc.c: Likewise.
* elf/dl-runtime.c: Likewise.
* elf/dl-support.c: Likewise.
* elf/dl-symbol.c: Likewise.
* elf/dl-version.c: Likewise.
* elf/dlfcn.h: Likewise.
* elf/dlsym.c: Likewise.
* elf/dlvsym.c: Likewise.
* elf/ldsodefs.h: Likewise.
* elf/rtld.c: Likewise.
* iconv/gconv_dl.c: Likewise.
* nss/nsswitch.c: Likewise.
* sysdeps/i386/dl-machine.h: Likewise.
* sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.

27 files changed:
ChangeLog
elf/Versions
elf/dl-close.c
elf/dl-deps.c
elf/dl-error.c
elf/dl-init.c
elf/dl-load.c
elf/dl-lookup.c
elf/dl-object.c
elf/dl-open.c
elf/dl-reloc.c
elf/dl-runtime.c
elf/dl-support.c
elf/dl-symbol.c
elf/dl-version.c
elf/dlfcn.h
elf/dlsym.c
elf/dlvsym.c
elf/ldsodefs.h
elf/link.h
elf/rtld.c
iconv/gconv_dl.c
linuxthreads/ChangeLog
linuxthreads/sysdeps/pthread/bits/libc-lock.h
nss/nsswitch.c
sysdeps/i386/dl-machine.h
sysdeps/unix/sysv/linux/i386/dl-librecon.h

index f929887f55ea88314b36c724cc853eaf3d0278df..b6a0202f79165dd9f34ff418662ec3dd046eba09 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+1998-09-06 09:00  Ulrich Drepper  <drepper@cygnus.com>
+
+       * version.h (VERSION): Bump to 2.0.96.
+
+       Rewrite runtime linker to be truly thread-safe.  There is now no
+       global variable specifying the scope.  We create all needed
+       scopes at the time the link maps are created.
+       * elf/Versions [GLIBC_2.1]: Add _dl_loaded and _dl_main_searchlist.
+       * elf/link.h: Add struct r_scope_elem and use this for l_searchlist,
+       l_symbolic_searchlist, l_scope, and l_local_scope elements in
+       struct link_map.
+       * elf/dl-close.c: Rewritten accordingly.
+       * elf/dl-deps.c: Likewise.
+       * elf/dl-error.c: Likewise.
+       * elf/dl-init.c: Likewise.
+       * elf/dl-load.c: Likewise.
+       * elf/dl-lookup.c: Likewise.
+       * elf/dl-object.c: Likewise.
+       * elf/dl-open.c: Likewise.
+       * elf/dl-reloc.c: Likewise.
+       * elf/dl-runtime.c: Likewise.
+       * elf/dl-support.c: Likewise.
+       * elf/dl-symbol.c: Likewise.
+       * elf/dl-version.c: Likewise.
+       * elf/dlfcn.h: Likewise.
+       * elf/dlsym.c: Likewise.
+       * elf/dlvsym.c: Likewise.
+       * elf/ldsodefs.h: Likewise.
+       * elf/rtld.c: Likewise.
+       * iconv/gconv_dl.c: Likewise.
+       * nss/nsswitch.c: Likewise.
+       * sysdeps/i386/dl-machine.h: Likewise.
+       * sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.
+
 1998-09-05  Mark Kettenis  <kettenis@phys.uva.nl>
 
        * sysdeps/mach/hurd/i386/init-first.c (init1): Call
index ed5ba6f83001dbf7a84dae59f12af19ff5dd3887..29795cef4c1bd2178f688b12bbe5b134a4d17433 100644 (file)
@@ -19,6 +19,7 @@ libc {
   GLIBC_2.1 {
     # global variables
     _dl_profile; _dl_profile_map; _dl_profile_output; _dl_start_profile;
+    _dl_loaded; _dl_main_searchlist;
 
     # functions used in other libraries
     _dl_mcount; _dl_mcount_wrapper; _dl_mcount_wrapper_check; _dl_unload_cache;
index 3b1e3c9f57f8fcf55248ab54dc956ce2f315a1a0..a2605394405079e71631be5fb802a6a17768cf7a 100644 (file)
@@ -57,8 +57,8 @@ _dl_close (struct link_map *map)
       return;
     }
 
-  list = map->l_searchlist;
-  nsearchlist = map->l_nsearchlist;
+  list = map->l_searchlist.r_list;
+  nsearchlist = map->l_searchlist.r_nlist;
 
   /* Call all termination functions at once.  */
   for (i = 0; i < nsearchlist; ++i)
@@ -103,16 +103,18 @@ _dl_close (struct link_map *map)
          if (imap->l_global)
            {
              /* This object is in the global scope list.  Remove it.  */
-             struct link_map **tail = _dl_global_scope_end;
+             unsigned int cnt = _dl_main_searchlist->r_nlist;
+
              do
-               --tail;
-             while (*tail != imap);
-             while (tail < _dl_global_scope_end)
+               --cnt;
+             while (_dl_main_searchlist->r_list[cnt] != imap);
+             while (cnt < _dl_main_searchlist->r_nlist)
                {
-                 tail[0] = tail[1];
-                 ++tail;
+                 _dl_main_searchlist->r_list[0]
+                   = _dl_main_searchlist->r_list[1];
+                 ++cnt;
                }
-             --_dl_global_scope_end;
+             --_dl_main_searchlist->r_nlist;
            }
 
          /* We can unmap all the maps at once.  We determined the
@@ -135,8 +137,6 @@ _dl_close (struct link_map *map)
 #endif
          if (imap->l_next)
            imap->l_next->l_prev = imap->l_prev;
-         if (imap->l_searchlist && imap->l_searchlist != list)
-           free (imap->l_searchlist);
 
          if (imap->l_versions != NULL)
            free (imap->l_versions);
@@ -156,15 +156,14 @@ _dl_close (struct link_map *map)
          while (lnp != NULL);
 
          /* Remove the searchlists.  */
-         if (imap->l_dupsearchlist != imap->l_searchlist)
+         if (imap->l_searchlist.r_duplist != imap->l_searchlist.r_list)
            {
-             /* If a l_searchlist object exists there always also is
-                a l_dupsearchlist object.  */
-             assert (imap->l_dupsearchlist != NULL);
-             free (imap->l_dupsearchlist);
+             /* If a r_list exists there always also is a r_duplist.  */
+             assert (imap->l_searchlist.r_list != NULL);
+             free (imap->l_searchlist.r_duplist);
            }
-         if (imap != map && imap->l_searchlist != NULL)
-           free (imap->l_searchlist);
+         if (imap != map && imap->l_searchlist.r_list != NULL)
+           free (imap->l_searchlist.r_list);
 
          free (imap);
        }
index 21dcf0dd41cca9c8f21b6dfb96d7b92a44ad209b..f08f65264283e1a0ad4c1939ed9f5727ecf31b32 100644 (file)
@@ -372,32 +372,33 @@ _dl_map_object_deps (struct link_map *map,
 
   /* Store the search list we built in the object.  It will be used for
      searches in the scope of this object.  */
-  map->l_searchlist = malloc (nlist * sizeof (struct link_map *));
-  if (map->l_searchlist == NULL)
+  map->l_searchlist.r_list = malloc (nlist * sizeof (struct link_map *));
+  if (map->l_searchlist.r_list == NULL)
     _dl_signal_error (ENOMEM, map->l_name,
                      "cannot allocate symbol search list");
-  map->l_nsearchlist = nlist;
+  map->l_searchlist.r_nlist = nlist;
 
   for (nlist = 0, runp = known; runp; runp = runp->unique)
     {
-      map->l_searchlist[nlist++] = runp->map;
+      map->l_searchlist.r_list[nlist++] = runp->map;
 
       /* Now clear all the mark bits we set in the objects on the search list
         to avoid duplicates, so the next call starts fresh.  */
       runp->map->l_reserved = 0;
     }
 
-  map->l_ndupsearchlist = nduplist;
+  map->l_searchlist.r_nduplist = nduplist;
   if (nlist == nduplist)
-    map->l_dupsearchlist = map->l_searchlist;
+    map->l_searchlist.r_duplist = map->l_searchlist.r_list;
   else
     {
-      map->l_dupsearchlist = malloc (nduplist * sizeof (struct link_map *));
-      if (map->l_dupsearchlist == NULL)
+      map->l_searchlist.r_duplist = malloc (nduplist
+                                           * sizeof (struct link_map *));
+      if (map->l_searchlist.r_duplist == NULL)
        _dl_signal_error (ENOMEM, map->l_name,
                          "cannot allocate symbol search list");
 
       for (nlist = 0, runp = known; runp; runp = runp->dup)
-       map->l_dupsearchlist[nlist++] = runp->map;
+       map->l_searchlist.r_duplist[nlist++] = runp->map;
     }
 }
index 03292abaf4af3d4e22725d4da289abfd497a3d46..cfb6b9ead52dafe1e0c18df8330b2891a127f286 100644 (file)
@@ -22,6 +22,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <elf/ldsodefs.h>
+#include <bits/libc-lock.h>
 
 /* This structure communicates state between _dl_catch_error and
    _dl_signal_error.  */
@@ -31,14 +32,57 @@ struct catch
     jmp_buf env;               /* longjmp here on error.  */
   };
 
-/* This points to such a structure during a call to _dl_catch_error.
-   During implicit startup and run-time work for needed shared libraries,
-   this is null.  */
+/* Multiple threads at once can use the `_dl_catch_error' function.  The
+   calls can come from the `_dl_map_object_deps', `_dlerror_run', or from
+   any of the libc functionality which loads dynamic objects (NSS, iconv).
+   Therefore we have to be prepared to safe the state in thread-local
+   memory.  `catch' will only be used for the non-threaded case.
+
+   Please note the horrible kludge we have to use to check for the
+   thread functions to be defined.  The problem is that while running
+   ld.so standalone (i.e., before the relocation with the libc symbols
+   available) we do not have a real handling of undefined weak symbols.
+   All symbols are relocated, regardless of the availability.  They are
+   relocated relative to the load address of the dynamic linker.  Adding
+   this start address to zero (the value in the GOT for undefined symbols)
+   leads to an address which is the load address of ld.so.  Once we have
+   relocated with the libc values the value is NULL if the function is
+   not available.  Our "solution" is to regard NULL and the ld.so load
+   address as indicators for unavailable weak symbols.   */
 static struct catch *catch;
 
+#ifdef PIC
+# define tsd_setspecific(data) \
+  if (__libc_internal_tsd_set != (void *) _dl_rtld_map.l_addr                \
+      && __libc_internal_tsd_set != NULL)                                    \
+    __libc_internal_tsd_set (_LIBC_TSD_KEY_DL_ERROR, data);                  \
+  else                                                                       \
+    catch = (data)
+# define tsd_getspecific() \
+  (__libc_internal_tsd_set != (void *) _dl_rtld_map.l_addr                   \
+   && __libc_internal_tsd_set != NULL                                        \
+   ? (struct catch *) __libc_internal_tsd_get (_LIBC_TSD_KEY_DL_ERROR)       \
+   : catch)
+#else
+# define tsd_setspecific(data) \
+  if (__libc_internal_tsd_set != NULL)                                       \
+    __libc_internal_tsd_set (_LIBC_TSD_KEY_DL_ERROR, data);                  \
+  else                                                                       \
+    catch = (data)
+# define tsd_getspecific() \
+  (__libc_internal_tsd_set != NULL                                           \
+   ? (struct catch *) __libc_internal_tsd_get (_LIBC_TSD_KEY_DL_ERROR)       \
+   : catch)
+#endif
+
+
 /* This points to a function which is called when an error is
    received.  Unlike the handling of `catch' this function may return.
-   The arguments will be the `errstring' and `objname'.  */
+   The arguments will be the `errstring' and `objname'.
+
+   Since this functionality is not used in normal programs (only in ld.so)
+   we do not care about multi-threaded programs here.  We keep this as a
+   global variable.  */
 static receiver_fct receiver;
 
 
@@ -48,27 +92,30 @@ _dl_signal_error (int errcode,
                  const char *objname,
                  const char *errstring)
 {
+  struct catch *lcatch;
+
   if (! errstring)
     errstring = "DYNAMIC LINKER BUG!!!";
 
-  if (catch)
+  lcatch = tsd_getspecific ();
+  if (lcatch != NULL)
     {
       /* We are inside _dl_catch_error.  Return to it.  We have to
         duplicate the error string since it might be allocated on the
         stack.  */
       size_t objname_len = objname ? strlen (objname) + 2 : 0;
       size_t errstring_len = strlen (errstring) + 1;
-      catch->errstring = malloc (objname_len + errstring_len);
-      if (catch->errstring != NULL)
+      lcatch->errstring = malloc (objname_len + errstring_len);
+      if (lcatch->errstring != NULL)
        {
          if (objname_len > 0)
            {
-             memcpy (catch->errstring, objname, objname_len - 2);
-             memcpy (catch->errstring + objname_len - 2, ": ", 2);
+             memcpy (lcatch->errstring, objname, objname_len - 2);
+             memcpy (lcatch->errstring + objname_len - 2, ": ", 2);
            }
-         memcpy (catch->errstring + objname_len, errstring, errstring_len);
+         memcpy (lcatch->errstring + objname_len, errstring, errstring_len);
        }
-      longjmp (catch->env, errcode ?: -1);
+      longjmp (lcatch->env, errcode ?: -1);
     }
   else if (receiver)
     {
@@ -106,19 +153,19 @@ _dl_catch_error (char **errstring,
      inefficient.  So we initialize `c' by hand.  */
   c.errstring = NULL;
 
-  old = catch;
+  old = tsd_getspecific ();
   errcode = setjmp (c.env);
   if (errcode == 0)
     {
-      catch = &c;
+      tsd_setspecific (&c);
       (*operate) (args);
-      catch = old;
+      tsd_setspecific (old);
       *errstring = NULL;
       return 0;
     }
 
   /* We get here only if we longjmp'd out of OPERATE.  */
-  catch = old;
+  tsd_setspecific (old);
   *errstring = c.errstring;
   return errcode == -1 ? 0 : errcode;
 }
@@ -130,15 +177,15 @@ _dl_receive_error (receiver_fct fct, void (*operate) (void *), void *args)
   struct catch *old_catch;
   receiver_fct old_receiver;
 
-  old_catch = catch;
+  old_catch = tsd_getspecific ();
   old_receiver = receiver;
 
   /* Set the new values.  */
-  catch = NULL;
+  tsd_setspecific (NULL);
   receiver = fct;
 
   (*operate) (args);
 
-  catch = old_catch;
+  tsd_setspecific (old_catch);
   receiver = old_receiver;
 }
index f93f8f1cb5925dfce2a9cc340533f03752794319..64aa1ce0bf47dea8a57efe7fec9f781c434635ba 100644 (file)
@@ -26,7 +26,7 @@
 
 ElfW(Addr)
 internal_function
-_dl_init_next (struct link_map *map)
+_dl_init_next (struct r_scope_elem *searchlist)
 {
   unsigned int i;
 
@@ -34,10 +34,10 @@ _dl_init_next (struct link_map *map)
      dependency order, so processing that list from back to front gets us
      breadth-first leaf-to-root order.  */
 
-  i = map->l_nsearchlist;
+  i = searchlist->r_nlist;
   while (i-- > 0)
     {
-      struct link_map *l = map->l_searchlist[i];
+      struct link_map *l = searchlist->r_list[i];
 
       if (l->l_init_called)
        /* This object is all done.  */
@@ -53,8 +53,8 @@ _dl_init_next (struct link_map *map)
          continue;
        }
 
-      if (l->l_info[DT_INIT] &&
-         !(l->l_name[0] == '\0' && l->l_type == lt_executable))
+      if (l->l_info[DT_INIT]
+         && (l->l_name[0] != '\0' || l->l_type != lt_executable))
        {
          /* Run this object's initializer.  */
          l->l_init_running = 1;
index c9a39c01a2572d432d1140568f2e487fb33c38f2..35c34e03057f13f8964ac6d11ea0644e34b3d2ae 100644 (file)
@@ -529,7 +529,12 @@ _dl_init_paths (const char *llp)
   l = _dl_loaded;
   if (l != NULL)
     {
-      if (l->l_type != lt_loaded && l->l_info[DT_RPATH])
+      /* We should never get here when initializing in a static application.
+        If this is a dynamically linked application _dl_loaded always
+        points to the main map which is not dlopen()ed.  */
+      assert (l->l_type != lt_loaded);
+
+      if (l->l_info[DT_RPATH])
        {
          /* Allocate room for the search path and fill in information
             from RPATH.  */
@@ -727,11 +732,10 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
 #endif
 
   /* Enter the new object in the list of loaded objects.  */
-  l = _dl_new_object (realname, name, l_type);
+  l = _dl_new_object (realname, name, l_type, loader);
   if (! l)
     lose (ENOMEM, "cannot create shared object descriptor");
   l->l_opencount = 1;
-  l->l_loader = loader;
 
   /* Extract the remaining details we need from the ELF header
      and then read in the program header table.  */
@@ -973,6 +977,35 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname,
   if (l->l_info[DT_HASH])
     _dl_setup_hash (l);
 
+  /* If this object has DT_SYMBOLIC set modify now its scope.  We don't
+     have to do this for the main map.  */
+  if (l->l_info[DT_SYMBOLIC] && &l->l_searchlist != l->l_scope[0])
+    {
+      /* Create an appropriate searchlist.  It contains only this map.
+
+        XXX This is the definition of DT_SYMBOLIC in SysVr4.  The old
+        GNU ld.so implementation had a different interpretation which
+        is more reasonable.  We are prepared to add this possibility
+        back as part of a GNU extension of the ELF format.  */
+      l->l_symbolic_searchlist.r_list =
+       (struct link_map **) malloc (sizeof (struct link_map *));
+
+      if (l->l_symbolic_searchlist.r_list == NULL)
+       lose (ENOMEM, "cannot create searchlist");
+
+      l->l_symbolic_searchlist.r_list[0] = l;
+      l->l_symbolic_searchlist.r_nlist = 1;
+      l->l_symbolic_searchlist.r_duplist = l->l_symbolic_searchlist.r_list;
+      l->l_symbolic_searchlist.r_nduplist = 1;
+
+      /* Now move the existing entries one back.  */
+      memmove (&l->l_scope[1], &l->l_scope[0],
+              3 * sizeof (struct r_scope_elem *));
+
+      /* Now add the new entry.  */
+      l->l_scope[0] = &l->l_symbolic_searchlist;
+    }
+
   return l;
 }
 \f
@@ -1280,7 +1313,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
          /* Enter the new object in the list of loaded objects.  */
          if ((name_copy = local_strdup (name)) == NULL
-             || (l = _dl_new_object (name_copy, name, type)) == NULL)
+             || (l = _dl_new_object (name_copy, name, type, loader)) == NULL)
            _dl_signal_error (ENOMEM, name,
                              "cannot create shared object descriptor");
          /* We use an opencount of 0 as a sign for the faked entry.  */
index 7badf8632834bad05fc9b5d93dfb366c2e8d6494..5245c628d2a5b16bd4ed033e08248583af3b3774 100644 (file)
@@ -63,12 +63,12 @@ struct sym_val
 static inline int
 do_lookup (const char *undef_name, unsigned long int hash,
           const ElfW(Sym) *ref, struct sym_val *result,
-          struct link_map *scope, size_t i, const char *reference_name,
+          struct r_scope_elem *scope, size_t i, const char *reference_name,
           const struct r_found_version *version, struct link_map *skip,
           int reloc_type)
 {
-  struct link_map **list = scope->l_searchlist;
-  size_t n = scope->l_nsearchlist;
+  struct link_map **list = scope->r_list;
+  size_t n = scope->r_nlist;
   struct link_map *map;
 
   for (; i < n; ++i)
@@ -212,13 +212,13 @@ do_lookup (const char *undef_name, unsigned long int hash,
 ElfW(Addr)
 internal_function
 _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
-                  struct link_map *symbol_scope[],
+                  struct r_scope_elem *symbol_scope[],
                   const char *reference_name,
                   int reloc_type)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
-  struct link_map **scope;
+  struct r_scope_elem **scope;
 
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
@@ -260,19 +260,19 @@ _dl_lookup_symbol (const char *undef_name, const ElfW(Sym) **ref,
 ElfW(Addr)
 internal_function
 _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
-                       struct link_map *symbol_scope[],
+                       struct r_scope_elem *symbol_scope[],
                        const char *reference_name,
                        struct link_map *skip_map)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
-  struct link_map **scope;
+  struct r_scope_elem **scope;
   size_t i;
 
   /* Search the relevant loaded objects for a definition.  */
   scope = symbol_scope;
-  for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
-    assert (i < (*scope)->l_ndupsearchlist);
+  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, NULL, skip_map, 0))
@@ -309,14 +309,14 @@ _dl_lookup_symbol_skip (const char *undef_name, const ElfW(Sym) **ref,
 ElfW(Addr)
 internal_function
 _dl_lookup_versioned_symbol (const char *undef_name, const ElfW(Sym) **ref,
-                            struct link_map *symbol_scope[],
+                            struct r_scope_elem *symbol_scope[],
                             const char *reference_name,
                             const struct r_found_version *version,
                             int reloc_type)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
-  struct link_map **scope;
+  struct r_scope_elem **scope;
 
   /* Search the relevant loaded objects for a definition.  */
   for (scope = symbol_scope; *scope; ++scope)
@@ -375,20 +375,20 @@ ElfW(Addr)
 internal_function
 _dl_lookup_versioned_symbol_skip (const char *undef_name,
                                  const ElfW(Sym) **ref,
-                                 struct link_map *symbol_scope[],
+                                 struct r_scope_elem *symbol_scope[],
                                  const char *reference_name,
                                  const struct r_found_version *version,
                                  struct link_map *skip_map)
 {
   const unsigned long int hash = _dl_elf_hash (undef_name);
   struct sym_val current_value = { NULL, NULL };
-  struct link_map **scope;
+  struct r_scope_elem **scope;
   size_t i;
 
   /* Search the relevant loaded objects for a definition.  */
   scope = symbol_scope;
-  for (i = 0; (*scope)->l_dupsearchlist[i] != skip_map; ++i)
-    assert (i < (*scope)->l_ndupsearchlist);
+  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, version, skip_map, 0))
index db6e81c11e511ac6a523298fef445c19e1511a87..d9dd692be289bdb5cac53d62bc2cae4405dcce42 100644 (file)
 
 #include <assert.h>
 
-/* List of objects currently loaded is [2] of this, aka _dl_loaded.  */
-struct link_map *_dl_default_scope[5];
 
 /* Allocate a `struct link_map' for a new object being loaded,
    and enter it into the _dl_loaded list.  */
 
 struct link_map *
 internal_function
-_dl_new_object (char *realname, const char *libname, int type)
+_dl_new_object (char *realname, const char *libname, int type,
+               struct link_map *loader)
 {
+  struct link_map *l;
+  int idx;
   size_t libname_len = strlen (libname) + 1;
   struct link_map *new = calloc (sizeof *new, 1);
   struct libname_list *newname = malloc (sizeof *newname + libname_len);
@@ -46,26 +47,37 @@ _dl_new_object (char *realname, const char *libname, int type)
   newname->next = NULL;
   new->l_libname = newname;
   new->l_type = type;
+  new->l_loader = loader;
 
-  if (_dl_loaded == NULL)
-    {
-      new->l_prev = new->l_next = NULL;
-      _dl_loaded = new;
-    }
-  else
+  /* Counter for the scopes we have to handle.  */
+  idx = 0;
+
+  if (_dl_loaded != NULL)
     {
-      struct link_map *l = _dl_loaded;
+      l = _dl_loaded;
       while (l->l_next)
        l = l->l_next;
       new->l_prev = l;
-      new->l_next = NULL;
+      /* new->l_next = NULL;   Would be necesary but we use calloc.  */
       l->l_next = new;
-    }
 
-  /* Don't try to find the origin for the main map.  */
-  if (realname[0] == '\0')
-    new->l_origin = NULL;
+      /* Add the global scope.  */
+      new->l_scope[idx++] = &_dl_loaded->l_searchlist;
+    }
+  /* This is our local scope.  */
+  if (loader != NULL)
+    {
+      while (loader->l_loader != NULL)
+       loader = loader->l_loader;
+      new->l_scope[idx] = &loader->l_searchlist;
+    }
   else
+    new->l_scope[idx] = &new->l_searchlist;
+
+  new->l_local_scope[0] = new->l_scope[idx];
+
+  /* Don't try to find the origin for the main map which has the name "".  */
+  if (realname[0] != '\0')
     {
       char *origin;
 
index fa36fcb32ec5590c14d27afe752518a0eae1013e..6765b6ce0860a8e2aca15ff9446403e5c0cf6f04 100644 (file)
@@ -77,7 +77,7 @@ dl_open_worker (void *a)
 
   /* Load the named object.  */
   args->map = new = _dl_map_object (NULL, file, 0, lt_loaded, 0);
-  if (new->l_searchlist)
+  if (new->l_searchlist.r_list)
     /* It was already open.  */
     return;
 
@@ -97,21 +97,6 @@ dl_open_worker (void *a)
     {
       if (! l->l_relocated)
        {
-         /* We use an indirect call call for _dl_relocate_object because
-            we must avoid using the PLT in the call.  If our PLT entry for
-            _dl_relocate_object hasn't been used yet, then the dynamic
-            linker fixup routine will clobber _dl_global_scope during its
-            work.  We must be sure that nothing will require a PLT fixup
-            between when _dl_object_relocation_scope returns and when we
-            enter the dynamic linker's code (_dl_relocate_object).  */
-         __typeof (_dl_relocate_object) *reloc = &_dl_relocate_object;
-
-         /* GCC is very clever.  If we wouldn't add some magic it would
-            simply optimize away our nice little variable `reloc' and we
-            would result in a not working binary.  So let's swing the
-            magic ward.  */
-         asm ("" : "=r" (reloc) : "0" (reloc));
-
 #ifdef PIC
          if (_dl_profile != NULL)
            {
@@ -122,7 +107,7 @@ dl_open_worker (void *a)
                 start the profiling.  */
              struct link_map *old_profile_map = _dl_profile_map;
 
-             (*reloc) (l, _dl_object_relocation_scope (l), 1, 1);
+             _dl_relocate_object (l, l->l_scope, 1, 1);
 
              if (old_profile_map == NULL && _dl_profile_map != NULL)
                /* We must prepare the profiling.  */
@@ -130,10 +115,8 @@ dl_open_worker (void *a)
            }
          else
 #endif
-           (*reloc) (l, _dl_object_relocation_scope (l),
-                     (mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
-
-         *_dl_global_scope_end = NULL;
+           _dl_relocate_object (l, l->l_scope,
+                                (mode & RTLD_BINDING_MASK) == RTLD_LAZY, 0);
        }
 
       if (l == new)
@@ -146,50 +129,58 @@ dl_open_worker (void *a)
     {
       /* The symbols of the new object and its dependencies are to be
         introduced into the global scope that will be used to resolve
-        references from other dynamically-loaded objects.  */
-
+        references from other dynamically-loaded objects.
+
+        The global scope is the searchlist in the main link map.  We
+        extend this list if necessary.  There is one problem though:
+        since this structure was allocated very early (before the libc
+        is loaded) the memory it uses is allocated by the malloc()-stub
+        in the ld.so.  When we come here these functions are not used
+        anymore.  Instead the malloc() implementation of the libc is
+        used.  But this means the block from the main map cannot be used
+        in an realloc() call.  Therefore we allocate a completely new
+        array the first time we have to add something to the locale scope.  */
       if (_dl_global_scope_alloc == 0)
        {
          /* This is the first dynamic object given global scope.  */
-         _dl_global_scope_alloc = 8;
-         _dl_global_scope = malloc (_dl_global_scope_alloc
-                                    * sizeof (struct link_map *));
-         if (! _dl_global_scope)
+         struct link_map **new_global;
+
+         _dl_global_scope_alloc = _dl_main_searchlist->r_nlist + 8;
+         new_global = (struct link_map **)
+           malloc (_dl_global_scope_alloc * sizeof (struct link_map *));
+         if (new_global == NULL)
            {
-             _dl_global_scope = _dl_default_scope;
+             _dl_global_scope_alloc = 0;
            nomem:
              new->l_global = 0;
              _dl_signal_error (ENOMEM, file, "cannot extend global scope");
            }
-         _dl_global_scope[2] = _dl_default_scope[2];
-         _dl_global_scope[3] = new;
-         _dl_global_scope[4] = NULL;
-         _dl_global_scope[5] = NULL;
-         _dl_global_scope_end = &_dl_global_scope [4];
+
+         /* Copy over the old entries.  */
+         memcpy (new_global, _dl_main_searchlist->r_list,
+                 (_dl_main_searchlist->r_nlist * sizeof (struct link_map *)));
+
+         _dl_main_searchlist->r_list = new_global;
        }
-      else
+      else if (_dl_main_searchlist->r_nlist == _dl_global_scope_alloc)
        {
-         if (_dl_global_scope_end + 3
-             > _dl_global_scope + _dl_global_scope_alloc)
-           {
-             /* Must extend the list.  */
-             struct link_map **new = realloc (_dl_global_scope,
-                                              _dl_global_scope_alloc * 2
-                                              * sizeof (struct link_map *));
-             if (! new)
-               goto nomem;
-             _dl_global_scope = new;
-             _dl_global_scope_end = new + _dl_global_scope_alloc - 2;
-             _dl_global_scope_alloc *= 2;
-           }
+         /* We have to extend the existing array of link maps in the
+            main map.  */
+         struct link_map **new_global;
+
+         new_global = (struct link_map **)
+           malloc ((_dl_global_scope_alloc + 8) * sizeof (struct link_map *));
+         if (new_global == NULL)
+           goto nomem;
 
-         /* Append the new object and re-terminate the list.  */
-         *_dl_global_scope_end++ = new;
-         /* We keep the list double-terminated so the last element
-            can be filled in for symbol lookups.  */
-         _dl_global_scope_end[0] = NULL;
-         _dl_global_scope_end[1] = NULL;
+         _dl_global_scope_alloc += 8;
+         _dl_main_searchlist->r_list = new_global;
        }
+
+      /* Now add the new entry.  */
+      _dl_main_searchlist->r_list[_dl_main_searchlist->r_nlist] = new;
+
+      /* XXX Do we have to add something to r_dupsearchlist???  --drepper */
     }
 
 
@@ -201,10 +192,14 @@ dl_open_worker (void *a)
   _dl_debug_state ();
 
   /* Run the initializer functions of new objects.  */
-  while (init = _dl_init_next (new))
+  while (init = _dl_init_next (&new->l_searchlist))
     (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv,
                                                __environ);
 
+  if (new->l_global)
+    /* Now we can make the new map available in the global scope.  */
+    ++_dl_main_searchlist->r_nlist;
+
   if (_dl_sysdep_start == NULL)
     /* We must be the static _dl_open in libc.a.  A static program that
        has loaded a dynamic object now has competition.  */
@@ -241,9 +236,6 @@ _dl_open (const char *file, int mode)
       /* Some error occured during loading.  */
       char *local_errstring;
 
-      /* Reset the global scope.  */
-      *_dl_global_scope_end = NULL;
-
       /* Remove the object from memory.  It may be in an inconsistent
         state if relocation failed, for example.  */
       if (args.map)
index 55e62b67059727a64ddc738f86ac9847c353f36d..35ef88ab710251e3c86e3f3150d9c4b21dd8c91c 100644 (file)
@@ -27,8 +27,8 @@
 
 
 void
-_dl_relocate_object (struct link_map *l, struct link_map *scope[], int lazy,
-                    int consider_profiling)
+_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[],
+                    int lazy, int consider_profiling)
 {
   if (l->l_relocated)
     return;
index a5e859215491bc44aad076e6743a2412b0a90ee3..38ecf965251807f3caeecb74b50e787a0a694e0a 100644 (file)
 
 #include <unistd.h>
 #include <elf/ldsodefs.h>
-
-
-/* The global scope we will use for symbol lookups.
-   This will be modified by _dl_open if RTLD_GLOBAL is used.  */
-struct link_map **_dl_global_scope = _dl_default_scope;
-struct link_map **_dl_global_scope_end = &_dl_default_scope[3];
-
-
-/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
-   _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
-   references made in the object L's relocations.  */
-inline struct link_map **
-internal_function
-_dl_object_relocation_scope (struct link_map *l)
-{
-  if (l->l_info[DT_SYMBOLIC])
-    {
-      /* This object's global references are to be resolved first
-        in the object itself, and only secondarily in more global
-        scopes.  */
-
-      if (! l->l_searchlist)
-       /* We must construct the searchlist for this object.  */
-       _dl_map_object_deps (l, NULL, 0, 0);
-
-      /* The primary scope is this object itself and its
-        dependencies.
-
-        XXX This is wrong.  Only the object must be searched, not
-        the dependencies. --drepper  */
-      _dl_global_scope[0] = l;
-
-      /* Secondary is the dependency tree that reached L; the object
-        requested directly by the user is at the root of that tree.  */
-      while (l->l_loader)
-       l = l->l_loader;
-      _dl_global_scope[1] = l;
-
-      /* Finally, the global scope follows.  */
-
-      return _dl_global_scope;
-    }
-  else
-    {
-      /* Use first the global scope, and then the scope of the root of the
-        dependency tree that first caused this object to be loaded.  */
-      while (l->l_loader)
-       l = l->l_loader;
-      /* There is no point in searching the same list twice.  This isn't
-        guaranteed to always find all duplicates if new objects are added
-        to the global scope, but is good enough most of the time.  */
-      if (_dl_global_scope[2] != l)
-       *_dl_global_scope_end = l;
-      return &_dl_global_scope[2];
-    }
-}
-\f
 #include "dynamic-link.h"
 
 #if !defined ELF_MACHINE_NO_RELA || ELF_MACHINE_NO_REL
@@ -115,9 +58,6 @@ fixup (
   void *const rel_addr = (void *)(l->l_addr + reloc->r_offset);
   ElfW(Addr) value;
 
-  /* Set up the scope to find symbols referenced by this object.  */
-  struct link_map **scope = _dl_object_relocation_scope (l);
-
   /* Sanity check that we're really looking at a PLT relocation.  */
   assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
 
@@ -134,13 +74,13 @@ fixup (
        if (version->hash != 0)
          {
            value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
-                                               &sym, scope, l->l_name,
+                                               &sym, l->l_scope, l->l_name,
                                                version, ELF_MACHINE_JMP_SLOT);
            break;
          }
       }
     case 0:
-      value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope,
+      value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
                                 l->l_name, ELF_MACHINE_JMP_SLOT);
     }
 
@@ -154,8 +94,6 @@ fixup (
   /* Finally, fix up the plt itself.  */
   elf_machine_fixup_plt (l, reloc, rel_addr, value);
 
-  *_dl_global_scope_end = NULL;
-
   return value;
 }
 
@@ -191,9 +129,6 @@ profile_fixup (
                          reloc_offset);
       const ElfW(Sym) *sym = &symtab[ELFW(R_SYM) (reloc->r_info)];
 
-      /* Set up the scope to find symbols referenced by this object.  */
-      struct link_map **scope = _dl_object_relocation_scope (l);
-
       /* Sanity check that we're really looking at a PLT relocation.  */
       assert (ELFW(R_TYPE)(reloc->r_info) == ELF_MACHINE_JMP_SLOT);
 
@@ -210,14 +145,14 @@ profile_fixup (
            if (version->hash != 0)
              {
                value = _dl_lookup_versioned_symbol(strtab + sym->st_name,
-                                                   &sym, scope, l->l_name,
-                                                   version,
+                                                   &sym, l->l_scope,
+                                                   l->l_name, version,
                                                    ELF_MACHINE_JMP_SLOT);
                break;
              }
          }
        case 0:
-         value = _dl_lookup_symbol (strtab + sym->st_name, &sym, scope,
+         value = _dl_lookup_symbol (strtab + sym->st_name, &sym, l->l_scope,
                                     l->l_name, ELF_MACHINE_JMP_SLOT);
        }
 
@@ -228,8 +163,6 @@ profile_fixup (
       /* And now perhaps the relocation addend.  */
       value = elf_machine_plt_value (l, reloc, value);
 
-      *_dl_global_scope_end = NULL;
-
       /* Store the result for later runs.  */
       *resultp = value;
     }
index 9b949079400e92ab5cd3972376473079ffbf572e..76af1883ac40365ae02d0fd1de12f3ffb1c90958 100644 (file)
@@ -66,6 +66,20 @@ void *__libc_stack_end;
 /* Path where the binary is found.  */
 const char *_dl_origin_path;
 
+/* Initially empty list of loaded objects.  */
+struct link_map *_dl_loaded;
+
+/* Fake scope.  In dynamically linked binaries this is the scope of the
+   main application but here we don't have  something like this.  So
+   create a fake scope containing nothing.  */
+static struct r_scope_elem fake_scope;
+/* Variable which can be used in lookup to process the global scope.  */
+struct r_scope_elem *_dl_global_scope[2] = { &fake_scope, NULL };
+/* This is a global pointer to this structure which is public.  It is
+   used by dlopen/dlclose to add and remove objects from what is regarded
+   to be the global scope.  */
+struct r_scope_elem *_dl_main_searchlist = &fake_scope;
+
 
 static void non_dynamic_init (void) __attribute__ ((unused));
 
index 22adf4351af49a337aff95a8182838de13367bd3..3ae44d6bea49e55996c22317c3fffcdef6bb6db5 100644 (file)
@@ -28,7 +28,7 @@ _dl_symbol_value (struct link_map *map, const char *name)
 {
   ElfW(Addr) loadbase;
   const ElfW(Sym) *ref = NULL;
-  struct link_map *scope[2] = { map, NULL };
-  loadbase = _dl_lookup_symbol (name, &ref, scope, map->l_name, 0);
+  loadbase = _dl_lookup_symbol (name, &ref, map->l_local_scope, map->l_name,
+                               0);
   return loadbase + ref->st_value;
 }
index 413b3bc0df04657c7e16a698b53b8e98323d5374..4ba7f1ab3ad2161ed534a9db2f1ab9188cbb7827 100644 (file)
@@ -61,9 +61,9 @@ find_needed (const char *name, struct link_map *map)
 
   /* The required object is not in the global scope, look to see if it is
      a dependency of the current object.  */
-  for (n = 0; n < map->l_nsearchlist; n++)
-    if (_dl_name_match_p (name, map->l_searchlist[n]))
-      return map->l_searchlist[n];
+  for (n = 0; n < map->l_searchlist.r_nlist; n++)
+    if (_dl_name_match_p (name, map->l_searchlist.r_list[n]))
+      return map->l_searchlist.r_list[n];
 
   /* Should never happen.  */
   return NULL;
index 715e1783cf91ee6847a2e78f9c657fc2ceca2b66..d2a27b85a2dda8f89f0ce3fa6c625488f38afab9 100644 (file)
 #define        _DLFCN_H 1
 
 #include <features.h>
+#define __need_NULL
+#include <stddef.h>
 
 /* Collect various system dependand definitions and declarations.  */
 #include <bits/dlfcn.h>
 
-/* If the first argument of `dlsym' is set to RTLD_NEXT the run-time
-   address of the symbol called NAME in the next shared object is
-   returned.  The "next" relation is defined by the order the shared
-   objects were loaded.  */
+/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT
+   the run-time address of the symbol called NAME in the next shared
+   object is returned.  The "next" relation is defined by the order
+   the shared objects were loaded.  */
 #define RTLD_NEXT      ((void *) -1l)
 
+/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT
+   the run-time address of the symbol called NAME in the global scope
+   is returned.  */
+#define RTLD_DEFAULT   NULL
+
 __BEGIN_DECLS
 
 /* Open the shared object FILE and map it in; return a handle that can be
@@ -57,6 +64,7 @@ extern void *dlvsym __P ((void *__handle, __const char *__name,
    the error string so that a following call returns null.  */
 extern char *dlerror __P ((void));
 
+#ifdef __USE_GNU
 /* Fill in *INFO with the following information about ADDRESS.
    Returns 0 iff no shared object's segments contain that address.  */
 typedef struct
@@ -68,7 +76,6 @@ typedef struct
   } Dl_info;
 extern int dladdr __P ((const void *__address, Dl_info *__info));
 
-#ifdef __USE_GNU
 /* To support profiling of shared objects it is a good idea to call
    the function found using `dlsym' using the following macro since
    these calls do not use the PLT.  But this would mean the dynamic
index 8b20dcf90defb75203192cffe13bb2464428a388..ed786a26250b0dec6065f0763f7248cf2758c1e5 100644 (file)
@@ -44,9 +44,7 @@ dlsym_doit (void *a)
   if (args->handle == NULL)
     /* Search the global scope.  */
     args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
-                                       &(_dl_global_scope
-                                         ?: _dl_default_scope)[2],
-                                       NULL, 0);
+                                       _dl_global_scope, NULL, 0);
   else if (args->handle == RTLD_NEXT)
     {
       struct link_map *l, *match;
@@ -65,19 +63,15 @@ RTLD_NEXT used in code not dynamically loaded"));
       while (l->l_loader)
        l = l->l_loader;
 
-      {
-       struct link_map *mapscope[2] = { l, NULL };
-       args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
-                                                mapscope, NULL, match);
-      }
+      args->loadbase = _dl_lookup_symbol_skip (args->name, &args->ref,
+                                              l->l_local_scope, NULL, match);
     }
   else
     {
       /* Search the scope of the given object.  */
       struct link_map *map = args->handle;
-      struct link_map *mapscope[2] = { map, NULL };
-      args->loadbase = _dl_lookup_symbol (args->name, &args->ref, mapscope,
-                                         map->l_name, 0);
+      args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
+                                         map->l_local_scope, map->l_name, 0);
     }
 }
 
index a1ba9504e8322fe00e577ee7147da97f864d5052..989e87b9fa0d07a6743420bb666a4db9c100d644 100644 (file)
@@ -46,8 +46,7 @@ dlvsym_doit (void *a)
   if (args->handle == NULL)
     /* Search the global scope.  */
     args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref,
-                                                 &(_dl_global_scope
-                                                   ?: _dl_default_scope)[2],
+                                                 _dl_global_scope,
                                                  NULL, &args->version, 0);
   else if (args->handle == RTLD_NEXT)
     {
@@ -67,23 +66,19 @@ RTLD_NEXT used in code not dynamically loaded"));
       while (l->l_loader)
        l = l->l_loader;
 
-      {
-       struct link_map *mapscope[2] = { l, NULL };
-       args->loadbase = _dl_lookup_versioned_symbol_skip (args->name,
-                                                          &args->ref,
-                                                          mapscope,
-                                                          NULL,
-                                                          &args->version,
-                                                          match);
-      }
+      args->loadbase = _dl_lookup_versioned_symbol_skip (args->name,
+                                                        &args->ref,
+                                                        l->l_local_scope,
+                                                        NULL, &args->version,
+                                                        match);
     }
   else
     {
       /* Search the scope of the given object.  */
       struct link_map *map = args->handle;
-      struct link_map *mapscope[2] = { map, NULL };
       args->loadbase = _dl_lookup_versioned_symbol (args->name, &args->ref,
-                                                   mapscope, map->l_name,
+                                                   map->l_local_scope,
+                                                   map->l_name,
                                                    &args->version, 0);
     }
 }
index 51fecc6eb7ae92d717b3915bf0bed750f3cce902..807613e4b479b7ab2087cc3b6ae2a5509694ac40 100644 (file)
@@ -282,7 +282,7 @@ extern void _dl_close (struct link_map *map)
    symbols can be chosen.  */
 extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
                                     const ElfW(Sym) **sym,
-                                    struct link_map *symbol_scope[],
+                                    struct r_scope_elem *symbol_scope[],
                                     const char *reference_name,
                                     int reloc_type)
      internal_function;
@@ -290,7 +290,7 @@ extern ElfW(Addr) _dl_lookup_symbol (const char *undef,
 /* Lookup versioned symbol.  */
 extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
                                               const ElfW(Sym) **sym,
-                                              struct link_map *symbol_scope[],
+                                              struct r_scope_elem *symbol_scope[],
                                               const char *reference_name,
                                               const struct r_found_version *version,
                                               int reloc_type)
@@ -299,7 +299,7 @@ extern ElfW(Addr) _dl_lookup_versioned_symbol (const char *undef,
 /* For handling RTLD_NEXT we must be able to skip shared objects.  */
 extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
                                          const ElfW(Sym) **sym,
-                                         struct link_map *symbol_scope[],
+                                         struct r_scope_elem *symbol_scope[],
                                          const char *reference_name,
                                          struct link_map *skip_this)
      internal_function;
@@ -308,7 +308,7 @@ extern ElfW(Addr) _dl_lookup_symbol_skip (const char *undef,
    skip shared objects.  */
 extern ElfW(Addr) _dl_lookup_versioned_symbol_skip (const char *undef,
                                                    const ElfW(Sym) **sym,
-                                                   struct link_map *symbol_scope[],
+                                                   struct r_scope_elem *symbol_scope[],
                                                    const char *reference_name,
                                                    const struct r_found_version *version,
                                                    struct link_map *skip_this)
@@ -325,46 +325,24 @@ extern ElfW(Addr) _dl_symbol_value (struct link_map *map, const char *name)
 
 /* Structure describing the dynamic linker itself.  */
 extern struct link_map _dl_rtld_map;
-
-/* The list of objects currently loaded is the third element of the
-   `_dl_default_scope' array, and the fourth element is always null.
-   This leaves two slots before it that are used when resolving
-   DT_SYMBOLIC objects' references one after it for normal references
-   (see below).  */
-#define _dl_loaded     (_dl_default_scope[2])
-extern struct link_map *_dl_default_scope[5];
-
-/* Null-terminated list of objects in the dynamic `global scope'.  The
-   list starts at [2]; i.e. &_dl_global_scope[2] is the argument
-   passed to _dl_lookup_symbol to search the global scope.  To search
-   a specific object and its dependencies in preference to the global
-   scope, fill in the [1] slot and pass its address; for two specific
-   object scopes, fill [0] and [1].  The list is double-terminated; to
-   search the global scope and then a specific object and its
-   dependencies, set *_dl_global_scope_end.  This variable initially
-   points to _dl_default_scope, and _dl_loaded is always kept in [2]
-   of this list.  A new list is malloc'd when new objects are loaded
-   with RTLD_GLOBAL.  */
-extern struct link_map **_dl_global_scope, **_dl_global_scope_end;
-extern size_t _dl_global_scope_alloc; /* Number of slots malloc'd.  */
-
-/* Hack _dl_global_scope[0] and [1] as necessary, and return a pointer into
-   _dl_global_scope that should be passed to _dl_lookup_symbol for symbol
-   references made in the object MAP's relocations.  */
-extern struct link_map **_dl_object_relocation_scope (struct link_map *map)
-     internal_function;
-
+/* And a pointer to the map for the main map.  */
+extern struct link_map *_dl_loaded;
+/* Array representing global scope.  */
+extern struct r_scope_elem *_dl_global_scope[2];
+/* Direct pointer to the searchlist of the main object.  */
+extern struct r_scope_elem *_dl_main_searchlist;
 
 /* Allocate a `struct link_map' for a new object being loaded,
-   and enter it into the _dl_loaded list.  */
+   and enter it into the _dl_main_map list.  */
 extern struct link_map *_dl_new_object (char *realname, const char *libname,
-                                       int type) internal_function;
+                                       int type, struct link_map *loader)
+     internal_function;
 
 /* Relocate the given object (if it hasn't already been).
    SCOPE is passed to _dl_lookup_symbol in symbol lookups.
    If LAZY is nonzero, don't relocate its PLT.  */
 extern void _dl_relocate_object (struct link_map *map,
-                                struct link_map *scope[],
+                                struct r_scope_elem *scope[],
                                 int lazy, int consider_profiling);
 
 /* Check the version dependencies of all objects available through
@@ -377,11 +355,11 @@ extern int _dl_check_all_versions (struct link_map *map, int verbose)
 extern int _dl_check_map_versions (struct link_map *map, int verbose)
      internal_function;
 
-/* Return the address of the next initializer function for MAP or one of
+/* Return the address of the next initializer function for SCOPE or one of
    its dependencies that has not yet been run.  When there are no more
    initializers to be run, this returns zero.  The functions are returned
    in the order they should be called.  */
-extern ElfW(Addr) _dl_init_next (struct link_map *map) internal_function;
+extern ElfW(Addr) _dl_init_next (struct r_scope_elem *scope) internal_function;
 
 /* Call the finalizer functions of all shared objects whose
    initializer functions have completed.  */
index e31dd2dd65ebc2bd1f9a4f15cb90cc2fb860c344..ecf0469b7a8ef3f5dd4ea4968879b9cf7693ad4c 100644 (file)
@@ -80,6 +80,24 @@ struct libname_list;
 struct r_found_version;
 struct r_search_path_elem;
 
+/* Forward declaration.  */
+struct link_map;
+
+/* Structure to describe a single list of scope elements.  The lookup
+   functions get passed an array of pointers to such structures.  */
+struct r_scope_elem
+{
+  /* Array of maps for the scope.  */
+  struct link_map **r_list;
+  /* Number of entries in the scope.  */
+  unsigned int r_nlist;
+
+  /* Array of maps which also includes duplicates.  */
+  struct link_map **r_duplist;
+  /* Number of elements in this list.  */
+  unsigned int r_nduplist;
+};
+
 
 /* Structure describing a loaded shared object.  The `l_next' and `l_prev'
    members form a chain of all the shared objects loaded at startup.
@@ -119,15 +137,14 @@ struct link_map
     ElfW(Half) l_phnum;                /* Number of program header entries.  */
 
     /* Array of DT_NEEDED dependencies and their dependencies, in
-       dependency order for symbol lookup.  This is null before the
-       dependencies have been loaded.  */
-    struct link_map **l_searchlist;
-    unsigned int l_nsearchlist;
+       dependency order for symbol lookup (with and without
+       duplicates).  There is no entry before the dependencies have
+       been loaded.  */
+    struct r_scope_elem l_searchlist;
 
-    /* We keep another list in which we keep duplicates.  This is
-       needed in _dl_lookup_symbol_skip to implemented RTLD_NEXT.  */
-    struct link_map **l_dupsearchlist;
-    unsigned int l_ndupsearchlist;
+    /* We need a special searchlist to process objects marked with
+       DT_SYMBOLIC.  */
+    struct r_scope_elem l_symbolic_searchlist;
 
     /* Dependent object that first caused this object to be loaded.  */
     struct link_map *l_loader;
@@ -168,6 +185,14 @@ struct link_map
     /* Start and finish of memory map for this object.  l_map_start
        need not be the same as l_addr.  */
     ElfW(Addr) l_map_start, l_map_end;
+
+    /* This is an array defining the lookup scope for this link map.
+     There are at most three different scope lists.  */
+    struct r_scope_elem *l_scope[4];
+
+    /* A similar array, this time only with the local scope.  This is
+       used occasionally.  */
+    struct r_scope_elem *l_local_scope[2];
   };
 
 #endif /* link.h */
index 66e5d6c59d5e23b1dbadb10e87f849a0dbe64a9f..52295deb2cf210ac3b84401c0d5feed0afe7d62e 100644 (file)
@@ -89,6 +89,14 @@ const char *_dl_inhibit_rpath;               /* RPATH values which should be
                                           ignored.  */
 const char *_dl_origin_path;
 
+/* This is a pointer to the map for the main object and through it to
+   all loaded objects.  */
+struct link_map *_dl_loaded;
+/* Pointer to the l_searchlist element of the link map of the main object.  */
+struct r_scope_elem *_dl_main_searchlist;
+/* Array which is used when looking up in the global scope.  */
+struct r_scope_elem *_dl_global_scope[2];
+
 /* Set nonzero during loading and initialization of executable and
    libraries, cleared before the executable's entry point runs.  This
    must not be initialized to nonzero, because the unused dynamic
@@ -201,7 +209,6 @@ struct map_args
 /* Arguments to version_check_doit.  */
 struct version_check_args
 {
-  struct link_map *main_map;
   int doexit;
 };
 
@@ -210,22 +217,22 @@ relocate_doit (void *a)
 {
   struct relocate_args *args = (struct relocate_args *) a;
 
-  _dl_relocate_object (args->l, _dl_object_relocation_scope (args->l),
+  _dl_relocate_object (args->l, args->l->l_scope,
                       args->lazy, 0);
 }
 
 static void
 map_doit (void *a)
 {
-  struct map_args *args = (struct map_args *)a;
+  struct map_args *args = (struct map_args *) a;
   args->main_map = _dl_map_object (NULL, args->str, 0, lt_library, 0);
 }
 
 static void
 version_check_doit (void *a)
 {
-  struct version_check_args *args = (struct version_check_args *)a;
-  if (_dl_check_all_versions (args->main_map, 1) && args->doexit)
+  struct version_check_args *args = (struct version_check_args *) a;
+  if (_dl_check_all_versions (_dl_loaded, 1) && args->doexit)
     /* We cannot start the application.  Abort now.  */
     _exit (1);
 }
@@ -234,11 +241,11 @@ version_check_doit (void *a)
 static inline struct link_map *
 find_needed (const char *name)
 {
-  unsigned int n;
+  unsigned int n = _dl_loaded->l_searchlist.r_nlist;
 
-  for (n = 0; n < _dl_loaded->l_nsearchlist; ++n)
-    if (_dl_name_match_p (name, _dl_loaded->l_searchlist[n]))
-      return _dl_loaded->l_searchlist[n];
+  while (n-- > 0)
+    if (_dl_name_match_p (name, _dl_loaded->l_searchlist.r_list[n]))
+      return _dl_loaded->l_searchlist.r_list[n];
 
   /* Should never happen.  */
   return NULL;
@@ -289,7 +296,6 @@ dl_main (const ElfW(Phdr) *phdr,
         ElfW(Addr) *user_entry)
 {
   const ElfW(Phdr) *ph;
-  struct link_map *main_map;
   int lazy;
   enum mode mode;
   struct link_map **preloads;
@@ -405,7 +411,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 
          args.str = _dl_argv[0];
          (void) _dl_catch_error (&err_str, map_doit, &args);
-         main_map = args.main_map;
+         _dl_loaded = args.main_map;
          if (err_str != NULL)
            {
              free (err_str);
@@ -413,37 +419,37 @@ of this helper program; chances are you did not intend to run this program.\n\
            }
        }
       else
-       main_map = _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
+       _dl_loaded = _dl_map_object (NULL, _dl_argv[0], 0, lt_library, 0);
 
-      phdr = main_map->l_phdr;
-      phent = main_map->l_phnum;
+      phdr = _dl_loaded->l_phdr;
+      phent = _dl_loaded->l_phnum;
       /* We overwrite here a pointer to a malloc()ed string.  But since
         the malloc() implementation used at this point is the dummy
         implementations which has no real free() function it does not
         makes sense to free the old string first.  */
-      main_map->l_name = (char *) "";
-      *user_entry = main_map->l_entry;
+      _dl_loaded->l_name = (char *) "";
+      *user_entry = _dl_loaded->l_entry;
     }
   else
     {
       /* Create a link_map for the executable itself.
         This will be what dlopen on "" returns.  */
-      main_map = _dl_new_object ((char *) "", "", lt_executable);
-      if (main_map == NULL)
+      _dl_loaded = _dl_new_object ((char *) "", "", lt_executable, NULL);
+      if (_dl_loaded == NULL)
        _dl_sysdep_fatal ("cannot allocate memory for link map\n", NULL);
-      main_map->l_phdr = phdr;
-      main_map->l_phnum = phent;
-      main_map->l_entry = *user_entry;
-      main_map->l_opencount = 1;
+      _dl_loaded->l_phdr = phdr;
+      _dl_loaded->l_phnum = phent;
+      _dl_loaded->l_entry = *user_entry;
+      _dl_loaded->l_opencount = 1;
 
       /* We delay initializing the path structure until we got the dynamic
         information for the program.  */
     }
 
   /* It is not safe to load stuff after the main program.  */
-  main_map->l_map_end = ~0;
+  _dl_loaded->l_map_end = ~0;
   /* Perhaps the executable has no PT_LOAD header entries at all.  */
-  main_map->l_map_start = ~0;
+  _dl_loaded->l_map_start = ~0;
 
   /* Scan the program header table for the dynamic section.  */
   for (ph = phdr; ph < &phdr[phent]; ++ph)
@@ -451,12 +457,12 @@ of this helper program; chances are you did not intend to run this program.\n\
       {
       case PT_PHDR:
        /* Find out the load address.  */
-       main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
+       _dl_loaded->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
        break;
       case PT_DYNAMIC:
        /* This tells us where to find the dynamic section,
           which tells us everything we need to do.  */
-       main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
+       _dl_loaded->l_ld = (void *) _dl_loaded->l_addr + ph->p_vaddr;
        break;
       case PT_INTERP:
        /* This "interpreter segment" was used by the program loader to
@@ -465,7 +471,8 @@ of this helper program; chances are you did not intend to run this program.\n\
           dlopen call or DT_NEEDED entry, for something that wants to link
           against the dynamic linker as a shared library, will know that
           the shared object is already loaded.  */
-       _dl_rtld_libname.name = (const char *) main_map->l_addr + ph->p_vaddr;
+       _dl_rtld_libname.name = ((const char *) _dl_loaded->l_addr
+                                + ph->p_vaddr);
        _dl_rtld_libname.next = NULL;
        _dl_rtld_map.l_libname = &_dl_rtld_libname;
 
@@ -491,9 +498,9 @@ of this helper program; chances are you did not intend to run this program.\n\
        /* Remember where the main program starts in memory.  */
        {
          ElfW(Addr) mapstart;
-         mapstart = main_map->l_addr + (ph->p_vaddr & ~(ph->p_align - 1));
-         if (main_map->l_map_start > mapstart)
-           main_map->l_map_start = mapstart;
+         mapstart = _dl_loaded->l_addr + (ph->p_vaddr & ~(ph->p_align - 1));
+         if (_dl_loaded->l_map_start > mapstart)
+           _dl_loaded->l_map_start = mapstart;
        }
        break;
       }
@@ -509,10 +516,10 @@ of this helper program; chances are you did not intend to run this program.\n\
     assert (_dl_rtld_map.l_libname); /* How else did we get here?  */
 
   /* Extract the contents of the dynamic section for easy access.  */
-  elf_get_dynamic_info (main_map->l_ld, main_map->l_info);
-  if (main_map->l_info[DT_HASH])
+  elf_get_dynamic_info (_dl_loaded->l_ld, _dl_loaded->l_info);
+  if (_dl_loaded->l_info[DT_HASH])
     /* Set up our cache of pointers into the hash table.  */
-    _dl_setup_hash (main_map);
+    _dl_setup_hash (_dl_loaded);
 
   if (mode == verify)
     {
@@ -520,7 +527,7 @@ of this helper program; chances are you did not intend to run this program.\n\
         executable using us as the program interpreter.  Exit with an
         error if we were not able to load the binary or no interpreter
         is specified (i.e., this is no dynamically linked binary.  */
-      if (main_map->l_ld == NULL)
+      if (_dl_loaded->l_ld == NULL)
        _exit (1);
 
       /* We allow here some platform specific code.  */
@@ -537,14 +544,14 @@ of this helper program; chances are you did not intend to run this program.\n\
 
   /* Put the link_map for ourselves on the chain so it can be found by
      name.  Note that at this point the global chain of link maps contains
-     exactly one element, which is pointed to by main_map.  */
+     exactly one element, which is pointed to by _dl_loaded.  */
   if (! _dl_rtld_map.l_name)
     /* If not invoked directly, the dynamic linker shared object file was
        found by the PT_INTERP name.  */
     _dl_rtld_map.l_name = (char *) _dl_rtld_map.l_libname->name;
   _dl_rtld_map.l_type = lt_library;
-  main_map->l_next = &_dl_rtld_map;
-  _dl_rtld_map.l_prev = main_map;
+  _dl_loaded->l_next = &_dl_rtld_map;
+  _dl_rtld_map.l_prev = _dl_loaded;
 
   /* We have two ways to specify objects to preload: via environment
      variable and via the file /etc/ld.so.preload.  The later can also
@@ -565,7 +572,7 @@ of this helper program; chances are you did not intend to run this program.\n\
        if (p[0] != '\0'
            && (! __libc_enable_secure || strchr (p, '/') == NULL))
          {
-           struct link_map *new_map = _dl_map_object (main_map, p, 1,
+           struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
                                                       lt_library, 0);
            if (new_map->l_opencount == 1)
              /* It is no duplicate.  */
@@ -627,7 +634,7 @@ of this helper program; chances are you did not intend to run this program.\n\
          while ((p = strsep (&runp, ": \t\n")) != NULL)
            if (p[0] != '\0')
              {
-               struct link_map *new_map = _dl_map_object (main_map, p, 1,
+               struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
                                                           lt_library, 0);
                if (new_map->l_opencount == 1)
                  /* It is no duplicate.  */
@@ -638,7 +645,7 @@ of this helper program; chances are you did not intend to run this program.\n\
       if (problem != NULL)
        {
          char *p = strndupa (problem, file_size - (problem - file));
-         struct link_map *new_map = _dl_map_object (main_map, p, 1,
+         struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1,
                                                     lt_library, 0);
          if (new_map->l_opencount == 1)
            /* It is no duplicate.  */
@@ -667,7 +674,7 @@ of this helper program; chances are you did not intend to run this program.\n\
   /* Load all the libraries specified by DT_NEEDED entries.  If LD_PRELOAD
      specified some libraries to load, these are inserted before the actual
      dependencies in the executable's searchlist for symbol resolution.  */
-  _dl_map_object_deps (main_map, preloads, npreloads, mode == trace);
+  _dl_map_object_deps (_dl_loaded, preloads, npreloads, mode == trace);
 
 #ifndef MAP_ANON
   /* We are done mapping things, so close the zero-fill descriptor.  */
@@ -687,11 +694,12 @@ of this helper program; chances are you did not intend to run this program.\n\
         chain in symbol search order because gdb uses the chain's order as
         its symbol search order.  */
       i = 1;
-      while (main_map->l_searchlist[i] != &_dl_rtld_map)
+      while (_dl_loaded->l_searchlist.r_list[i] != &_dl_rtld_map)
        ++i;
-      _dl_rtld_map.l_prev = main_map->l_searchlist[i - 1];
-      _dl_rtld_map.l_next = (i + 1 < main_map->l_nsearchlist ?
-                            main_map->l_searchlist[i + 1] : NULL);
+      _dl_rtld_map.l_prev = _dl_loaded->l_searchlist.r_list[i - 1];
+      _dl_rtld_map.l_next = (i + 1 < _dl_loaded->l_searchlist.r_nlist
+                            ? _dl_loaded->l_searchlist.r_list[i + 1]
+                            : NULL);
       assert (_dl_rtld_map.l_prev->l_next == _dl_rtld_map.l_next);
       _dl_rtld_map.l_prev->l_next = &_dl_rtld_map;
       if (_dl_rtld_map.l_next)
@@ -706,7 +714,6 @@ of this helper program; chances are you did not intend to run this program.\n\
   {
     struct version_check_args args;
     args.doexit = mode == normal;
-    args.main_map = main_map;
     _dl_receive_error (print_missing_version, version_check_doit, &args);
   }
 
@@ -745,7 +752,7 @@ of this helper program; chances are you did not intend to run this program.\n\
          {
            const ElfW(Sym) *ref = NULL;
            ElfW(Addr) loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
-                                                    &_dl_default_scope[2],
+                                                    _dl_loaded->l_scope,
                                                     "argument",
                                                     ELF_MACHINE_JMP_SLOT);
            char buf[20], *bp;
@@ -780,7 +787,6 @@ of this helper program; chances are you did not intend to run this program.\n\
                      args.l = l;
                      _dl_receive_error (print_unresolved, relocate_doit,
                                         &args);
-                     *_dl_global_scope_end = NULL;
                    }
                  l = l->l_prev;
                } while (l);
@@ -890,11 +896,8 @@ of this helper program; chances are you did not intend to run this program.\n\
     do
       {
        if (l != &_dl_rtld_map)
-         {
-           _dl_relocate_object (l, _dl_object_relocation_scope (l), lazy,
-                                consider_profiling);
-           *_dl_global_scope_end = NULL;
-         }
+         _dl_relocate_object (l, l->l_scope, lazy, consider_profiling);
+
        l = l->l_prev;
       } while (l);
 
@@ -908,9 +911,13 @@ of this helper program; chances are you did not intend to run this program.\n\
     if (_dl_rtld_map.l_opencount > 0)
       /* There was an explicit ref to the dynamic linker as a shared lib.
         Re-relocate ourselves with user-controlled symbol definitions.  */
-      _dl_relocate_object (&_dl_rtld_map, &_dl_default_scope[2], 0, 0);
+      _dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0);
   }
 
+  /* Now set up the variable which helps the assembler startup code.  */
+  _dl_main_searchlist = &_dl_loaded->l_searchlist;
+  _dl_global_scope[0] = &_dl_loaded->l_searchlist;
+
   {
     /* Initialize _r_debug.  */
     struct r_debug *r = _dl_debug_initialize (_dl_rtld_map.l_addr);
index e0471b0de6adbf1a8fc81d0b39ff41d6cb89db95..1c04dee16955e4d0c7e5f012cb05eef7c036d464 100644 (file)
@@ -100,10 +100,10 @@ static void
 get_sym (void *a)
 {
   struct get_sym_args *args = (struct get_sym_args *) a;
-  struct link_map *scope[2] = { args->map, NULL };
   args->ref = NULL;
   args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
-                                     scope, args->map->l_name, 0);
+                                     args->map->l_local_scope,
+                                     args->map->l_name, 0);
 }
 
 
index 45d06abc6c5d0acb4cb19f101ec55bcc82e9f72b..d358962f713383d1dd18e353242bd2c0d86c5d3a 100644 (file)
@@ -1,3 +1,8 @@
+1998-09-06 09:08  Ulrich Drepper  <drepper@cygnus.com>
+
+       * sysdeps/pthread/bits/libc-lock.h (enum __libc_tsd_key_t): Add
+       _LIBC_TSD_KEY_DL_ERROR.
+
 1998-08-31  Ulrich Drepper  <drepper@cygnus.com>
 
        * sysdeps/i386/i686/pt-machine.h (testandset): Add memory clobber.
index b84107cfa4222dea7a4cb5d3a5674fd0ef1e3136..820d65aca8ad9cd89aa2ea375c743e3e8ae8aa3e 100644 (file)
@@ -152,7 +152,9 @@ typedef pthread_key_t __libc_key_t;
 #ifdef _LIBC
 
 /* Fast thread-specific data internal to libc.  */
-enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0, _LIBC_TSD_KEY_N };
+enum __libc_tsd_key_t { _LIBC_TSD_KEY_MALLOC = 0,
+                       _LIBC_TSD_KEY_DL_ERROR,
+                       _LIBC_TSD_KEY_N };
 
 extern void *__libc_internal_tsd_get __P ((enum __libc_tsd_key_t));
 extern int __libc_internal_tsd_set __P ((enum __libc_tsd_key_t,
index 644343a030ab2bae2935846ad6018ef2d18a8f1b..e4f475868eb727cc1211d87e6d8ed8aaca3cd76f 100644 (file)
@@ -292,10 +292,10 @@ static void
 get_sym (void *a)
 {
   struct get_sym_args *args = (struct get_sym_args *) a;
-  struct link_map *scope[2] = { args->map, NULL };
   args->ref = NULL;
   args->loadbase = _dl_lookup_symbol (args->name, &args->ref,
-                                     scope, args->map->l_name, 0);
+                                     args->map->l_local_scope,
+                                     args->map->l_name, 0);
 }
 #endif
 
index a6d8974ab33a4676c17224d1152e9a477a2200d0..87d924821a567781023ef6d6cf2fb0f4d70d74c8 100644 (file)
@@ -227,9 +227,10 @@ _dl_start_user:\n\
        leal (%esp,%eax,4), %esp\n\
        # Push back the modified argument count.\n\
        pushl %ecx\n\
-       # Push _dl_default_scope[2] as argument in _dl_init_next call below.\n\
-       movl _dl_default_scope@GOT(%ebx), %eax\n\
-       movl 8(%eax), %esi\n\
+       # Push the searchlist of the main object as argument in\n\
+       # _dl_init_next call below.\n\
+       movl _dl_main_searchlist@GOT(%ebx), %eax\n\
+       movl (%eax), %esi\n\
 0:     movl %esi,%eax\n\
        # Call _dl_init_next to return the address of an initializer\n\
        # function to run.\n\
index b9ef9af8b69d2a51020d1e6d4af2b436e6802e9c..4ae2e87a7b04b3bfb0e23882b146a9092b8c72e4 100644 (file)
       /* We have to find out whether the binary is linked against            \
         libc 5 or glibc.  We do this by looking at all the DT_NEEDED         \
         entries.  If one is libc.so.5 this is a libc 5 linked binary.  */    \
-      if (main_map->l_info[DT_NEEDED])                                       \
+      if (_dl_loaded->l_info[DT_NEEDED])                                     \
        {                                                                     \
          /* We have dependencies.  */                                        \
-         const char *strtab = ((void *) main_map->l_addr                     \
-                               + main_map->l_info[DT_STRTAB]->d_un.d_ptr);   \
          const ElfW(Dyn) *d;                                                 \
+         const char *strtab;                                                 \
                                                                              \
-         for (d = main_map->l_ld; d->d_tag != DT_NULL; ++d)                  \
+         strtab = ((void *) _dl_loaded->l_addr                               \
+                   + _dl_loaded->l_info[DT_STRTAB]->d_un.d_ptr);             \
+                                                                             \
+         for (d = _dl_loaded->l_ld; d->d_tag != DT_NULL; ++d)                \
            if (d->d_tag == DT_NEEDED                                         \
                && strcmp (strtab + d->d_un.d_val, "libc.so.5") == 0)         \
              break;                                                          \