Tue Jun 4 02:25:44 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
authorRoland McGrath <roland@gnu.org>
Tue, 4 Jun 1996 05:18:15 +0000 (05:18 +0000)
committerRoland McGrath <roland@gnu.org>
Tue, 4 Jun 1996 05:18:15 +0000 (05:18 +0000)
* elf/linux-compat.c (_init): Pass reloc_addr arg to _dl_lookup_symbol.

* elf/dl-lookup.c (_dl_lookup_symbol): Use l_searchlist.

* elf/dl-deps.c: New file.
* elf/Makefile (rtld-routines): Add dl-deps.
* elf/link.h: Declare _dl_map_object_deps, _dl_open.
* elf/rtld.c (dl_main): Use _dl_map_object_deps.
* elf/dlopen.c: Use _dl_open.

* elf/rtld.c (dl_main): Remove BEFORE_RTLD variable and list
frobnication based on its value.  Detach RTLD_MAP from the chain if
its l_opencount is zero after loading deps.

* elf/dlfcn.h (RTLD_BINDING_MASK): New macro.

* elf/link.h (struct link_map): Replace l_deps_loaded flag member with
`struct link_map **l_searchlist' and `unsigned int l_nsearchlist'.
* elf/dl-lookup.c (_dl_lookup_symbol): Make SYMBOL_SCOPE arg an array
of two link_map ptrs.  Search the maps in the l_searchlist of each
elt that is not null.
* elf/dl-reloc.c (_dl_relocate_object): Pass proper SCOPE array.
* elf/dl-runtime.c: Likewise.
* elf/dlsym.c: Likewise.
* elf/rtld.c (dl_main): Likewise.

* elf/dl-minimal.c (realloc): Support realloc of the block most
recently returned by the minimal malloc.

* intl/localealias.c, intl/dcgettext.c [_LIBC]: Define HAVE_ALLOCA.

13 files changed:
ChangeLog
elf/Makefile
elf/dl-deps.c [new file with mode: 0644]
elf/dl-lookup.c
elf/dl-minimal.c
elf/dl-reloc.c
elf/dl-runtime.c
elf/dlfcn.h
elf/dlopen.c
elf/dlsym.c
elf/link.h
elf/linux-compat.c
elf/rtld.c

index eaf157e..62ae972 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,9 +1,40 @@
+Tue Jun  4 02:25:44 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
+
+       * elf/linux-compat.c (_init): Pass reloc_addr arg to _dl_lookup_symbol.
+
+       * elf/dl-lookup.c (_dl_lookup_symbol): Use l_searchlist.
+
+       * elf/dl-deps.c: New file.
+       * elf/Makefile (rtld-routines): Add dl-deps.
+       * elf/link.h: Declare _dl_map_object_deps, _dl_open.
+       * elf/rtld.c (dl_main): Use _dl_map_object_deps.
+       * elf/dlopen.c: Use _dl_open.
+
+       * elf/rtld.c (dl_main): Remove BEFORE_RTLD variable and list
+       frobnication based on its value.  Detach RTLD_MAP from the chain if
+       its l_opencount is zero after loading deps.
+
+       * elf/dlfcn.h (RTLD_BINDING_MASK): New macro.
+
+       * elf/link.h (struct link_map): Replace l_deps_loaded flag member with
+       `struct link_map **l_searchlist' and `unsigned int l_nsearchlist'.
+       * elf/dl-lookup.c (_dl_lookup_symbol): Make SYMBOL_SCOPE arg an array
+       of two link_map ptrs.  Search the maps in the l_searchlist of each
+       elt that is not null.
+       * elf/dl-reloc.c (_dl_relocate_object): Pass proper SCOPE array.
+       * elf/dl-runtime.c: Likewise.
+       * elf/dlsym.c: Likewise.
+       * elf/rtld.c (dl_main): Likewise.
+
+       * elf/dl-minimal.c (realloc): Support realloc of the block most
+       recently returned by the minimal malloc.
+
 Tue Jun  4 00:16:03 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
 
        * sysdeps/gnu/errlist.awk: Produce N_("..."), not _N("...").
 
        * intl: Updated from gettext-0.10.13.
-       * intl/localealias.c intl/dcgettext.c [_LIBC]: Define HAVE_ALLOCA.
+       * intl/localealias.c, intl/dcgettext.c [_LIBC]: Define HAVE_ALLOCA.
 
        * signal/siggetmask.c: New file.  Wrapper around sigblock with
        link_warning about obsolescence.
@@ -38,18 +69,6 @@ Mon Jun  3 15:58:22 1996  Michael I. Bushnell, p/BSG  <mib@gnu.ai.mit.edu>
        for a HANDLE signal to IGNORE because the signal is blocked, clean
        up any pending suspension left over from a call to resume.
 
-Mon Jun  3 01:29:53 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
-
-       * elf/link.h (struct link_map): Replace l_deps_loaded flag member with
-       `struct link_map **l_searchlist'.
-       * elf/dl-lookup.c (_dl_lookup_symbol): Make SYMBOL_SCOPE arg an array
-       of two link_map ptrs.  Search the maps in the l_searchlist of each
-       of the two elts that is non-null.
-       * elf/dl-reloc.c (_dl_relocate_object): Pass proper SCOPE array.
-       * elf/dl-runtime.c: Likewise.
-       * elf/dlsym.c: Likewise.
-       * elf/rtld.c (dl_main): Likewise.
-
 Mon Jun  3 00:30:35 1996  Roland McGrath  <roland@delasyd.gnu.ai.mit.edu>
 
        * elf/dl-lookup.c (_dl_lookup_symbol): Take new arg RELOC_ADDR and
index 6124fa9..8f34a9c 100644 (file)
@@ -29,7 +29,7 @@ libdl-routines        := dlopen dlclose dlsym dlerror
 libdl-inhibit-o        = $(filter-out .so,$(object-suffixes)) # Build only shared.
 
 rtld-routines  := rtld $(addprefix dl-,minimal load lookup object reloc \
-                                       runtime sysdep error init fini)
+                                       deps runtime sysdep error init fini)
 distribute     = $(rtld-routines:=.c) dynamic-link.h do-rel.h \
                  soinit.c sofini.c ldd.sh.in linux-compat.c
 
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
new file mode 100644 (file)
index 0000000..f87475a
--- /dev/null
@@ -0,0 +1,93 @@
+/* Load the dependencies of a mapped object.
+Copyright (C) 1996 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.  */
+
+#include <link.h>
+#include <errno.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+
+void
+_dl_map_object_deps (struct link_map *map)
+{
+  unsigned int nlist = 1;
+  struct link_map **list = malloc (sizeof *list);
+  unsigned int done;
+
+  /* Start the search list with one element: MAP itself.  */
+  list[0] = map;
+
+  /* Process each element of the search list, loading each of its immediate
+     dependencies and appending them to the list as we step through it.
+     This produces a flat, ordered list that represents a breadth-first
+     search of the dependency tree.  */
+  for (done = 0; done < nlist; ++done)
+    {
+      struct link_map *l = list[done];
+      if (l->l_info[DT_NEEDED])
+       {
+         const char *strtab
+           = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
+         const Elf32_Dyn *d;
+         for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
+           if (d->d_tag == DT_NEEDED)
+             {
+               /* Extend the list and put this object on the end.  */
+               struct link_map **n
+                 = realloc (list, (nlist + 1) * sizeof *list);
+               if (n)
+                 list = n;
+               else
+                 {
+                   free (list);
+                   _dl_signal_error (ENOMEM, map->l_name,
+                                     "finding dependencies");
+                 }
+               list[nlist++] = _dl_map_object (l, strtab + d->d_un.d_val);
+             }
+       }
+    }
+
+  map->l_searchlist = list;
+  map->l_nsearchlist = nlist;
+}
+
+
+struct link_map *
+_dl_open (struct link_map *parent, const char *file, int mode)
+{
+  struct link_map *new, *l;
+  Elf32_Addr init;
+
+  /* Load the named object.  */
+  new = _dl_map_object (parent, file);
+
+  /* Load that object's dependencies.  */
+  _dl_map_object_deps (new);
+
+  /* Relocate the objects loaded.  */
+  for (l = new; l; l = l->l_next)
+    if (! l->l_relocated)
+      _dl_relocate_object (l, (mode & RTLD_BINDING_MASK) == RTLD_LAZY);
+
+  /* Run the initializer functions of new objects.  */
+  while (init = _dl_init_next ())
+    (*(void (*) (void)) init) ();
+
+  return new;
+}
index b72a6a2..26357c2 100644 (file)
@@ -29,77 +29,84 @@ Cambridge, MA 02139, USA.  */
 
 Elf32_Addr
 _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
-                  struct link_map *symbol_scope,
+                  struct link_map *symbol_scope[2],
                   const char *reference_name,
                   Elf32_Addr reloc_addr,
                   int noplt)
 {
   unsigned long int hash = elf_hash (undef_name);
-  struct link_map *map;
   struct
     {
       Elf32_Addr a;
       const Elf32_Sym *s;
     } weak_value = { 0, NULL };
+  size_t i;
+  struct link_map **scope, *map;
 
   /* Search the relevant loaded objects for a definition.  */
-  for (map = symbol_scope; map; map = map->l_next)
-    {
-      const Elf32_Sym *symtab;
-      const char *strtab;
-      Elf32_Word symidx;
-
-      symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
-      strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
-
-      /* Search the appropriate hash bucket in this object's symbol table
-        for a definition for the same symbol name.  */
-      for (symidx = map->l_buckets[hash % map->l_nbuckets];
-          symidx != STN_UNDEF;
-          symidx = map->l_chain[symidx])
+  for (scope = symbol_scope; scope < &symbol_scope[2]; ++scope)
+    if (*scope)
+      for (i = 0; i < (*scope)->l_nsearchlist; ++i)
        {
-         const Elf32_Sym *sym = &symtab[symidx];
+         const Elf32_Sym *symtab;
+         const char *strtab;
+         Elf32_Word symidx;
+
+         map = (*scope)->l_searchlist[i];
 
-         if (sym->st_value == 0 || /* No value.  */
-             reloc_addr == map->l_addr + sym->st_value || /* Self ref.  */
-             (noplt && sym->st_shndx == SHN_UNDEF)) /* Unwanted PLT entry.  */
-           continue;
+         symtab = ((void *) map->l_addr + map->l_info[DT_SYMTAB]->d_un.d_ptr);
+         strtab = ((void *) map->l_addr + map->l_info[DT_STRTAB]->d_un.d_ptr);
 
-         switch (ELF32_ST_TYPE (sym->st_info))
+         /* Search the appropriate hash bucket in this object's symbol table
+            for a definition for the same symbol name.  */
+         for (symidx = map->l_buckets[hash % map->l_nbuckets];
+              symidx != STN_UNDEF;
+              symidx = map->l_chain[symidx])
            {
-           case STT_NOTYPE:
-           case STT_FUNC:
-           case STT_OBJECT:
-             break;
-           default:
-             /* Not a code/data definition.  */
-             continue;
-           }
+             const Elf32_Sym *sym = &symtab[symidx];
 
-         if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
-           /* Not the symbol we are looking for.  */
-           continue;
+             if (sym->st_value == 0 || /* No value.  */
+                 /* Cannot resolve to the location being filled in.  */
+                 reloc_addr == map->l_addr + sym->st_value ||
+                 (noplt && sym->st_shndx == SHN_UNDEF)) /* Reject PLT.  */
+               continue;
 
-         switch (ELF32_ST_BIND (sym->st_info))
-           {
-           case STB_GLOBAL:
-             /* Global definition.  Just what we need.  */
-             *ref = sym;
-             return map->l_addr;
-           case STB_WEAK:
-             /* Weak definition.  Use this value if we don't find another.  */
-             if (! weak_value.s)
+             switch (ELF32_ST_TYPE (sym->st_info))
                {
-                 weak_value.s = sym;
-                 weak_value.a = map->l_addr;
+               case STT_NOTYPE:
+               case STT_FUNC:
+               case STT_OBJECT:
+                 break;
+               default:
+                 /* Not a code/data definition.  */
+                 continue;
+               }
+
+             if (sym != *ref && strcmp (strtab + sym->st_name, undef_name))
+               /* Not the symbol we are looking for.  */
+               continue;
+
+             switch (ELF32_ST_BIND (sym->st_info))
+               {
+               case STB_GLOBAL:
+                 /* Global definition.  Just what we need.  */
+                 *ref = sym;
+                 return map->l_addr;
+               case STB_WEAK:
+                 /* Weak definition.  Use this value if we don't find
+                    another.  */
+                 if (! weak_value.s)
+                   {
+                     weak_value.s = sym;
+                     weak_value.a = map->l_addr;
+                   }
+                 break;
+               default:
+                 /* Local symbols are ignored.  */
+                 break;
                }
-             break;
-           default:
-             /* Local symbols are ignored.  */
-             break;
            }
        }
-    }
 
   if (weak_value.s == NULL && ELF32_ST_BIND ((*ref)->st_info) != STB_WEAK)
     {
index 9e0a770..c61b515 100644 (file)
@@ -1,5 +1,5 @@
 /* Minimal replacements for basic facilities used in the dynamic linker.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 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
@@ -84,10 +84,17 @@ free (void *ptr)
 }
 weak_symbol (free)
 
-/* This is never called.  */
+/* This is only called with the most recent block returned by malloc.  */
 void *
 realloc (void *ptr, size_t n)
-{ ptr += n; abort (); }
+{
+  void *new;
+  assert (ptr == alloc_last_block);
+  alloc_ptr = alloc_last_block;
+  new = malloc (n);
+  assert (new == ptr);
+  return new;
+}
 weak_symbol (realloc)
 \f
 /* Avoid signal frobnication in setjmp/longjmp.  Keeps things smaller.  */
index 424d303..bfa0174 100644 (file)
@@ -54,12 +54,11 @@ _dl_relocate_object (struct link_map *l, int lazy)
     }
 
   {
-    struct link_map *real_next, *scope;
+    struct link_map *scope[2];
 
     const char *strtab
       = ((void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr);
 
-
     Elf32_Addr resolve (const Elf32_Sym **ref,
                        Elf32_Addr reloc_addr, int noplt)
       {
@@ -67,16 +66,16 @@ _dl_relocate_object (struct link_map *l, int lazy)
                                  l->l_name, reloc_addr, noplt);
       }
 
-    real_next = l->l_next;
     if (l->l_info[DT_SYMBOLIC])
       {
-       if (l->l_prev)
-         l->l_prev->l_next = real_next;
-       l->l_next = _dl_loaded;
-       scope = l;
+       scope[0] = l;
+       scope[1] = _dl_loaded;
       }
     else
-      scope = _dl_loaded;
+      {
+       scope[0] = _dl_loaded;
+       scope[1] = l;
+      }
 
     if (l->l_type == lt_interpreter)
       /* We cannot be lazy when relocating the dynamic linker itself.  It
@@ -87,11 +86,6 @@ _dl_relocate_object (struct link_map *l, int lazy)
       lazy = 0;
 
     ELF_DYNAMIC_RELOCATE (l, lazy, resolve);
-
-    /* Restore list frobnication done above for DT_SYMBOLIC.  */
-    l->l_next = real_next;
-    if (l->l_prev)
-      l->l_prev->l_next = l;
   }
 
   /* Set up the PLT so its unrelocated entries will
index 0beba76..dce34f8 100644 (file)
@@ -70,8 +70,9 @@ fixup (
   Elf32_Addr resolve (const Elf32_Sym **ref,
                      Elf32_Addr reloc_addr, int noplt)
     {
-      return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, _dl_loaded,
-                               l->l_name, reloc_addr, noplt);
+      struct link_map *scope[2] = { _dl_loaded, NULL };
+      return _dl_lookup_symbol (strtab + (*ref)->st_name, ref,
+                               scope, l->l_name, reloc_addr, noplt);
     }
 
   /* Perform the specified relocation.  */
index a405baa..8d19b8b 100644 (file)
@@ -24,6 +24,7 @@ Cambridge, MA 02139, USA.  */
 /* The MODE argument to `dlopen' contains one of the following: */
 #define RTLD_LAZY      0x001   /* Lazy function call binding.  */
 #define RTLD_NOW       0x002   /* Immediate function call binding.  */
+#define        RTLD_BINDING_MASK 0x3   /* Mask of binding time value.  */
 
 /* If the following bit is set in the MODE argument to `dlopen',
    the symbols of the loaded object and its dependencies are made
index 26ed35a..74ab8bb 100644 (file)
@@ -24,38 +24,11 @@ Cambridge, MA 02139, USA.  */
 void *
 dlopen (const char *file, int mode)
 {
-  struct link_map *new, *l;
+  struct link_map *new;
 
   void doit (void)
     {
-      Elf32_Addr init;
-
-      new = _dl_map_object (_dl_loaded, file);
-
-      /* Map in any dependencies.  */
-      for (l = new; l; l = l->l_next)
-       if (! l->l_deps_loaded)
-         {
-           if (l->l_info[DT_NEEDED])
-             {
-               const char *strtab
-                 = (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
-               const Elf32_Dyn *d;
-               for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
-                 if (d->d_tag == DT_NEEDED)
-                   _dl_map_object (l, strtab + d->d_un.d_val);
-             }
-           l->l_deps_loaded = 1;
-         }
-
-      /* Relocate the objects loaded.  */
-      for (l = new; l; l = l->l_next)
-       if (! l->l_relocated)
-         _dl_relocate_object (l, mode == RTLD_LAZY);
-
-      /* Run the initializer functions of new objects.  */
-      while (init = _dl_init_next ())
-       (*(void (*) (void)) init) ();
+      new = _dl_open (_dl_loaded, file, mode);
     }
 
   return _dlerror_run (doit) ? NULL : new;
index cc50650..804d404 100644 (file)
@@ -33,7 +33,8 @@ dlsym (void *handle, const char *name)
   int lose;
   void doit (void)
     {
-      loadbase = _dl_lookup_symbol (name, &ref, map, map->l_name, 0);
+      struct link_map *scope[2] = { map, NULL };
+      loadbase = _dl_lookup_symbol (name, &ref, scope, map->l_name, 0, 0);
     }
 
   /* Confine the symbol scope to just this map.  */
index a19a2ce..73782d8 100644 (file)
@@ -90,6 +90,12 @@ struct link_map
     Elf32_Word l_phnum;                /* Number of program header entries.  */
     Elf32_Addr l_entry;                /* Entry point location.  */
 
+    /* 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;
+
     /* Symbol hash table.  */
     Elf32_Word l_nbuckets;
     const Elf32_Word *l_buckets, *l_chain;
@@ -102,7 +108,6 @@ struct link_map
        lt_library,             /* Library needed by main executable.  */
        lt_loaded,              /* Extra run-time loaded shared object.  */
       } l_type:2;
-    unsigned int l_deps_loaded:1; /* Nonzero if DT_NEEDED items loaded.  */
     unsigned int l_relocated:1;        /* Nonzero if object's relocations done.  */
     unsigned int l_init_called:1; /* Nonzero if DT_INIT function called.  */
     unsigned int l_init_running:1; /* Nonzero while DT_INIT function runs.  */
@@ -176,22 +181,36 @@ extern struct link_map *_dl_map_object (struct link_map *loader,
 extern struct link_map *_dl_map_object_from_fd (const char *name,
                                                int fd, char *realname);
 
+/* Call _dl_map_object on the dependencies of MAP, and
+   set up MAP->l_searchlist.  */
+extern void _dl_map_object_deps (struct link_map *map);
+
 /* Cache the locations of MAP's hash table.  */
 extern void _dl_setup_hash (struct link_map *map);
 
 
+/* Open the shared object NAME, relocate it, and run its initializer if it
+   hasn't already been run.  LOADER's DT_RPATH is used in searching for
+   NAME.  MODE is as for `dlopen' (see <dlfcn.h>).  If the object is
+   already opened, returns its existing map.  */
+extern struct link_map *_dl_open (struct link_map *loader,
+                                 const char *name, int mode);
+
+
+
 /* Search loaded objects' symbol tables for a definition of the symbol
    referred to by UNDEF.  *SYM is the symbol table entry containing the
    reference; it is replaced with the defining symbol, and the base load
-   address of the defining object is returned.  SYMBOL_SCOPE is the head of
-   the chain used for searching.  REFERENCE_NAME should name the object
-   containing the reference; it is used in error messages.  RELOC_ADDR is
-   the address being fixed up and the chosen symbol cannot be one with this
-   value.  If NOPLT is nonzero, then the reference must not be resolved to
-   a PLT entry.  */
+   address of the defining object is returned.  Each of SYMBOL_SCOPE[0] and
+   SYMBOL_SCOPE[1] that is not null and their dependencies are searched to
+   resolve the name.  REFERENCE_NAME should name the object containing the
+   reference; it is used in error messages.  RELOC_ADDR is the address
+   being fixed up and the chosen symbol cannot be one with this value.  If
+   NOPLT is nonzero, then the reference must not be resolved to a PLT
+   entry.  */
 extern Elf32_Addr _dl_lookup_symbol (const char *undef,
                                     const Elf32_Sym **sym,
-                                    struct link_map *symbol_scope,
+                                    struct link_map *symbol_scope[2],
                                     const char *reference_name,
                                     Elf32_Addr reloc_addr,
                                     int noplt);
index ed1595e..8821a14 100644 (file)
@@ -1,5 +1,5 @@
 /* Initializer for Linux-compatible dynamic linker `/lib/ld-linux.so.1'.
-Copyright (C) 1995 Free Software Foundation, Inc.
+Copyright (C) 1995, 1996 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
@@ -33,8 +33,9 @@ void
 _init (void)
 {
   const Elf32_Sym *ref = NULL;
-  Elf32_Addr loadbase = _dl_lookup_symbol ("atexit", &ref, _dl_loaded,
+  struct link_map *scope[2] = { _dl_loaded, NULL };
+  Elf32_Addr loadbase = _dl_lookup_symbol ("atexit", &ref, scope,
                                           "<ld-linux.so.1 initialization>",
-                                          1);
+                                          0, 1);
   (*(__typeof (atexit) *) (loadbase + ref->st_value)) (&_dl_fini);
 }
index 511d19c..6dc6822 100644 (file)
@@ -124,7 +124,7 @@ dl_main (const Elf32_Phdr *phdr,
         Elf32_Addr *user_entry)
 {
   const Elf32_Phdr *ph;
-  struct link_map *l, *last, *before_rtld;
+  struct link_map *l;
   const char *interpreter_name;
   int lazy;
   int list_only = 0;
@@ -250,44 +250,19 @@ of this helper program; chances are you did not intend to run this program.\n",
   l->l_next = &rtld_map;
   rtld_map.l_prev = l;
 
-  /* Now process all the DT_NEEDED entries and map in the objects.
-     Each new link_map will go on the end of the chain, so we will
-     come across it later in the loop to map in its dependencies.  */
-  before_rtld = NULL;
-  for (l = _dl_loaded; l; l = l->l_next)
-    {
-      if (l->l_info[DT_NEEDED])
-       {
-         const char *strtab
-           = (void *) l->l_addr + l->l_info[DT_STRTAB]->d_un.d_ptr;
-         const Elf32_Dyn *d;
-         last = l;
-         for (d = l->l_ld; d->d_tag != DT_NULL; ++d)
-           if (d->d_tag == DT_NEEDED)
-             {
-               struct link_map *new;
-               new = _dl_map_object (l, strtab + d->d_un.d_val);
-               if (!before_rtld && new == &rtld_map)
-                 before_rtld = last;
-               last = new;
-             }
-       }
-      l->l_deps_loaded = 1;
-    }
+  /* Load all the libraries specified by DT_NEEDED entries.  */
+  _dl_map_object_deps (l);
 
-  /* If any DT_NEEDED entry referred to the interpreter object itself,
-     reorder the list so it appears after its dependent.  If not,
-     remove it from the maps we will use for symbol resolution.  */
-  rtld_map.l_prev->l_next = rtld_map.l_next;
-  if (rtld_map.l_next)
-    rtld_map.l_next->l_prev = rtld_map.l_prev;
-  if (before_rtld)
+  /* XXX if kept, move it so l_next list is in dep order because
+     it will determine gdb's search order.
+     Perhaps do this always, so later dlopen by name finds it?
+     XXX But then gdb always considers it present.  */
+  if (rtld_map.l_opencount == 0)
     {
-      rtld_map.l_prev = before_rtld;
-      rtld_map.l_next = before_rtld->l_next;
-      before_rtld->l_next = &rtld_map;
-      if (rtld_map.l_next)
-       rtld_map.l_next->l_prev = &rtld_map;
+      /* No DT_NEEDED entry referred to the interpreter object itself,
+        so remove it from the list of visible objects.  */
+      rtld_map.l_prev->l_next = rtld_map.l_next;
+      rtld_map.l_next->l_prev = rtld_map.l_prev;
     }
 
   if (list_only)
@@ -316,9 +291,9 @@ of this helper program; chances are you did not intend to run this program.\n",
       for (i = 1; i < _dl_argc; ++i)
        {
          const Elf32_Sym *ref = NULL;
-         Elf32_Addr loadbase = _dl_lookup_symbol (_dl_argv[i], &ref,
-                                                  _dl_loaded, "argument",
-                                                  0, 0);
+         struct link_map *scope[2] ={ _dl_loaded, NULL };
+         Elf32_Addr loadbase
+           = _dl_lookup_symbol (_dl_argv[i], &ref, scope, "argument", 0, 0);
          char buf[20], *bp;
          buf[sizeof buf - 1] = '\0';
          bp = _itoa (ref->st_value, &buf[sizeof buf - 1], 16, 0);