Misc fixes in new rtld code.
authorroland <roland>
Sat, 6 May 1995 14:40:15 +0000 (14:40 +0000)
committerroland <roland>
Sat, 6 May 1995 14:40:15 +0000 (14:40 +0000)
elf/dl-error.c
elf/dl-load.c
elf/dl-lookup.c
elf/dl-object.c
elf/dl-reloc.c
elf/dlclose.c
elf/dlerror.c
elf/dlsym.c
elf/dynamic-link.h
elf/link.h
elf/rtld.c

index b9ee351..5f8e4e4 100644 (file)
@@ -22,23 +22,28 @@ Cambridge, MA 02139, USA.  */
 #include <setjmp.h>
 
 static jmp_buf catch_env;
-static const char *signalled_errstring;
+static const char *signalled_errstring, *signalled_objname;
 
 void
-_dl_signal_error (int errcode, const char *errstring)
+_dl_signal_error (int errcode,
+                 const char *objname,
+                 const char *errstring)
 {
   signalled_errstring = errstring ?: "DYNAMIC LINKER BUG!!!";
   longjmp (catch_env, errcode ?: -1);
 }
 
 int
-_dl_catch_error (const char **errstring, void (*operate) (void))
+_dl_catch_error (const char **errstring,
+                const char **objname,
+                void (*operate) (void))
 {
   int errcode;
 
-  signalled_errstring = NULL;
+  signalled_errstring = signalled_objname = NULL;
   errcode = setjmp (catch_env);
   (*operate) ();
   *errstring = signalled_errstring;
+  *objname = signalled_objname;
   return *errstring ? errcode : 0;
 }
index 0de7404..f8b37ba 100644 (file)
@@ -107,10 +107,20 @@ _dl_map_object (struct link_map *loader, const char *name,
                Elf32_Addr *entry_point)
 {
   int fd;
+  struct link_map *l = NULL;
   char *realname;
   const size_t pagesize = getpagesize ();
   void *file_mapping = NULL;
   size_t mapping_size = 0;
+
+  void lose (int code, const char *msg)
+    {
+      (void) close (fd);
+      if (file_mapping)
+       munmap (file_mapping, mapping_size);
+      _dl_signal_error (code, l ? l->l_name : name, msg);
+    }
+
   /* Make sure LOCATION is mapped in.  */
   void *map (off_t location, size_t size)
     {
@@ -124,14 +134,13 @@ _dl_map_object (struct link_map *loader, const char *name,
          result = mmap (file_mapping, mapping_size, PROT_READ,
                         MAP_COPY|MAP_FILE, fd, 0);
          if (result == (void *) -1)
-           return NULL;
+           lose (errno, "cannot map file data");
          file_mapping = result;
        }
       return file_mapping + location;
     }
 
   const Elf32_Ehdr *header;
-  struct link_map *l;
 
   /* Look for this name among those already loaded.  */
   for (l = _dl_loaded; l; l = l->l_next)
@@ -170,7 +179,7 @@ _dl_map_object (struct link_map *loader, const char *name,
     }
 
   if (fd == -1)
-    return NULL;
+    lose (errno, "cannot open shared object file");
 
   /* Look again to see if the real name matched another already loaded.  */
   for (l = _dl_loaded; l; l = l->l_next)
@@ -186,17 +195,9 @@ _dl_map_object (struct link_map *loader, const char *name,
 
   /* Map in the first page to read the header.  */
   header = map (0, sizeof *header);
-  if (! header)
-    {
-    lose:
-      (void) close (fd);
-      if (file_mapping)
-       munmap (file_mapping, mapping_size);
-      return NULL;
-    }
 
 #undef LOSE
-#define LOSE(s) _dl_signal_error (0, s)
+#define LOSE(s) lose (0, (s))
   /* Check the header for basic validity.  */
   if (*(Elf32_Word *) &header->e_ident != ((ELFMAG0 << (EI_MAG0 * 8)) |
                                           (ELFMAG1 << (EI_MAG1 * 8)) |
@@ -224,7 +225,7 @@ _dl_map_object (struct link_map *loader, const char *name,
     {
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
       if (_dl_zerofd == -1)
-       _dl_signal_error (errno, "cannot open zero fill device");
+       _dl_signal_error (errno, NULL, "cannot open zero fill device");
     }
 
   {
@@ -235,8 +236,6 @@ _dl_map_object (struct link_map *loader, const char *name,
     int anywhere;
 
     ph = map (header->e_phoff, header->e_phnum * sizeof (Elf32_Phdr));
-    if (! ph)
-      goto lose;
     memcpy (phdr, ph, sizeof phdr);
     l->l_phnum = header->e_phnum;
 
@@ -288,7 +287,8 @@ _dl_map_object (struct link_map *loader, const char *name,
              {
                /* XXX this loses if the first segment mmap call puts
                   it someplace where the later segments cannot fit.  */
-               mapat = mmap ((caddr_t) l->l_addr + mapstart, mapend - mapstart,
+               mapat = mmap ((caddr_t) (l->l_addr + mapstart),
+                             mapend - mapstart,
                              prot, MAP_COPY|MAP_FILE|MAP_INHERIT |
                              /* Let the system choose any convenient
                                 location if this is the first segment.
@@ -312,8 +312,7 @@ _dl_map_object (struct link_map *loader, const char *name,
                l->l_addr = 0;
              }
            if (mapat == (caddr_t) -1)
-             _dl_signal_error (errno,
-                               "failed to map region from shared object");
+             lose (errno, "failed to map segment from shared object");
 
            if (ph->p_memsz > ph->p_filesz)
              {
@@ -341,8 +340,7 @@ _dl_map_object (struct link_map *loader, const char *name,
                                                 & ~(pagesize - 1)),
                                      pagesize,
                                      prot|PROT_WRITE) < 0)
-                         _dl_signal_error (errno,
-                                           "cannot change protections");
+                         lose (errno, "cannot change memory protections");
                      }
                    memset (zero, 0, zeroend - zero);
                    if ((prot & PROT_WRITE) == 0)
index b4600b1..a7afcc7 100644 (file)
@@ -27,7 +27,8 @@ 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,
+                  const char *reference_name)
 {
   unsigned long int hash = elf_hash (undef_name);
   struct link_map *map;
@@ -106,7 +107,7 @@ _dl_lookup_symbol (const char *undef_name, const Elf32_Sym **ref,
       char buf[sizeof msg + strlen (undef_name)];
       memcpy (buf, msg, sizeof msg - 1);
       memcpy (&buf[sizeof msg - 1], undef_name, sizeof buf - sizeof msg);
-      _dl_signal_error (0, msg);
+      _dl_signal_error (0, reference_name, msg);
     }
 
   *ref = weak_value.s;
index e7b1ce3..ca4e785 100644 (file)
@@ -37,7 +37,8 @@ _dl_new_object (char *realname, const char *libname, int type)
 {
   struct link_map *new = malloc (sizeof *new);
   if (! new)
-    _dl_signal_error (ENOMEM, "can't open new object");
+    _dl_signal_error (ENOMEM, libname,
+                     "cannot allocate shared object descriptor");
 
   memset (new, 0, sizeof *new);
   new->l_name = realname;
index 8efb3f0..9315517 100644 (file)
@@ -48,7 +48,7 @@ _dl_relocate_object (struct link_map *l, int lazy)
                               & ~(pagesize - 1)));
            if (mprotect (mapstart, mapend - mapstart,
                          PROT_READ|PROT_WRITE) < 0)
-             _dl_signal_error (errno,
+             _dl_signal_error (errno, l->l_name,
                                "cannot make segment writable for relocation");
          }
     }
@@ -62,7 +62,8 @@ _dl_relocate_object (struct link_map *l, int lazy)
 
     Elf32_Addr resolve (const Elf32_Sym **ref)
       {
-       return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope);
+       return _dl_lookup_symbol (strtab + (*ref)->st_name, ref, scope,
+                                 l->l_name);
       }
 
     real_next = l->l_next;
@@ -75,7 +76,7 @@ _dl_relocate_object (struct link_map *l, int lazy)
     else
       scope = _dl_loaded;
 
-    elf_dynamic_relocate (l->l_info, l->l_addr, lazy, resolve);
+    elf_dynamic_relocate (l, lazy, resolve);
 
     /* Restore list frobnication done above for DT_SYMBOLIC.  */
     l->l_next = real_next;
@@ -107,7 +108,7 @@ _dl_relocate_object (struct link_map *l, int lazy)
            if (ph->p_flags & PF_X)
              prot |= PROT_EXEC;
            if (mprotect (mapstart, mapend - mapstart, prot) < 0)
-             _dl_signal_error (errno,
+             _dl_signal_error (errno, l->l_name,
                                "can't restore segment prot after reloc");
          }
     }
index 4aa4085..06b2d1b 100644 (file)
@@ -24,7 +24,7 @@ Cambridge, MA 02139, USA.  */
 #include <sys/mman.h>
 
 
-#define LOSE(s) _dl_signal_error (0, s)
+#define LOSE(s) _dl_signal_error (0, map->l_name, s)
 
 int
 dlclose (void *handle)
index 0eed60a..4ec5037 100644 (file)
@@ -23,42 +23,49 @@ Cambridge, MA 02139, USA.  */
 #include <string.h>
 #include <stdlib.h>
 
-static int _dl_last_errcode;
-static const char *_dl_last_errstring;
+static int last_errcode;
+static const char *last_errstring;
+static const char *last_object_name;
 
 char *
 dlerror (void)
 {
- char *ret;
+  static char *buf;
+  char *ret;
 
-  if (! _dl_last_errstring)
-    return NULL;
-
-  if (_dl_last_errcode)
+  if (buf)
     {
-      static char *buf;
-      if (buf)
-       {
-         free (buf);
-         buf = NULL;
-       }
-      if (asprintf (&buf, "%s: %s",
-                   _dl_last_errstring, strerror (_dl_last_errcode)) == -1)
-       return NULL;
-      else
-       ret = buf;
+      free (buf);
+      buf = NULL;
     }
- else
-   ret = (char *) _dl_last_errstring;
 
- /* Reset the error indicator.  */
- _dl_last_errstring = NULL;
- return ret;
+  if (! last_errstring)
+    return NULL;
+
+  if (last_errcode == 0 && ! last_object_name)
+    ret = (char *) last_errstring;
+  else if (last_errcode == 0)
+    ret = (asprintf (&buf, "%s: %s", last_object_name, last_errstring) == -1
+          ? NULL : buf);
+  else if (! last_object_name)
+    ret = (asprintf (&buf, "%s: %s",
+                    last_errstring, strerror (last_errcode)) == -1
+          ? NULL : buf);
+  else
+    ret = (asprintf (&buf, "%s: %s: %s",
+                    last_object_name, last_errstring,
+                    strerror (last_errcode)) == -1
+          ? NULL : buf);
+
+  /* Reset the error indicator.  */
+  last_errstring = NULL;
+  return ret;
 }
 
 int
 _dlerror_run (void (*operate) (void))
 {
-  _dl_last_errcode = _dl_catch_error (&_dl_last_errstring, operate);
-  return _dl_last_errstring != NULL;
+  last_errcode = _dl_catch_error (&last_errstring, &last_object_name,
+                                 operate);
+  return last_errstring != NULL;
 }
index 6d87810..3e10812 100644 (file)
@@ -33,7 +33,7 @@ dlsym (void *handle, const char *name)
   void doit (void)
     {
       const Elf32_Sym *ref = NULL;
-      value = _dl_lookup_symbol (name, &ref, map);
+      value = _dl_lookup_symbol (name, map->l_name, &ref, map);
     }
 
   /* Confine the symbol scope to just this map.  */
index 1c3af29..5b4a502 100644 (file)
@@ -21,10 +21,10 @@ Cambridge, MA 02139, USA.  */
 
 /* This machine-dependent file defines these inline functions.  */
 
-static void elf_machine_rel (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
+static void elf_machine_rel (struct link_map *map,
                             const Elf32_Rel *reloc, 
                             Elf32_Addr sym_loadaddr, const Elf32_Sym *sym);
-static void elf_machine_rela (Elf32_Addr loadaddr, Elf32_Dyn *info[DT_NUM],
+static void elf_machine_rela (struct link_map *map,
                              const Elf32_Rela *reloc, 
                              Elf32_Addr sym_loadaddr, const Elf32_Sym *sym);
 static Elf32_Addr *elf_machine_got (void);
@@ -60,18 +60,18 @@ elf_get_dynamic_info (Elf32_Dyn *dyn, Elf32_Dyn *info[DT_NUM])
            info[DT_PLTREL]->d_un.d_val == DT_RELA);
 }
 
-/* Perform the relocations specified by DYNAMIC on the running program
+/* Perform the relocations specified by MAP on the running program
    image.  If LAZY is nonzero, don't relocate PLT entries.  *RESOLVE is
    called to resolve symbol values; it modifies its argument pointer to
    point to the defining symbol, and returns the base load address of the
    defining object.  */
 
 static inline void
-elf_dynamic_relocate (Elf32_Dyn *dynamic[DT_NUM], Elf32_Addr loadaddr,
+elf_dynamic_relocate (struct link_map *map,
                      int lazy, Elf32_Addr (*resolve) (const Elf32_Sym **))
 {
   const Elf32_Sym *const symtab
-    = (const Elf32_Sym *) dynamic[DT_SYMTAB]->d_un.d_ptr;
+    = (const Elf32_Sym *) map->l_info[DT_SYMTAB]->d_un.d_ptr;
 
   inline Elf32_Addr symvalue (Elf32_Word info, const Elf32_Sym **definer)
     {
@@ -84,36 +84,37 @@ elf_dynamic_relocate (Elf32_Dyn *dynamic[DT_NUM], Elf32_Addr loadaddr,
   /* Perform Elf32_Rel relocations in the section found by RELTAG, SZTAG.  */
   inline void do_rel (Elf32_Word reltag, Elf32_Word sztag)
     {
-      const Elf32_Rel *r = (const Elf32_Rel *) dynamic[reltag]->d_un.d_ptr;
-      const Elf32_Rel *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r];
+      const Elf32_Rel *r = (const Elf32_Rel *) map->l_info[reltag]->d_un.d_ptr;
+      const Elf32_Rel *end = &r[map->l_info[sztag]->d_un.d_val / sizeof *r];
       while (r < end)
        {
          const Elf32_Sym *definer;
          Elf32_Addr loadbase = symvalue (r->r_info, &definer);
-         elf_machine_rel (loadaddr, dynamic, r, loadbase, definer);
+         elf_machine_rel (map, r, loadbase, definer);
          ++r;
        }
     }
   /* Perform Elf32_Rela relocations in the section found by RELTAG, SZTAG.  */
   inline void do_rela (Elf32_Word reltag, Elf32_Word sztag)
     {
-      const Elf32_Rela *r = (const Elf32_Rela *) dynamic[reltag]->d_un.d_ptr;
-      const Elf32_Rela *end = &r[dynamic[sztag]->d_un.d_val / sizeof *r];
+      const Elf32_Rela *r
+       = (const Elf32_Rela *) map->l_info[reltag]->d_un.d_ptr;
+      const Elf32_Rela *end = &r[map->l_info[sztag]->d_un.d_val / sizeof *r];
       while (r < end)
        {
          const Elf32_Sym *definer;
          Elf32_Addr loadbase = symvalue (r->r_info, &definer);
-         elf_machine_rela (loadaddr, dynamic, r, loadbase, definer);
+         elf_machine_rela (map, r, loadbase, definer);
          ++r;
        }
     }
 
-  if (dynamic[DT_RELA])
+  if (map->l_info[DT_RELA])
     do_rela (DT_RELA, DT_RELASZ);
-  if (dynamic[DT_REL])
+  if (map->l_info[DT_REL])
     do_rel (DT_REL, DT_RELSZ);
-  if (dynamic[DT_JMPREL] && ! lazy)
+  if (map->l_info[DT_JMPREL] && ! lazy)
     /* Relocate the PLT right now.  */
-    (dynamic[DT_PLTREL]->d_un.d_val == DT_REL ? do_rel : do_rela)
+    (map->l_info[DT_PLTREL]->d_un.d_val == DT_REL ? do_rel : do_rela)
       (DT_JMPREL, DT_PLTRELSZ);
 }
index 7b999dc..66de6d9 100644 (file)
@@ -131,17 +131,23 @@ extern void _dl_sysdep_fatal (const char *string, ...)
 extern int _dl_secure;
 
 /* This function is called by all the internal dynamic linker functions
-   when they encounter an error.  ERRCODE is either an `errno' code
-   or zero; ERRSTRING is a string describing the specific problem.  */
+   when they encounter an error.  ERRCODE is either an `errno' code or
+   zero; OBJECT is the name of the problematical shared object, or null if
+   it is a general problem; ERRSTRING is a string describing the specific
+   problem.  */
    
-extern void _dl_signal_error (int errcode, const char *errstring)
+extern void _dl_signal_error (int errcode,
+                             const char *object,
+                             const char *errstring)
      __attribute__ ((__noreturn__));
 
 /* Call OPERATE, catching errors from `dl_signal_error'.  If there is no
-   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING is
-   set to the string passed to _dl_signal_error, and the error code passed
-   is the return value.  */
-extern int _dl_catch_error (const char **errstring, void (*operate) (void));
+   error, *ERRSTRING is set to null.  If there is an error, *ERRSTRING and
+   *OBJECT are set to the strings passed to _dl_signal_error, and the error
+   code passed is the return value.  */
+extern int _dl_catch_error (const char **errstring,
+                           const char **object,
+                           void (*operate) (void));
 
 
 /* Helper function for <dlfcn.h> functions.  Runs the OPERATE function via
@@ -166,10 +172,12 @@ extern void _dl_setup_hash (struct link_map *map);
    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.  */
+   the chain used for searching.  REFERENCE_NAME should name the object
+   containing the reference; it is used in error messages.  */
 extern Elf32_Addr _dl_lookup_symbol (const char *undef,
                                     const Elf32_Sym **sym,
-                                    struct link_map *symbol_scope);
+                                    struct link_map *symbol_scope,
+                                    const char *reference_name);
 
 
 /* List of objects currently loaded.  */
index fd75779..2b7d369 100644 (file)
@@ -52,21 +52,21 @@ static void dl_main (const Elf32_Phdr *phdr,
 Elf32_Addr
 _dl_start (void *arg)
 {
-  Elf32_Addr rtld_loadaddr;
-  Elf32_Dyn *dynamic_section;
-  Elf32_Dyn *dynamic_info[DT_NUM];
+  struct link_map rtld_map;
+
+  rtld_map.l_name = (char *) "<dynamic linker>";
 
   /* Figure out the run-time load address of the dynamic linker itself.  */
-  rtld_loadaddr = elf_machine_load_address ();
+  rtld_map.l_addr = elf_machine_load_address ();
 
   /* Read our own dynamic section and fill in the info array.
      Conveniently, the first element of the GOT contains the
      offset of _DYNAMIC relative to the run-time load address.  */
-  dynamic_section = (void *) rtld_loadaddr + *elf_machine_got ();
-  elf_get_dynamic_info (dynamic_section, dynamic_info);
+  rtld_map.l_ld = (void *) rtld_map.l_addr + *elf_machine_got ();
+  elf_get_dynamic_info (rtld_map.l_ld, rtld_map.l_info);
 
 #ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
-  ELF_MACHINE_BEFORE_RTLD_RELOC (dynamic_info);
+  ELF_MACHINE_BEFORE_RTLD_RELOC (rtld_map.l_info);
 #endif
 
   /* Relocate ourselves so we can do normal function calls and
@@ -75,9 +75,9 @@ _dl_start (void *arg)
     Elf32_Addr resolve (const Elf32_Sym **ref)
       {
        assert ((*ref)->st_shndx != SHN_UNDEF);
-       return rtld_loadaddr;
+       return rtld_map.l_addr;
       }
-    elf_dynamic_relocate (dynamic_info, rtld_loadaddr, 0, resolve);
+    elf_dynamic_relocate (&rtld_map, 0, resolve);
   }
 
   /* Now life is sane; we can call functions and access global data.
@@ -85,7 +85,7 @@ _dl_start (void *arg)
      the operating system's program loader where to find the program
      header table in core.  */
 
-  dl_r_debug.r_ldbase = rtld_loadaddr; /* Record our load address.  */
+  dl_r_debug.r_ldbase = rtld_map.l_addr; /* Record our load address.  */
 
   /* Call the OS-dependent function to set up life so we can do things like
      file access.  It will call `dl_main' (below) to do all the real work
@@ -107,29 +107,30 @@ dl_main (const Elf32_Phdr *phdr,
 {
   void doit (void)
     {
-  const Elf32_Phdr *ph;
-  struct link_map *l;
-  const char *interpreter_name;
-  int lazy;
+      const Elf32_Phdr *ph;
+      struct link_map *l;
+      const char *interpreter_name;
+      int lazy;
 
-  if (*user_entry == (Elf32_Addr) &_start)
-    {
-      /* Ho ho.  We are not the program interpreter!  We are the program
-        itself!  This means someone ran ld.so as a command.  Well, that
-        might be convenient to do sometimes.  We support it by
-        interpreting the args like this:
-
-        ld.so PROGRAM ARGS...
-        
-        The first argument is the name of a file containing an ELF
-        executable we will load and run with the following arguments.  To
-        simplify life here, PROGRAM is searched for using the normal rules
-        for shared objects, rather than $PATH or anything like that.  We
-        just load it and use its entry point; we don't pay attention to
-        its PT_INTERP command (we are the interpreter ourselves).  This is
-        an easy way to test a new ld.so before installing it.  */
-      if (_dl_argc < 2)
-       _dl_sysdep_fatal ("\
+      if (*user_entry == (Elf32_Addr) &_start)
+       {
+         /* Ho ho.  We are not the program interpreter!  We are the program
+            itself!  This means someone ran ld.so as a command.  Well, that
+            might be convenient to do sometimes.  We support it by
+            interpreting the args like this:
+            
+            ld.so PROGRAM ARGS...
+            
+            The first argument is the name of a file containing an ELF
+            executable we will load and run with the following arguments.
+            To simplify life here, PROGRAM is searched for using the
+            normal rules for shared objects, rather than $PATH or anything
+            like that.  We just load it and use its entry point; we don't
+            pay attention to its PT_INTERP command (we are the interpreter
+            ourselves).  This is an easy way to test a new ld.so before
+            installing it.  */
+         if (_dl_argc < 2)
+           _dl_sysdep_fatal ("\
 Usage: ld.so EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]\n\
 You have invoked `ld.so', the helper program for shared library executables.\n\
 This program usually lives in the file `/lib/ld.so', and special directives\n\
@@ -142,116 +143,118 @@ that file itself, but always uses this helper program from the file you\n\
 specified, instead of the helper program file specified in the executable\n\
 file you run.  This is mostly of use for maintainers to test new versions\n\
 of this helper program; chances are you did not intend to run this program.\n"
-                         );
-
-      interpreter_name = _dl_argv[0];
-      --_dl_argc;
-      ++_dl_argv;
-      l = _dl_map_object (NULL, _dl_argv[0], user_entry);
-      phdr = l->l_phdr;
-      phent = l->l_phnum;
-      l->l_type = lt_executable;
-      l->l_libname = (char *) "";
-    }
-  else
-    {
-      /* Create a link_map for the executable itself.
-        This will be what dlopen on "" returns.  */
-      l = _dl_new_object ((char *) "", "", lt_executable);
-      l->l_phdr = phdr;
-      l->l_phnum = phent;
-      interpreter_name = 0;
-    }
+                             );
+
+         interpreter_name = _dl_argv[0];
+         --_dl_argc;
+         ++_dl_argv;
+         l = _dl_map_object (NULL, _dl_argv[0], user_entry);
+         phdr = l->l_phdr;
+         phent = l->l_phnum;
+         l->l_type = lt_executable;
+         l->l_libname = (char *) "";
+       }
+      else
+       {
+         /* Create a link_map for the executable itself.
+            This will be what dlopen on "" returns.  */
+         l = _dl_new_object ((char *) "", "", lt_executable);
+         l->l_phdr = phdr;
+         l->l_phnum = phent;
+         interpreter_name = 0;
+       }
 
-  /* Scan the program header table for the dynamic section.  */
-  for (ph = phdr; ph < &phdr[phent]; ++ph)
-    switch (ph->p_type)
-      {
-      case PT_DYNAMIC:
-       /* This tells us where to find the dynamic section,
-          which tells us everything we need to do.  */
-       l->l_ld = (void *) ph->p_vaddr;
-       break;
-      case PT_INTERP:
-       /* This "interpreter segment" was used by the program loader to
-          find the program interpreter, which is this program itself, the
-          dynamic linker.  We note what name finds us, so that a future
-          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.  */
-       interpreter_name = (void *) ph->p_vaddr;
-       break;
-      }
-  assert (interpreter_name);   /* How else did we get here?  */
-
-  /* Extract the contents of the dynamic section for easy access.  */
-  elf_get_dynamic_info (l->l_ld, l->l_info);
-  /* Set up our cache of pointers into the hash table.  */
-  _dl_setup_hash (l);
-
-  if (l->l_info[DT_DEBUG])
-    /* There is a DT_DEBUG entry in the dynamic section.  Fill it in
-       with the run-time address of the r_debug structure, which we
-       will set up later to communicate with the debugger.  */
-    l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;
-
-  l = _dl_new_object ((char *) interpreter_name, interpreter_name,
-                     lt_interpreter);
-
-  /* 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.  */
-  for (l = _dl_loaded; l; l = l->l_next)
-    {
-      if (l->l_info[DT_NEEDED])
+      /* Scan the program header table for the dynamic section.  */
+      for (ph = phdr; ph < &phdr[phent]; ++ph)
+       switch (ph->p_type)
+         {
+         case PT_DYNAMIC:
+           /* This tells us where to find the dynamic section,
+              which tells us everything we need to do.  */
+           l->l_ld = (void *) ph->p_vaddr;
+           break;
+         case PT_INTERP:
+           /* This "interpreter segment" was used by the program loader to
+              find the program interpreter, which is this program itself, the
+              dynamic linker.  We note what name finds us, so that a future
+              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.  */
+           interpreter_name = (void *) ph->p_vaddr;
+           break;
+         }
+      assert (interpreter_name); /* How else did we get here?  */
+
+      /* Extract the contents of the dynamic section for easy access.  */
+      elf_get_dynamic_info (l->l_ld, l->l_info);
+      /* Set up our cache of pointers into the hash table.  */
+      _dl_setup_hash (l);
+
+      if (l->l_info[DT_DEBUG])
+       /* There is a DT_DEBUG entry in the dynamic section.  Fill it in
+          with the run-time address of the r_debug structure, which we
+          will set up later to communicate with the debugger.  */
+       l->l_info[DT_DEBUG]->d_un.d_ptr = (Elf32_Addr) &dl_r_debug;
+
+      l = _dl_new_object ((char *) interpreter_name, interpreter_name,
+                         lt_interpreter);
+
+      /* 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.  */
+      for (l = _dl_loaded; l; l = l->l_next)
        {
-         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, NULL);
+         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, NULL);
+           }
+         l->l_deps_loaded = 1;
        }
-      l->l_deps_loaded = 1;
-    }
 
-  l = _dl_loaded->l_next;
-  assert (l->l_type == lt_interpreter);
-  if (l->l_opencount == 0)
-    {
-      /* No DT_NEEDED entry referred to the interpreter object itself.
-        Remove it from the maps we will use for symbol resolution.  */
-      l->l_prev->l_next = l->l_next;
-      if (l->l_next)
-       l->l_next->l_prev = l->l_prev;
-    }
+      l = _dl_loaded->l_next;
+      assert (l->l_type == lt_interpreter);
+      if (l->l_opencount == 0)
+       {
+         /* No DT_NEEDED entry referred to the interpreter object itself.
+            Remove it from the maps we will use for symbol resolution.  */
+         l->l_prev->l_next = l->l_next;
+         if (l->l_next)
+           l->l_next->l_prev = l->l_prev;
+       }
 
-  lazy = _dl_secure || *(getenv ("LD_BIND_NOW") ?: "");
+      lazy = _dl_secure || *(getenv ("LD_BIND_NOW") ?: "");
 
-  /* Now we have all the objects loaded.  Relocate them all.
-     We do this in reverse order so that copy relocs of earlier
-     objects overwrite the data written by later objects.  */
-  l = _dl_loaded;
-  while (l->l_next)
-    l = l->l_next;
-  do
-    {
-      _dl_relocate_object (l, lazy);
-      l = l->l_prev;
-    } while (l);
-
-  /* Tell the debugger where to find the map of loaded objects.  */
-  dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
-  dl_r_debug.r_map = _dl_loaded;
-  dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
-}
+      /* Now we have all the objects loaded.  Relocate them all.
+        We do this in reverse order so that copy relocs of earlier
+        objects overwrite the data written by later objects.  */
+      l = _dl_loaded;
+      while (l->l_next)
+       l = l->l_next;
+      do
+       {
+         _dl_relocate_object (l, lazy);
+         l = l->l_prev;
+       } while (l);
+
+      /* Tell the debugger where to find the map of loaded objects.  */
+      dl_r_debug.r_version = 1 /* R_DEBUG_VERSION XXX */;
+      dl_r_debug.r_map = _dl_loaded;
+      dl_r_debug.r_brk = (Elf32_Addr) &_dl_r_debug_state;
+    }
   const char *errstring;
+  const char *errobj;
   int err;
 
-  err = _dl_catch_error (&errstring, &doit);
+  err = _dl_catch_error (&errstring, &errobj, &doit);
   if (errstring)
     _dl_sysdep_fatal (_dl_argv[0] ?: "<program name unknown>",
                      ": error in loading shared libraries\n",
+                     errobj ?: "", errobj ? ": " : "",
                      errstring, err ? ": " : NULL,
                      err ? strerror (err) : NULL, NULL);