]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/dl-load.c
Fix BZ 20419. A PT_NOTE in a binary could be arbitratily large, so using
[thirdparty/glibc.git] / elf / dl-load.c
index 025b9fd86b600eefa40db3f40d731f7009f49673..431236920f9d1b04fa98923195ca45f775262949 100644 (file)
@@ -1,5 +1,5 @@
 /* Map in a shared object's segments from the file.
-   Copyright (C) 1995-2005, 2006, 2007  Free Software Foundation, Inc.
+   Copyright (C) 1995-2018 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
@@ -13,9 +13,8 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
 
 #include <elf.h>
 #include <errno.h>
 #include "dynamic-link.h"
 #include <abi-tag.h>
 #include <stackinfo.h>
-#include <caller.h>
 #include <sysdep.h>
+#include <stap-probe.h>
+#include <libc-pointer-arith.h>
+#include <array_length.h>
 
 #include <dl-dst.h>
-
-/* On some systems, no flag bits are given to specify file mapping.  */
-#ifndef MAP_FILE
-# define MAP_FILE      0
-#endif
-
-/* The right way to map in the shared library files is MAP_COPY, which
-   makes a virtual copy of the data at the time of the mmap call; this
-   guarantees the mapped pages will be consistent even if the file is
-   overwritten.  Some losing VM systems like Linux's lack MAP_COPY.  All we
-   get is MAP_PRIVATE, which copies each page when it is modified; this
-   means if the file is overwritten, we may at some point get some pages
-   from the new version after starting with pages from the old version.
-
-   To make up for the lack and avoid the overwriting problem,
-   what Linux does have is MAP_DENYWRITE.  This prevents anyone
-   from modifying the file while we have it mapped.  */
-#ifndef MAP_COPY
-# ifdef MAP_DENYWRITE
-#  define MAP_COPY     (MAP_PRIVATE | MAP_DENYWRITE)
-# else
-#  define MAP_COPY     MAP_PRIVATE
-# endif
-#endif
-
-/* Some systems link their relocatable objects for another base address
-   than 0.  We want to know the base address for these such that we can
-   subtract this address from the segment addresses during mapping.
-   This results in a more efficient address space usage.  Defaults to
-   zero for almost all systems.  */
-#ifndef MAP_BASE_ADDR
-# define MAP_BASE_ADDR(l)      0
-#endif
+#include <dl-load.h>
+#include <dl-map-segments.h>
+#include <dl-unmap-segments.h>
+#include <dl-machine-reject-phdr.h>
+#include <dl-sysdep-open.h>
 
 
 #include <endian.h>
 
 #define STRING(x) __STRING (x)
 
-#ifdef MAP_ANON
-/* The fd is not examined when using MAP_ANON.  */
-# define ANONFD -1
-#else
-int _dl_zerofd = -1;
-# define ANONFD _dl_zerofd
-#endif
-
-/* Handle situations where we have a preferred location in memory for
-   the shared objects.  */
-#ifdef ELF_PREFERRED_ADDRESS_DATA
-ELF_PREFERRED_ADDRESS_DATA;
-#endif
-#ifndef ELF_PREFERRED_ADDRESS
-# define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) (mapstartpref)
-#endif
-#ifndef ELF_FIXED_ADDRESS
-# define ELF_FIXED_ADDRESS(loader, mapstart) ((void) 0)
-#endif
-
 
 int __stack_prot attribute_hidden attribute_relro
 #if _STACK_GROWS_DOWN && defined PROT_GROWSDOWN
@@ -150,7 +103,9 @@ static size_t ncapstr attribute_relro;
 static size_t max_capstrlen attribute_relro;
 
 
-/* Get the generated information about the trusted directories.  */
+/* Get the generated information about the trusted directories.  Use
+   an array of concatenated strings to avoid relocations.  See
+   gen-trusted-dirs.awk.  */
 #include "trusted-dirs.h"
 
 static const char system_dirs[] = SYSTEM_DIRS;
@@ -158,27 +113,73 @@ static const size_t system_dirs_len[] =
 {
   SYSTEM_DIRS_LEN
 };
-#define nsystem_dirs_len \
-  (sizeof (system_dirs_len) / sizeof (system_dirs_len[0]))
-
+#define nsystem_dirs_len array_length (system_dirs_len)
 
-/* Local version of `strdup' function.  */
-static inline char *
-local_strdup (const char *s)
+static bool
+is_trusted_path_normalize (const char *path, size_t len)
 {
-  size_t len = strlen (s) + 1;
-  void *new = malloc (len);
+  if (len == 0)
+    return false;
 
-  if (new == NULL)
-    return NULL;
+  if (*path == ':')
+    {
+      ++path;
+      --len;
+    }
 
-  return (char *) memcpy (new, s, len);
+  char *npath = (char *) alloca (len + 2);
+  char *wnp = npath;
+  while (*path != '\0')
+    {
+      if (path[0] == '/')
+       {
+         if (path[1] == '.')
+           {
+             if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
+               {
+                 while (wnp > npath && *--wnp != '/')
+                   ;
+                 path += 3;
+                 continue;
+               }
+             else if (path[2] == '/' || path[2] == '\0')
+               {
+                 path += 2;
+                 continue;
+               }
+           }
+
+         if (wnp > npath && wnp[-1] == '/')
+           {
+             ++path;
+             continue;
+           }
+       }
+
+      *wnp++ = *path++;
+    }
+
+  if (wnp == npath || wnp[-1] != '/')
+    *wnp++ = '/';
+
+  const char *trun = system_dirs;
+
+  for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
+    {
+      if (wnp - npath >= system_dirs_len[idx]
+         && memcmp (trun, npath, system_dirs_len[idx]) == 0)
+       /* Found it.  */
+       return true;
+
+      trun += system_dirs_len[idx] + 1;
+    }
+
+  return false;
 }
 
 
 static size_t
-is_dst (const char *start, const char *name, const char *str,
-       int is_path, int secure)
+is_dst (const char *start, const char *name, const char *str, int secure)
 {
   size_t len;
   bool is_curly = false;
@@ -203,13 +204,12 @@ is_dst (const char *start, const char *name, const char *str,
       /* Skip over closing curly brace and adjust for the --name.  */
       len += 2;
     }
-  else if (name[len] != '\0' && name[len] != '/'
-          && (!is_path || name[len] != ':'))
+  else if (name[len] != '\0' && name[len] != '/')
     return 0;
 
-  if (__builtin_expect (secure, 0)
-      && ((name[len] != '\0' && (!is_path || name[len] != ':'))
-         || (name != start + 1 && (!is_path || name[-2] != ':'))))
+  if (__glibc_unlikely (secure)
+      && ((name[len] != '\0' && name[len] != '/')
+         || (name != start + 1)))
     return 0;
 
   return len;
@@ -217,7 +217,7 @@ is_dst (const char *start, const char *name, const char *str,
 
 
 size_t
-_dl_dst_count (const char *name, int is_path)
+_dl_dst_count (const char *name)
 {
   const char *const start = name;
   size_t cnt = 0;
@@ -229,10 +229,9 @@ _dl_dst_count (const char *name, int is_path)
       /* $ORIGIN is not expanded for SUID/GUID programs (except if it
         is $ORIGIN alone) and it must always appear first in path.  */
       ++name;
-      if ((len = is_dst (start, name, "ORIGIN", is_path,
-                        INTUSE(__libc_enable_secure))) != 0
-         || (len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0
-         || (len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+      if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0
+         || (len = is_dst (start, name, "PLATFORM", 0)) != 0
+         || (len = is_dst (start, name, "LIB", 0)) != 0)
        ++cnt;
 
       name = strchr (name + len, '$');
@@ -244,39 +243,35 @@ _dl_dst_count (const char *name, int is_path)
 
 
 char *
-_dl_dst_substitute (struct link_map *l, const char *name, char *result,
-                   int is_path)
+_dl_dst_substitute (struct link_map *l, const char *name, char *result)
 {
   const char *const start = name;
-  char *last_elem, *wp;
 
   /* Now fill the result path.  While copying over the string we keep
-     track of the start of the last path element.  When we come accross
+     track of the start of the last path element.  When we come across
      a DST we copy over the value or (if the value is not available)
      leave the entire path element out.  */
-  last_elem = wp = result;
+  char *wp = result;
+  char *last_elem = result;
+  bool check_for_trusted = false;
 
   do
     {
-      if (__builtin_expect (*name == '$', 0))
+      if (__glibc_unlikely (*name == '$'))
        {
          const char *repl = NULL;
          size_t len;
 
          ++name;
-         if ((len = is_dst (start, name, "ORIGIN", is_path,
-                            INTUSE(__libc_enable_secure))) != 0)
+         if ((len = is_dst (start, name, "ORIGIN", __libc_enable_secure)) != 0)
            {
-#ifndef SHARED
-             if (l == NULL)
-               repl = _dl_get_origin ();
-             else
-#endif
-               repl = l->l_origin;
+             repl = l->l_origin;
+             check_for_trusted = (__libc_enable_secure
+                                  && l->l_type == lt_executable);
            }
-         else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+         else if ((len = is_dst (start, name, "PLATFORM", 0)) != 0)
            repl = GLRO(dl_platform);
-         else if ((len = is_dst (start, name, "LIB", is_path, 0)) != 0)
+         else if ((len = is_dst (start, name, "LIB", 0)) != 0)
            repl = DL_DST_LIB;
 
          if (repl != NULL && repl != (const char *) -1)
@@ -289,9 +284,7 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
              /* We cannot use this path element, the value of the
                 replacement is unknown.  */
              wp = last_elem;
-             name += len;
-             while (*name != '\0' && (!is_path || *name != ':'))
-               ++name;
+             break;
            }
          else
            /* No DST we recognize.  */
@@ -300,12 +293,16 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
       else
        {
          *wp++ = *name++;
-         if (is_path && *name == ':')
-           last_elem = wp;
        }
     }
   while (*name != '\0');
 
+  /* In SUID/SGID programs, after $ORIGIN expansion the normalized
+     path must be rooted in one of the trusted directories.  */
+  if (__glibc_unlikely (check_for_trusted)
+      && !is_trusted_path_normalize (last_elem, wp - last_elem))
+    wp = last_elem;
+
   *wp = '\0';
 
   return result;
@@ -321,7 +318,7 @@ static char *
 expand_dynamic_string_token (struct link_map *l, const char *s)
 {
   /* We make two runs over the string.  First we determine how large the
-     resulting string is and then we copy it over.  Since this is now
+     resulting string is and then we copy it over.  Since this is no
      frequently executed operation we are looking here not for performance
      but rather for code size.  */
   size_t cnt;
@@ -329,11 +326,11 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
   char *result;
 
   /* Determine the number of DST elements.  */
-  cnt = DL_DST_COUNT (s, 1);
+  cnt = DL_DST_COUNT (s);
 
   /* If we do not have to replace anything simply copy the string.  */
-  if (__builtin_expect (cnt, 0) == 0)
-    return local_strdup (s);
+  if (__glibc_likely (cnt == 0))
+    return __strdup (s);
 
   /* Determine the length of the substituted string.  */
   total = DL_DST_REQUIRED (l, s, strlen (s), cnt);
@@ -343,7 +340,7 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
   if (result == NULL)
     return NULL;
 
-  return _dl_dst_substitute (l, s, result, 1);
+  return _dl_dst_substitute (l, s, result);
 }
 
 
@@ -352,7 +349,6 @@ expand_dynamic_string_token (struct link_map *l, const char *s)
    be freed if the shared object already has this name.
    Returns false if the object already had this name.  */
 static void
-internal_function
 add_name_to_object (struct link_map *l, const char *name)
 {
   struct libname_list *lnp, *lastp;
@@ -388,7 +384,7 @@ static size_t max_dirnamelen;
 
 static struct r_search_path_elem **
 fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
-             int check_trusted, const char *what, const char *where)
+             const char *what, const char *where, struct link_map *l)
 {
   char *cp;
   size_t nelems = 0;
@@ -396,51 +392,35 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
   while ((cp = __strsep (&rpath, sep)) != NULL)
     {
       struct r_search_path_elem *dirp;
-      size_t len = strlen (cp);
+      char *to_free = NULL;
+      size_t len = 0;
 
-      /* `strsep' can pass an empty string.  This has to be
-         interpreted as `use the current directory'. */
-      if (len == 0)
+      /* `strsep' can pass an empty string.  */
+      if (*cp != '\0')
        {
-         static const char curwd[] = "./";
-         cp = (char *) curwd;
-       }
-
-      /* Remove trailing slashes (except for "/").  */
-      while (len > 1 && cp[len - 1] == '/')
-       --len;
+         to_free = cp = expand_dynamic_string_token (l, cp);
 
-      /* Now add one if there is none so far.  */
-      if (len > 0 && cp[len - 1] != '/')
-       cp[len++] = '/';
-
-      /* Make sure we don't use untrusted directories if we run SUID.  */
-      if (__builtin_expect (check_trusted, 0))
-       {
-         const char *trun = system_dirs;
-         size_t idx;
-         int unsecure = 1;
+         /* expand_dynamic_string_token can return NULL in case of empty
+            path or memory allocation failure.  */
+         if (cp == NULL)
+           continue;
 
-         /* All trusted directories must be complete names.  */
-         if (cp[0] == '/')
+         /* Compute the length after dynamic string token expansion and
+            ignore empty paths.  */
+         len = strlen (cp);
+         if (len == 0)
            {
-             for (idx = 0; idx < nsystem_dirs_len; ++idx)
-               {
-                 if (len == system_dirs_len[idx]
-                     && memcmp (trun, cp, len) == 0)
-                   {
-                     /* Found it.  */
-                     unsecure = 0;
-                     break;
-                   }
-
-                 trun += system_dirs_len[idx] + 1;
-               }
+             free (to_free);
+             continue;
            }
 
-         if (unsecure)
-           /* Simply drop this directory.  */
-           continue;
+         /* Remove trailing slashes (except for "/").  */
+         while (len > 1 && cp[len - 1] == '/')
+           --len;
+
+         /* Now add one if there is none so far.  */
+         if (len > 0 && cp[len - 1] != '/')
+           cp[len++] = '/';
        }
 
       /* See if this directory is already known.  */
@@ -489,7 +469,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
            dirp->status[cnt] = init_val;
 
          dirp->what = what;
-         if (__builtin_expect (where != NULL, 1))
+         if (__glibc_likely (where != NULL))
            dirp->where = memcpy ((char *) dirp + sizeof (*dirp) + len + 1
                                  + (ncapstr * sizeof (enum r_dir_status)),
                                  where, where_len);
@@ -502,6 +482,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
          /* Put it in the result array.  */
          result[nelems++] = dirp;
        }
+      free (to_free);
     }
 
   /* Terminate the array.  */
@@ -512,13 +493,11 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 
 
 static bool
-internal_function
 decompose_rpath (struct r_search_path_struct *sps,
                 const char *rpath, struct link_map *l, const char *what)
 {
   /* Make a copy we can work with.  */
   const char *where = l->l_name;
-  char *copy;
   char *cp;
   struct r_search_path_elem **result;
   size_t nelems;
@@ -527,8 +506,8 @@ decompose_rpath (struct r_search_path_struct *sps,
 
   /* First see whether we must forget the RUNPATH and RPATH from this
      object.  */
-  if (__builtin_expect (GLRO(dl_inhibit_rpath) != NULL, 0)
-      && !INTUSE(__libc_enable_secure))
+  if (__glibc_unlikely (GLRO(dl_inhibit_rpath) != NULL)
+      && !__libc_enable_secure)
     {
       const char *inhp = GLRO(dl_inhibit_rpath);
 
@@ -557,9 +536,15 @@ decompose_rpath (struct r_search_path_struct *sps,
       while (*inhp != '\0');
     }
 
-  /* Make a writable copy.  At the same time expand possible dynamic
-     string tokens.  */
-  copy = expand_dynamic_string_token (l, rpath);
+  /* Ignore empty rpaths.  */
+  if (*rpath == '\0')
+    {
+      sps->dirs = (struct r_search_path_elem **) -1;
+      return false;
+    }
+
+  /* Make a writable copy.  */
+  char *copy = __strdup (rpath);
   if (copy == NULL)
     {
       errstring = N_("cannot create RUNPATH/RPATH copy");
@@ -578,17 +563,26 @@ decompose_rpath (struct r_search_path_struct *sps,
                                                  * sizeof (*result));
   if (result == NULL)
     {
+      free (copy);
       errstring = N_("cannot create cache for search path");
     signal_error:
       _dl_signal_error (ENOMEM, NULL, NULL, errstring);
     }
 
-  fillin_rpath (copy, result, ":", 0, what, where);
+  fillin_rpath (copy, result, ":", what, where, l);
 
   /* Free the copied RPATH string.  `fillin_rpath' make own copies if
      necessary.  */
   free (copy);
 
+  /* There is no path after expansion.  */
+  if (result[0] == NULL)
+    {
+      free (result);
+      sps->dirs = (struct r_search_path_elem **) -1;
+      return false;
+    }
+
   sps->dirs = result;
   /* The caller will change this value if we haven't used a real malloc.  */
   sps->malloced = 1;
@@ -624,16 +618,13 @@ cache_rpath (struct link_map *l,
 
 
 void
-internal_function
 _dl_init_paths (const char *llp)
 {
   size_t idx;
   const char *strp;
   struct r_search_path_elem *pelem, **aelem;
   size_t round_size;
-#ifdef SHARED
-  struct link_map *l;
-#endif
+  struct link_map __attribute__ ((unused)) *l = NULL;
   /* Initialize to please the compiler.  */
   const char *errstring = NULL;
 
@@ -658,9 +649,8 @@ _dl_init_paths (const char *llp)
                 + ncapstr * sizeof (enum r_dir_status))
                / sizeof (struct r_search_path_elem));
 
-  rtld_search_dirs.dirs[0] = (struct r_search_path_elem *)
-    malloc ((sizeof (system_dirs) / sizeof (system_dirs[0]))
-           * round_size * sizeof (struct r_search_path_elem));
+  rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size
+                                    * sizeof (*rtld_search_dirs.dirs[0]));
   if (rtld_search_dirs.dirs[0] == NULL)
     {
       errstring = N_("cannot create cache for search path");
@@ -714,6 +704,9 @@ _dl_init_paths (const char *llp)
                           (const void *) (D_PTR (l, l_info[DT_STRTAB])
                                           + l->l_info[DT_RUNPATH]->d_un.d_val),
                           l, "RUNPATH");
+         /* During rtld init the memory is allocated by the stub malloc,
+            prevent any attempt to free it by the normal malloc.  */
+         l->l_runpath_dirs.malloced = 0;
 
          /* The RPATH is ignored.  */
          l->l_rpath_dirs.dirs = (void *) -1;
@@ -730,6 +723,9 @@ _dl_init_paths (const char *llp)
                               (const void *) (D_PTR (l, l_info[DT_STRTAB])
                                               + l->l_info[DT_RPATH]->d_un.d_val),
                               l, "RPATH");
+             /* During rtld init the memory is allocated by the stub
+                malloc, prevent any attempt to free it by the normal
+                malloc.  */
              l->l_rpath_dirs.malloced = 0;
            }
          else
@@ -740,37 +736,14 @@ _dl_init_paths (const char *llp)
 
   if (llp != NULL && *llp != '\0')
     {
-      size_t nllp;
-      const char *cp = llp;
-      char *llp_tmp;
-
-#ifdef SHARED
-      /* Expand DSTs.  */
-      size_t cnt = DL_DST_COUNT (llp, 1);
-      if (__builtin_expect (cnt == 0, 1))
-       llp_tmp = strdupa (llp);
-      else
-       {
-         /* Determine the length of the substituted string.  */
-         size_t total = DL_DST_REQUIRED (l, llp, strlen (llp), cnt);
-
-         /* Allocate the necessary memory.  */
-         llp_tmp = (char *) alloca (total + 1);
-         llp_tmp = _dl_dst_substitute (l, llp, llp_tmp, 1);
-       }
-#else
-      llp_tmp = strdupa (llp);
-#endif
+      char *llp_tmp = strdupa (llp);
 
       /* Decompose the LD_LIBRARY_PATH contents.  First determine how many
         elements it has.  */
-      nllp = 1;
-      while (*cp)
-       {
-         if (*cp == ':' || *cp == ';')
-           ++nllp;
-         ++cp;
-       }
+      size_t nllp = 1;
+      for (const char *cp = llp_tmp; *cp != '\0'; ++cp)
+       if (*cp == ':' || *cp == ';')
+         ++nllp;
 
       env_path_list.dirs = (struct r_search_path_elem **)
        malloc ((nllp + 1) * sizeof (struct r_search_path_elem *));
@@ -781,8 +754,7 @@ _dl_init_paths (const char *llp)
        }
 
       (void) fillin_rpath (llp_tmp, env_path_list.dirs, ":;",
-                          INTUSE(__libc_enable_secure), "LD_LIBRARY_PATH",
-                          NULL);
+                          "LD_LIBRARY_PATH", NULL, l);
 
       if (env_path_list.dirs[0] == NULL)
        {
@@ -794,39 +766,27 @@ _dl_init_paths (const char *llp)
     }
   else
     env_path_list.dirs = (void *) -1;
-
-  /* Remember the last search directory added at startup.  */
-  GLRO(dl_init_all_dirs) = GL(dl_all_dirs);
 }
 
 
 static void
 __attribute__ ((noreturn, noinline))
 lose (int code, int fd, const char *name, char *realname, struct link_map *l,
-      const char *msg, struct r_debug *r)
+      const char *msg, struct r_debug *r, Lmid_t nsid)
 {
   /* The file might already be closed.  */
   if (fd != -1)
     (void) __close (fd);
-  if (l != NULL)
-    {
-      /* Remove the stillborn object from the list and free it.  */
-      assert (l->l_next == NULL);
-      if (l->l_prev == NULL)
-       /* No other module loaded. This happens only in the static library,
-          or in rtld under --verify.  */
-       GL(dl_ns)[l->l_ns]._ns_loaded = NULL;
-      else
-       l->l_prev->l_next = NULL;
-      --GL(dl_ns)[l->l_ns]._ns_nloaded;
-      free (l);
-    }
+  if (l != NULL && l->l_origin != (char *) -1l)
+    free ((char *) l->l_origin);
+  free (l);
   free (realname);
 
   if (r != NULL)
     {
       r->r_state = RT_CONSISTENT;
       _dl_debug_state ();
+      LIBC_PROBE (map_failed, 2, nsid, r);
     }
 
   _dl_signal_error (code, name, NULL, msg);
@@ -840,9 +800,10 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
 static
 #endif
 struct link_map *
-_dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
-                       char *realname, struct link_map *loader, int l_type,
-                       int mode, void **stack_endp, Lmid_t nsid)
+_dl_map_object_from_fd (const char *name, const char *origname, int fd,
+                       struct filebuf *fbp, char *realname,
+                       struct link_map *loader, int l_type, int mode,
+                       void **stack_endp, Lmid_t nsid)
 {
   struct link_map *l = NULL;
   const ElfW(Ehdr) *header;
@@ -850,7 +811,6 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   const ElfW(Phdr) *ph;
   size_t maplength;
   int type;
-  struct stat64 st;
   /* Initialize to keep the compiler happy.  */
   const char *errstring = NULL;
   int errval = 0;
@@ -858,19 +818,20 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
   bool make_consistent = false;
 
   /* Get file information.  */
-  if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st) < 0, 0))
+  struct r_file_id id;
+  if (__glibc_unlikely (!_dl_get_file_id (fd, &id)))
     {
       errstring = N_("cannot stat shared object");
     call_lose_errno:
       errval = errno;
     call_lose:
       lose (errval, fd, name, realname, l, errstring,
-           make_consistent ? r : NULL);
+           make_consistent ? r : NULL, nsid);
     }
 
   /* Look again to see if the real name matched another already loaded.  */
-  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
-    if (l->l_removed == 0 && l->l_ino == st.st_ino && l->l_dev == st.st_dev)
+  for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
+    if (!l->l_removed && _dl_file_id_match_p (&l->l_file_id, &id))
       {
        /* The object is already loaded.
           Just bump its reference count and return it.  */
@@ -887,9 +848,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 #ifdef SHARED
   /* When loading into a namespace other than the base one we must
      avoid loading ld.so since there can only be one copy.  Ever.  */
-  if (__builtin_expect (nsid != LM_ID_BASE, 0)
-      && ((st.st_ino == GL(dl_rtld_map).l_ino
-          && st.st_dev == GL(dl_rtld_map).l_dev)
+  if (__glibc_unlikely (nsid != LM_ID_BASE)
+      && (_dl_file_id_match_p (&id, &GL(dl_rtld_map).l_file_id)
          || _dl_name_match_p (name, &GL(dl_rtld_map))))
     {
       /* This is indeed ld.so.  Create a new link_map which refers to
@@ -905,17 +865,24 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
         never be unloaded.  */
       __close (fd);
 
+      /* Add the map for the mirrored object to the object list.  */
+      _dl_add_to_namespace_list (l, nsid);
+
       return l;
     }
 #endif
 
   if (mode & RTLD_NOLOAD)
-    /* We are not supposed to load the object unless it is already
-       loaded.  So return now.  */
-    return NULL;
+    {
+      /* We are not supposed to load the object unless it is already
+        loaded.  So return now.  */
+      free (realname);
+      __close (fd);
+      return NULL;
+    }
 
   /* Print debugging message.  */
-  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
+  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
     _dl_debug_printf ("file=%s [%lu];  generating link map\n", name, nsid);
 
   /* This is the ELF header.  We read it in `open_verify'.  */
@@ -928,6 +895,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
       _dl_zerofd = _dl_sysdep_open_zero_fill ();
       if (_dl_zerofd == -1)
        {
+         free (realname);
          __close (fd);
          _dl_signal_error (errno, NULL, NULL,
                            N_("cannot open zero fill device"));
@@ -940,7 +908,8 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
     {
 #ifdef SHARED
       /* Auditing checkpoint: we are going to add new objects.  */
-      if (__builtin_expect (GLRO(dl_naudit) > 0, 0))
+      if ((mode & __RTLD_AUDIT) == 0
+         && __glibc_unlikely (GLRO(dl_naudit) > 0))
        {
          struct link_map *head = GL(dl_ns)[nsid]._ns_loaded;
          /* Do not call the functions for any auditing object.  */
@@ -963,6 +932,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
         linking has not been used before.  */
       r->r_state = RT_ADD;
       _dl_debug_state ();
+      LIBC_PROBE (map_start, 2, nsid, r);
       make_consistent = true;
     }
   else
@@ -970,7 +940,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 
   /* Enter the new object in the list of loaded objects.  */
   l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
-  if (__builtin_expect (l == NULL, 0))
+  if (__glibc_unlikely (l == NULL))
     {
 #ifdef SHARED
     fail_new:
@@ -999,17 +969,14 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
        }
     }
 
-  /* Presumed absent PT_GNU_STACK.  */
-  uint_fast16_t stack_flags = PF_R|PF_W|PF_X;
+   /* On most platforms presume that PT_GNU_STACK is absent and the stack is
+    * executable.  Other platforms default to a nonexecutable stack and don't
+    * need PT_GNU_STACK to do so.  */
+   uint_fast16_t stack_flags = DEFAULT_STACK_PERMS;
 
   {
     /* Scan the program header table, collecting its load commands.  */
-    struct loadcmd
-      {
-       ElfW(Addr) mapstart, mapend, dataend, allocend;
-       off_t mapoff;
-       int prot;
-      } loadcmds[l->l_phnum], *c;
+    struct loadcmd loadcmds[l->l_phnum];
     size_t nloadcmds = 0;
     bool has_holes = false;
 
@@ -1024,8 +991,14 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
             segments are mapped in.  We record the addresses it says
             verbatim, and later correct for the run-time load address.  */
        case PT_DYNAMIC:
-         l->l_ld = (void *) ph->p_vaddr;
-         l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+         if (ph->p_filesz)
+           {
+             /* Debuginfo only files from "objcopy --only-keep-debug"
+                contain a PT_DYNAMIC segment with p_filesz == 0.  Skip
+                such a segment to avoid a crash later.  */
+             l->l_ld = (void *) ph->p_vaddr;
+             l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
+           }
          break;
 
        case PT_PHDR:
@@ -1035,27 +1008,25 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
        case PT_LOAD:
          /* A load command tells us to map in part of the file.
             We record the load commands and process them all later.  */
-         if (__builtin_expect ((ph->p_align & (GLRO(dl_pagesize) - 1)) != 0,
-                               0))
+         if (__glibc_unlikely ((ph->p_align & (GLRO(dl_pagesize) - 1)) != 0))
            {
              errstring = N_("ELF load command alignment not page-aligned");
              goto call_lose;
            }
-         if (__builtin_expect (((ph->p_vaddr - ph->p_offset)
-                                & (ph->p_align - 1)) != 0, 0))
+         if (__glibc_unlikely (((ph->p_vaddr - ph->p_offset)
+                                & (ph->p_align - 1)) != 0))
            {
              errstring
                = N_("ELF load command address/offset not properly aligned");
              goto call_lose;
            }
 
-         c = &loadcmds[nloadcmds++];
-         c->mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
-         c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1)
-                      & ~(GLRO(dl_pagesize) - 1));
+         struct loadcmd *c = &loadcmds[nloadcmds++];
+         c->mapstart = ALIGN_DOWN (ph->p_vaddr, GLRO(dl_pagesize));
+         c->mapend = ALIGN_UP (ph->p_vaddr + ph->p_filesz, GLRO(dl_pagesize));
          c->dataend = ph->p_vaddr + ph->p_filesz;
          c->allocend = ph->p_vaddr + ph->p_memsz;
-         c->mapoff = ph->p_offset & ~(GLRO(dl_pagesize) - 1);
+         c->mapoff = ALIGN_DOWN (ph->p_offset, GLRO(dl_pagesize));
 
          /* Determine whether there is a gap between the last segment
             and this one.  */
@@ -1095,10 +1066,10 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 
          /* If not loading the initial set of shared libraries,
             check whether we should permit loading a TLS segment.  */
-         if (__builtin_expect (l->l_type == lt_library, 1)
+         if (__glibc_likely (l->l_type == lt_library)
              /* If GL(dl_tls_dtv_slotinfo_list) == NULL, then rtld.c did
                 not set up TLS data structures, so don't use them now.  */
-             || __builtin_expect (GL(dl_tls_dtv_slotinfo_list) != NULL, 1))
+             || __glibc_likely (GL(dl_tls_dtv_slotinfo_list) != NULL))
            {
              /* Assign the next available module ID.  */
              l->l_tls_modid = _dl_next_tls_modid ();
@@ -1106,53 +1077,14 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
            }
 
 #ifdef SHARED
-         if (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0)
-           /* We are loading the executable itself when the dynamic linker
-              was executed directly.  The setup will happen later.  */
-           break;
-
-         /* In a static binary there is no way to tell if we dynamically
-            loaded libpthread.  */
-         if (GL(dl_error_catch_tsd) == &_dl_initial_error_catch_tsd)
+         /* We are loading the executable itself when the dynamic
+            linker was executed directly.  The setup will happen
+            later.  Otherwise, the TLS data structures are already
+            initialized, and we assigned a TLS modid above.  */
+         assert (l->l_prev == NULL || (mode & __RTLD_AUDIT) != 0);
+#else
+         assert (false && "TLS not initialized in static application");
 #endif
-           {
-             /* We have not yet loaded libpthread.
-                We can do the TLS setup right now!  */
-
-             void *tcb;
-
-             /* The first call allocates TLS bookkeeping data structures.
-                Then we allocate the TCB for the initial thread.  */
-             if (__builtin_expect (_dl_tls_setup (), 0)
-                 || __builtin_expect ((tcb = _dl_allocate_tls (NULL)) == NULL,
-                                      0))
-               {
-                 errval = ENOMEM;
-                 errstring = N_("\
-cannot allocate TLS data structures for initial thread");
-                 goto call_lose;
-               }
-
-             /* Now we install the TCB in the thread register.  */
-             errstring = TLS_INIT_TP (tcb, 0);
-             if (__builtin_expect (errstring == NULL, 1))
-               {
-                 /* Now we are all good.  */
-                 l->l_tls_modid = ++GL(dl_tls_max_dtv_idx);
-                 break;
-               }
-
-             /* The kernel is too old or somesuch.  */
-             errval = 0;
-             _dl_deallocate_tls (tcb, 1);
-             goto call_lose;
-           }
-
-         /* Uh-oh, the binary expects TLS support but we cannot
-            provide it.  */
-         errval = 0;
-         errstring = N_("cannot handle TLS data");
-         goto call_lose;
          break;
 
        case PT_GNU_STACK:
@@ -1165,7 +1097,7 @@ cannot allocate TLS data structures for initial thread");
          break;
        }
 
-    if (__builtin_expect (nloadcmds == 0, 0))
+    if (__glibc_unlikely (nloadcmds == 0))
       {
        /* This only happens for a bogus object that will be caught with
           another error below.  But we don't want to go through the
@@ -1174,158 +1106,31 @@ cannot allocate TLS data structures for initial thread");
        goto call_lose;
       }
 
-    /* Now process the load commands and map segments into memory.  */
-    c = loadcmds;
-
-    /* Length of the sections to be loaded.  */
-    maplength = loadcmds[nloadcmds - 1].allocend - c->mapstart;
-
-    if (__builtin_expect (type, ET_DYN) == ET_DYN)
-      {
-       /* This is a position-independent shared object.  We can let the
-          kernel map it anywhere it likes, but we must have space for all
-          the segments in their specified positions relative to the first.
-          So we map the first segment without MAP_FIXED, but with its
-          extent increased to cover all the segments.  Then we remove
-          access from excess portion, and there is known sufficient space
-          there to remap from the later segments.
-
-          As a refinement, sometimes we have an address that we would
-          prefer to map such objects at; but this is only a preference,
-          the OS can do whatever it likes. */
-       ElfW(Addr) mappref;
-       mappref = (ELF_PREFERRED_ADDRESS (loader, maplength,
-                                         c->mapstart & GLRO(dl_use_load_bias))
-                  - MAP_BASE_ADDR (l));
-
-       /* Remember which part of the address space this object uses.  */
-       l->l_map_start = (ElfW(Addr)) __mmap ((void *) mappref, maplength,
-                                             c->prot,
-                                             MAP_COPY|MAP_FILE,
-                                             fd, c->mapoff);
-       if (__builtin_expect ((void *) l->l_map_start == MAP_FAILED, 0))
-         {
-         map_error:
-           errstring = N_("failed to map segment from shared object");
-           goto call_lose_errno;
-         }
-
-       l->l_map_end = l->l_map_start + maplength;
-       l->l_addr = l->l_map_start - c->mapstart;
-
-       if (has_holes)
-         /* Change protection on the excess portion to disallow all access;
-            the portions we do not remap later will be inaccessible as if
-            unallocated.  Then jump into the normal segment-mapping loop to
-            handle the portion of the segment past the end of the file
-            mapping.  */
-         __mprotect ((caddr_t) (l->l_addr + c->mapend),
-                     loadcmds[nloadcmds - 1].mapstart - c->mapend,
-                     PROT_NONE);
-
-       l->l_contiguous = 1;
-
-       goto postmap;
-      }
-
-    /* This object is loaded at a fixed address.  This must never
-       happen for objects loaded with dlopen().  */
-    if (__builtin_expect ((mode & __RTLD_OPENEXEC) == 0, 0))
+    if (__glibc_unlikely (type != ET_DYN)
+       && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
       {
+       /* This object is loaded at a fixed address.  This must never
+          happen for objects loaded with dlopen.  */
        errstring = N_("cannot dynamically load executable");
        goto call_lose;
       }
 
-    /* Notify ELF_PREFERRED_ADDRESS that we have to load this one
-       fixed.  */
-    ELF_FIXED_ADDRESS (loader, c->mapstart);
-
-
-    /* Remember which part of the address space this object uses.  */
-    l->l_map_start = c->mapstart + l->l_addr;
-    l->l_map_end = l->l_map_start + maplength;
-    l->l_contiguous = !has_holes;
-
-    while (c < &loadcmds[nloadcmds])
-      {
-       if (c->mapend > c->mapstart
-           /* Map the segment contents from the file.  */
-           && (__mmap ((void *) (l->l_addr + c->mapstart),
-                       c->mapend - c->mapstart, c->prot,
-                       MAP_FIXED|MAP_COPY|MAP_FILE,
-                       fd, c->mapoff)
-               == MAP_FAILED))
-         goto map_error;
-
-      postmap:
-       if (c->prot & PROT_EXEC)
-         l->l_text_end = l->l_addr + c->mapend;
-
-       if (l->l_phdr == 0
-           && (ElfW(Off)) c->mapoff <= header->e_phoff
-           && ((size_t) (c->mapend - c->mapstart + c->mapoff)
-               >= header->e_phoff + header->e_phnum * sizeof (ElfW(Phdr))))
-         /* Found the program header in this segment.  */
-         l->l_phdr = (void *) (c->mapstart + header->e_phoff - c->mapoff);
-
-       if (c->allocend > c->dataend)
-         {
-           /* Extra zero pages should appear at the end of this segment,
-              after the data mapped from the file.   */
-           ElfW(Addr) zero, zeroend, zeropage;
-
-           zero = l->l_addr + c->dataend;
-           zeroend = l->l_addr + c->allocend;
-           zeropage = ((zero + GLRO(dl_pagesize) - 1)
-                       & ~(GLRO(dl_pagesize) - 1));
-
-           if (zeroend < zeropage)
-             /* All the extra data is in the last page of the segment.
-                We can just zero it.  */
-             zeropage = zeroend;
-
-           if (zeropage > zero)
-             {
-               /* Zero the final part of the last page of the segment.  */
-               if (__builtin_expect ((c->prot & PROT_WRITE) == 0, 0))
-                 {
-                   /* Dag nab it.  */
-                   if (__mprotect ((caddr_t) (zero
-                                              & ~(GLRO(dl_pagesize) - 1)),
-                                   GLRO(dl_pagesize), c->prot|PROT_WRITE) < 0)
-                     {
-                       errstring = N_("cannot change memory protections");
-                       goto call_lose_errno;
-                     }
-                 }
-               memset ((void *) zero, '\0', zeropage - zero);
-               if (__builtin_expect ((c->prot & PROT_WRITE) == 0, 0))
-                 __mprotect ((caddr_t) (zero & ~(GLRO(dl_pagesize) - 1)),
-                             GLRO(dl_pagesize), c->prot);
-             }
-
-           if (zeroend > zeropage)
-             {
-               /* Map the remaining zero pages in from the zero fill FD.  */
-               caddr_t mapat;
-               mapat = __mmap ((caddr_t) zeropage, zeroend - zeropage,
-                               c->prot, MAP_ANON|MAP_PRIVATE|MAP_FIXED,
-                               ANONFD, 0);
-               if (__builtin_expect (mapat == MAP_FAILED, 0))
-                 {
-                   errstring = N_("cannot map zero-fill pages");
-                   goto call_lose_errno;
-                 }
-             }
-         }
-
-       ++c;
-      }
+    /* Length of the sections to be loaded.  */
+    maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
+
+    /* Now process the load commands and map segments into memory.
+       This is responsible for filling in:
+       l_map_start, l_map_end, l_addr, l_contiguous, l_text_end, l_phdr
+     */
+    errstring = _dl_map_segments (l, fd, header, type, loadcmds, nloadcmds,
+                                 maplength, has_holes, loader);
+    if (__glibc_unlikely (errstring != NULL))
+      goto call_lose;
   }
 
   if (l->l_ld == 0)
     {
-      if (__builtin_expect (type == ET_DYN, 0))
+      if (__glibc_unlikely (type == ET_DYN))
        {
          errstring = N_("object file has no dynamic section");
          goto call_lose;
@@ -1338,11 +1143,11 @@ cannot allocate TLS data structures for initial thread");
 
   /* Make sure we are not dlopen'ing an object that has the
      DF_1_NOOPEN flag set.  */
-  if (__builtin_expect (l->l_flags_1 & DF_1_NOOPEN, 0)
+  if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
       && (mode & __RTLD_DLOPEN))
     {
       /* We are not supposed to load this object.  Free all resources.  */
-      __munmap ((void *) l->l_map_start, l->l_map_end - l->l_map_start);
+      _dl_unmap_segments (l);
 
       if (!l->l_libname->dont_free)
        free (l->l_libname);
@@ -1375,15 +1180,8 @@ cannot allocate TLS data structures for initial thread");
     /* Adjust the PT_PHDR value by the runtime load address.  */
     l->l_phdr = (ElfW(Phdr) *) ((ElfW(Addr)) l->l_phdr + l->l_addr);
 
-  if (__builtin_expect ((stack_flags &~ GL(dl_stack_flags)) & PF_X, 0))
+  if (__glibc_unlikely ((stack_flags &~ GL(dl_stack_flags)) & PF_X))
     {
-      if (__builtin_expect (__check_caller (RETURN_ADDRESS (0), allow_ldso),
-                           0) != 0)
-       {
-         errstring = N_("invalid caller");
-         goto call_lose;
-       }
-
       /* The stack is presently not executable, but this module
         requires that it be executable.  We must change the
         protection of the variable which contains the flags used in
@@ -1398,10 +1196,14 @@ cannot allocate TLS data structures for initial thread");
          const uintptr_t relro_end = ((m->l_addr + m->l_relro_addr
                                        + m->l_relro_size)
                                       & -GLRO(dl_pagesize));
-         if (__builtin_expect (p + s <= relro_end, 1))
+         if (__glibc_likely (p + s <= relro_end))
            {
              /* The variable lies in the region protected by RELRO.  */
-             __mprotect ((void *) p, s, PROT_READ|PROT_WRITE);
+             if (__mprotect ((void *) p, s, PROT_READ|PROT_WRITE) < 0)
+               {
+                 errstring = N_("cannot change memory protections");
+                 goto call_lose_errno;
+               }
              __stack_prot |= PROT_READ|PROT_WRITE|PROT_EXEC;
              __mprotect ((void *) p, s, PROT_READ);
            }
@@ -1430,7 +1232,7 @@ cannot enable executable stack as shared object requires");
     l->l_tls_initimage = (char *) l->l_tls_initimage + l->l_addr;
 
   /* We are done mapping in the file.  We no longer need the descriptor.  */
-  if (__builtin_expect (__close (fd) != 0, 0))
+  if (__glibc_unlikely (__close (fd) != 0))
     {
       errstring = N_("cannot close file descriptor");
       goto call_lose_errno;
@@ -1438,12 +1240,12 @@ cannot enable executable stack as shared object requires");
   /* Signal that we closed the file.  */
   fd = -1;
 
-  if (l->l_type == lt_library && type == ET_EXEC)
-    l->l_type = lt_executable;
+  /* If this is ET_EXEC, we should have loaded it as lt_executable.  */
+  assert (type != ET_EXEC || l->l_type == lt_executable);
 
   l->l_entry += l->l_addr;
 
-  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
+  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
     _dl_debug_printf ("\
   dynamic: 0x%0*lx  base: 0x%0*lx   size: 0x%0*Zx\n\
     entry: 0x%0*lx  phdr: 0x%0*lx  phnum:   %*u\n\n",
@@ -1464,20 +1266,11 @@ cannot enable executable stack as shared object requires");
   /* If this object has DT_SYMBOLIC set modify now its scope.  We don't
      have to do this for the main map.  */
   if ((mode & RTLD_DEEPBIND) == 0
-      && __builtin_expect (l->l_info[DT_SYMBOLIC] != NULL, 0)
+      && __glibc_unlikely (l->l_info[DT_SYMBOLIC] != NULL)
       && &l->l_searchlist != l->l_scope[0])
     {
       /* Create an appropriate searchlist.  It contains only this map.
         This is the definition of DT_SYMBOLIC in SysVr4.  */
-      l->l_symbolic_searchlist.r_list =
-       (struct link_map **) malloc (sizeof (struct link_map *));
-
-      if (l->l_symbolic_searchlist.r_list == NULL)
-       {
-         errstring = N_("cannot create searchlist");
-         goto call_lose_errno;
-       }
-
       l->l_symbolic_searchlist.r_list[0] = l;
       l->l_symbolic_searchlist.r_nlist = 1;
 
@@ -1494,19 +1287,36 @@ cannot enable executable stack as shared object requires");
     GL(dl_initfirst) = l;
 
   /* Finally the file information.  */
-  l->l_dev = st.st_dev;
-  l->l_ino = st.st_ino;
+  l->l_file_id = id;
+
+#ifdef SHARED
+  /* When auditing is used the recorded names might not include the
+     name by which the DSO is actually known.  Add that as well.  */
+  if (__glibc_unlikely (origname != NULL))
+    add_name_to_object (l, origname);
+#else
+  /* Audit modules only exist when linking is dynamic so ORIGNAME
+     cannot be non-NULL.  */
+  assert (origname == NULL);
+#endif
 
   /* When we profile the SONAME might be needed for something else but
      loading.  Add it right away.  */
-  if (__builtin_expect (GLRO(dl_profile) != NULL, 0)
+  if (__glibc_unlikely (GLRO(dl_profile) != NULL)
       && l->l_info[DT_SONAME] != NULL)
     add_name_to_object (l, ((const char *) D_PTR (l, l_info[DT_STRTAB])
                            + l->l_info[DT_SONAME]->d_un.d_val));
 
+#ifdef DL_AFTER_LOAD
+  DL_AFTER_LOAD (l);
+#endif
+
+  /* Now that the object is fully initialized add it to the object list.  */
+  _dl_add_to_namespace_list (l, nsid);
+
 #ifdef SHARED
   /* Auditing checkpoint: we have a new object.  */
-  if (__builtin_expect (GLRO(dl_naudit) > 0, 0)
+  if (__glibc_unlikely (GLRO(dl_naudit) > 0)
       && !GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing)
     {
       struct audit_ifaces *afct = GLRO(dl_audit);
@@ -1531,7 +1341,7 @@ cannot enable executable stack as shared object requires");
 /* Print search path.  */
 static void
 print_search_path (struct r_search_path_elem **list,
-                   const char *what, const char *name)
+                  const char *what, const char *name)
 {
   char buf[max_dirnamelen + max_capstrlen];
   int first = 1;
@@ -1561,7 +1371,7 @@ print_search_path (struct r_search_path_elem **list,
 
   if (name != NULL)
     _dl_debug_printf_c ("\t\t(%s from file %s)\n", what,
-                       name[0] ? name : rtld_progname);
+                       DSO_FILENAME (name));
   else
     _dl_debug_printf_c ("\t\t(%s)\n", what);
 }
@@ -1570,10 +1380,14 @@ print_search_path (struct r_search_path_elem **list,
    ignore only ELF files for other architectures.  Non-ELF files and
    ELF files with different header information cause fatal errors since
    this could mean there is something wrong in the installation and the
-   user might want to know about this.  */
+   user might want to know about this.
+
+   If FD is not -1, then the file is already open and FD refers to it.
+   In that case, FD is consumed for both successful and error returns.  */
 static int
-open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
-            int whatcode, bool *found_other_class, bool free_name)
+open_verify (const char *name, int fd,
+             struct filebuf *fbp, struct link_map *loader,
+            int whatcode, int mode, bool *found_other_class, bool free_name)
 {
   /* This is the expected ELF header.  */
 #define ELF32_CLASS ELFCLASS32
@@ -1581,9 +1395,11 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 #ifndef VALID_ELF_HEADER
 # define VALID_ELF_HEADER(hdr,exp,size)        (memcmp (hdr, exp, size) == 0)
 # define VALID_ELF_OSABI(osabi)                (osabi == ELFOSABI_SYSV)
-# define VALID_ELF_ABIVERSION(ver)     (ver == 0)
+# define VALID_ELF_ABIVERSION(osabi,ver) (ver == 0)
+#elif defined MORE_ELF_HEADER_DATA
+  MORE_ELF_HEADER_DATA;
 #endif
-  static const unsigned char expected[EI_PAD] =
+  static const unsigned char expected[EI_NIDENT] =
   {
     [EI_MAG0] = ELFMAG0,
     [EI_MAG1] = ELFMAG1,
@@ -1608,9 +1424,10 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 
 #ifdef SHARED
   /* Give the auditing libraries a chance.  */
-  if (__builtin_expect (GLRO(dl_naudit) > 0, 0) && whatcode != 0
+  if (__glibc_unlikely (GLRO(dl_naudit) > 0) && whatcode != 0
       && loader->l_auditing == 0)
     {
+      const char *original_name = name;
       struct audit_ifaces *afct = GLRO(dl_audit);
       for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
        {
@@ -1625,30 +1442,51 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 
          afct = afct->next;
        }
+
+      if (fd != -1 && name != original_name && strcmp (name, original_name))
+        {
+          /* An audit library changed what we're supposed to open,
+             so FD no longer matches it.  */
+          __close (fd);
+          fd = -1;
+        }
     }
 #endif
 
-  /* Open the file.  We always open files read-only.  */
-  int fd = __open (name, O_RDONLY);
+  if (fd == -1)
+    /* Open the file.  We always open files read-only.  */
+    fd = __open (name, O_RDONLY | O_CLOEXEC);
+
   if (fd != -1)
     {
       ElfW(Ehdr) *ehdr;
       ElfW(Phdr) *phdr, *ph;
-      ElfW(Word) *abi_note, abi_note_buf[8];
+      ElfW(Word) *abi_note;
+      ElfW(Word) *abi_note_malloced = NULL;
       unsigned int osversion;
       size_t maplength;
 
-      /* We successfully openened the file.  Now verify it is a file
+      /* We successfully opened the file.  Now verify it is a file
         we can use.  */
       __set_errno (0);
-      fbp->len = __libc_read (fd, fbp->buf, sizeof (fbp->buf));
+      fbp->len = 0;
+      assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
+      /* Read in the header.  */
+      do
+       {
+         ssize_t retlen = __libc_read (fd, fbp->buf + fbp->len,
+                                       sizeof (fbp->buf) - fbp->len);
+         if (retlen <= 0)
+           break;
+         fbp->len += retlen;
+       }
+      while (__glibc_unlikely (fbp->len < sizeof (ElfW(Ehdr))));
 
       /* This is where the ELF header is loaded.  */
-      assert (sizeof (fbp->buf) > sizeof (ElfW(Ehdr)));
       ehdr = (ElfW(Ehdr) *) fbp->buf;
 
       /* Now run the tests.  */
-      if (__builtin_expect (fbp->len < (ssize_t) sizeof (ElfW(Ehdr)), 0))
+      if (__glibc_unlikely (fbp->len < (ssize_t) sizeof (ElfW(Ehdr))))
        {
          errval = errno;
          errstring = (errval == 0
@@ -1660,15 +1498,21 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
              name = strdupa (realname);
              free (realname);
            }
-         lose (errval, fd, name, NULL, NULL, errstring, NULL);
+         lose (errval, fd, name, NULL, NULL, errstring, NULL, 0);
        }
 
       /* See whether the ELF header is what we expect.  */
-      if (__builtin_expect (! VALID_ELF_HEADER (ehdr->e_ident, expected,
-                                               EI_PAD), 0))
+      if (__glibc_unlikely (! VALID_ELF_HEADER (ehdr->e_ident, expected,
+                                               EI_ABIVERSION)
+                           || !VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
+                                                     ehdr->e_ident[EI_ABIVERSION])
+                           || memcmp (&ehdr->e_ident[EI_PAD],
+                                      &expected[EI_PAD],
+                                      EI_NIDENT - EI_PAD) != 0))
        {
          /* Something is wrong.  */
-         if (*(Elf32_Word *) &ehdr->e_ident !=
+         const Elf32_Word *magp = (const void *) ehdr->e_ident;
+         if (*magp !=
 #if BYTE_ORDER == LITTLE_ENDIAN
              ((ELFMAG0 << (EI_MAG0 * 8)) |
               (ELFMAG1 << (EI_MAG1 * 8)) |
@@ -1704,8 +1548,12 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
             allowed here.  */
          else if (!VALID_ELF_OSABI (ehdr->e_ident[EI_OSABI]))
            errstring = N_("ELF file OS ABI invalid");
-         else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_ABIVERSION]))
+         else if (!VALID_ELF_ABIVERSION (ehdr->e_ident[EI_OSABI],
+                                         ehdr->e_ident[EI_ABIVERSION]))
            errstring = N_("ELF file ABI version invalid");
+         else if (memcmp (&ehdr->e_ident[EI_PAD], &expected[EI_PAD],
+                          EI_NIDENT - EI_PAD) != 0)
+           errstring = N_("nonzero padding in e_ident");
          else
            /* Otherwise we don't know what went wrong.  */
            errstring = N_("internal error");
@@ -1713,21 +1561,31 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
          goto call_lose;
        }
 
-      if (__builtin_expect (ehdr->e_version, EV_CURRENT) != EV_CURRENT)
+      if (__glibc_unlikely (ehdr->e_version != EV_CURRENT))
        {
          errstring = N_("ELF file version does not match current one");
          goto call_lose;
        }
-      if (! __builtin_expect (elf_machine_matches_host (ehdr), 1))
+      if (! __glibc_likely (elf_machine_matches_host (ehdr)))
        goto close_and_out;
-      else if (__builtin_expect (ehdr->e_type, ET_DYN) != ET_DYN
-              && __builtin_expect (ehdr->e_type, ET_EXEC) != ET_EXEC)
+      else if (__glibc_unlikely (ehdr->e_type != ET_DYN
+                                && ehdr->e_type != ET_EXEC))
        {
          errstring = N_("only ET_DYN and ET_EXEC can be loaded");
          goto call_lose;
        }
-      else if (__builtin_expect (ehdr->e_phentsize, sizeof (ElfW(Phdr)))
-              != sizeof (ElfW(Phdr)))
+      else if (__glibc_unlikely (ehdr->e_type == ET_EXEC
+                                && (mode & __RTLD_OPENEXEC) == 0))
+       {
+         /* BZ #16634. It is an error to dlopen ET_EXEC (unless
+            __RTLD_OPENEXEC is explicitly set).  We return error here
+            so that code in _dl_map_object_from_fd does not try to set
+            l_tls_modid for this module.  */
+
+         errstring = N_("cannot dynamically load executable");
+         goto call_lose;
+       }
+      else if (__glibc_unlikely (ehdr->e_phentsize != sizeof (ElfW(Phdr))))
        {
          errstring = N_("ELF file's phentsize not the expected size");
          goto call_lose;
@@ -1749,22 +1607,70 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
            }
        }
 
+      if (__glibc_unlikely (elf_machine_reject_phdr_p
+                           (phdr, ehdr->e_phnum, fbp->buf, fbp->len,
+                            loader, fd)))
+       goto close_and_out;
+
       /* Check .note.ABI-tag if present.  */
       for (ph = phdr; ph < &phdr[ehdr->e_phnum]; ++ph)
-       if (ph->p_type == PT_NOTE && ph->p_filesz == 32 && ph->p_align >= 4)
+       if (ph->p_type == PT_NOTE && ph->p_filesz >= 32 && ph->p_align >= 4)
          {
-           if (ph->p_offset + 32 <= (size_t) fbp->len)
+           ElfW(Addr) size = ph->p_filesz;
+           /* NB: Some PT_NOTE segment may have alignment value of 0
+              or 1.  gABI specifies that PT_NOTE segments should be
+              aligned to 4 bytes in 32-bit objects and to 8 bytes in
+              64-bit objects.  As a Linux extension, we also support
+              4 byte alignment in 64-bit objects.  If p_align is less
+              than 4, we treate alignment as 4 bytes since some note
+              segments have 0 or 1 byte alignment.   */
+           ElfW(Addr) align = ph->p_align;
+           if (align < 4)
+             align = 4;
+           else if (align != 4 && align != 8)
+             continue;
+
+           if (ph->p_offset + size <= (size_t) fbp->len)
              abi_note = (void *) (fbp->buf + ph->p_offset);
            else
              {
+               /* Note: __libc_use_alloca is not usable here, because
+                  thread info may not have been set up yet.  */
+               if (size < __MAX_ALLOCA_CUTOFF)
+                 abi_note = alloca (size);
+               else
+                 {
+                   /* There could be multiple PT_NOTEs.  */
+                   abi_note_malloced = realloc (abi_note_malloced, size);
+                   if (abi_note_malloced == NULL)
+                     goto read_error;
+
+                   abi_note = abi_note_malloced;
+                 }
                __lseek (fd, ph->p_offset, SEEK_SET);
-               if (__libc_read (fd, (void *) abi_note_buf, 32) != 32)
-                 goto read_error;
+               if (__libc_read (fd, (void *) abi_note, size) != size)
+                 {
+                   free (abi_note_malloced);
+                   goto read_error;
+                 }
+             }
 
-               abi_note = abi_note_buf;
+           while (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+             {
+               ElfW(Addr) note_size
+                 = ELF_NOTE_NEXT_OFFSET (abi_note[0], abi_note[1],
+                                         align);
+
+               if (size - 32 < note_size)
+                 {
+                   size = 0;
+                   break;
+                 }
+               size -= note_size;
+               abi_note = (void *) abi_note + note_size;
              }
 
-           if (memcmp (abi_note, &expected_note, sizeof (expected_note)))
+           if (size == 0)
              continue;
 
            osversion = (abi_note[5] & 0xff) * 65536
@@ -1781,6 +1687,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
 
            break;
          }
+      free (abi_note_malloced);
     }
 
   return fd;
@@ -1794,7 +1701,7 @@ open_verify (const char *name, struct filebuf *fbp, struct link_map *loader,
    if MAY_FREE_DIRS is true.  */
 
 static int
-open_path (const char *name, size_t namelen, int preloaded,
+open_path (const char *name, size_t namelen, int mode,
           struct r_search_path_struct *sps, char **realname,
           struct filebuf *fbp, struct link_map *loader, int whatcode,
           bool *found_other_class)
@@ -1805,7 +1712,7 @@ open_path (const char *name, size_t namelen, int preloaded,
   const char *current_what = NULL;
   int any = 0;
 
-  if (__builtin_expect (dirs == NULL, 0))
+  if (__glibc_unlikely (dirs == NULL))
     /* We're called before _dl_init_paths when loading the main executable
        given on the command line when rtld is run directly.  */
     return -1;
@@ -1822,7 +1729,7 @@ open_path (const char *name, size_t namelen, int preloaded,
 
       /* If we are debugging the search for libraries print the path
         now if it hasn't happened now.  */
-      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0)
+      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS)
          && current_what != this_dir->what)
        {
          current_what = this_dir->what;
@@ -1843,11 +1750,11 @@ open_path (const char *name, size_t namelen, int preloaded,
             - buf);
 
          /* Print name we try if this is wanted.  */
-         if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
+         if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
            _dl_debug_printf ("  trying file=%s\n", buf);
 
-         fd = open_verify (buf, fbp, loader, whatcode, found_other_class,
-                           false);
+         fd = open_verify (buf, -1, fbp, loader, whatcode, mode,
+                           found_other_class, false);
          if (this_dir->status[cnt] == unknown)
            {
              if (fd != -1)
@@ -1876,8 +1783,8 @@ open_path (const char *name, size_t namelen, int preloaded,
          /* Remember whether we found any existing directory.  */
          here_any |= this_dir->status[cnt] != nonexisting;
 
-         if (fd != -1 && __builtin_expect (preloaded, 0)
-             && INTUSE(__libc_enable_secure))
+         if (fd != -1 && __glibc_unlikely (mode & __RTLD_SECURE)
+             && __libc_enable_secure)
            {
              /* This is an extra security effort to make sure nobody can
                 preload broken shared objects which are in the trusted
@@ -1925,16 +1832,16 @@ open_path (const char *name, size_t namelen, int preloaded,
   while (*++dirs != NULL);
 
   /* Remove the whole path if none of the directories exists.  */
-  if (__builtin_expect (! any, 0))
+  if (__glibc_unlikely (! any))
     {
       /* Paths which were allocated using the minimal malloc() in ld.so
         must not be freed using the general free() in libc.  */
       if (sps->malloced)
        free (sps->dirs);
 
-      /* rtld_search_dirs is attribute_relro, therefore avoid writing
-        into it.  */
-      if (sps != &rtld_search_dirs)
+      /* rtld_search_dirs and env_path_list are attribute_relro, therefore
+        avoid writing into it.  */
+      if (sps != &rtld_search_dirs && sps != &env_path_list)
        sps->dirs = (void *) -1;
     }
 
@@ -1944,18 +1851,18 @@ open_path (const char *name, size_t namelen, int preloaded,
 /* Map in the shared object file NAME.  */
 
 struct link_map *
-internal_function
-_dl_map_object (struct link_map *loader, const char *name, int preloaded,
+_dl_map_object (struct link_map *loader, const char *name,
                int type, int trace_mode, int mode, Lmid_t nsid)
 {
   int fd;
+  const char *origname = NULL;
   char *realname;
   char *name_copy;
   struct link_map *l;
   struct filebuf fb;
 
   assert (nsid >= 0);
-  assert (nsid < DL_NNS);
+  assert (nsid < GL(dl_nns));
 
   /* Look for this name among those already loaded.  */
   for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
@@ -1963,14 +1870,13 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       /* If the requested name matches the soname of a loaded object,
         use that object.  Elide this check for names that have not
         yet been opened.  */
-      if (__builtin_expect (l->l_faked, 0) != 0
-         || __builtin_expect (l->l_removed, 0) != 0)
+      if (__glibc_unlikely ((l->l_faked | l->l_removed) != 0))
        continue;
       if (!_dl_name_match_p (name, l))
        {
          const char *soname;
 
-         if (__builtin_expect (l->l_soname_added, 1)
+         if (__glibc_likely (l->l_soname_added)
              || l->l_info[DT_SONAME] == NULL)
            continue;
 
@@ -1989,16 +1895,17 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
     }
 
   /* Display information if we are debugging.  */
-  if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
+  if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES)
       && loader != NULL)
-    _dl_debug_printf ("\nfile=%s [%lu];  needed by %s [%lu]\n", name, nsid,
-                             loader->l_name[0]
-                             ? loader->l_name : rtld_progname, loader->l_ns);
+    _dl_debug_printf ((mode & __RTLD_CALLMAP) == 0
+                     ? "\nfile=%s [%lu];  needed by %s [%lu]\n"
+                     : "\nfile=%s [%lu];  dynamically loaded by %s [%lu]\n",
+                     name, nsid, DSO_FILENAME (loader->l_name), loader->l_ns);
 
 #ifdef SHARED
   /* Give the auditing libraries a chance to change the name before we
      try anything.  */
-  if (__builtin_expect (GLRO(dl_naudit) > 0, 0)
+  if (__glibc_unlikely (GLRO(dl_naudit) > 0)
       && (loader == NULL || loader->l_auditing == 0))
     {
       struct audit_ifaces *afct = GLRO(dl_audit);
@@ -2006,6 +1913,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
        {
          if (afct->objsearch != NULL)
            {
+             const char *before = name;
              name = afct->objsearch (name, &loader->l_audit[cnt].cookie,
                                      LA_SER_ORIG);
              if (name == NULL)
@@ -2014,6 +1922,15 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
                  fd = -1;
                  goto no_file;
                }
+             if (before != name && strcmp (before, name) != 0)
+               {
+                 if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_FILES))
+                   _dl_debug_printf ("audit changed filename %s -> %s\n",
+                                     before, name);
+
+                 if (origname == NULL)
+                   origname = before;
+               }
            }
 
          afct = afct->next;
@@ -2030,13 +1947,13 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
       size_t namelen = strlen (name) + 1;
 
-      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
+      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
        _dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
 
       fd = -1;
 
       /* When the object has the RUNPATH information we don't use any
-         RPATHs.  */
+        RPATHs.  */
       if (loader == NULL || loader->l_info[DT_RUNPATH] == NULL)
        {
          /* This is the executable's map (if there is one).  Make sure that
@@ -2049,7 +1966,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
          for (l = loader; l; l = l->l_loader)
            if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
              {
-               fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
+               fd = open_path (name, namelen, mode,
+                               &l->l_rpath_dirs,
                                &realname, &fb, loader, LA_SER_RUNPATH,
                                &found_other_class);
                if (fd != -1)
@@ -2059,19 +1977,20 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
              }
 
          /* If dynamically linked, try the DT_RPATH of the executable
-             itself.  NB: we do this for lookups in any namespace.  */
+            itself.  NB: we do this for lookups in any namespace.  */
          if (fd == -1 && !did_main_map
              && main_map != NULL && main_map->l_type != lt_loaded
              && cache_rpath (main_map, &main_map->l_rpath_dirs, DT_RPATH,
                              "RPATH"))
-           fd = open_path (name, namelen, preloaded, &main_map->l_rpath_dirs,
+           fd = open_path (name, namelen, mode,
+                           &main_map->l_rpath_dirs,
                            &realname, &fb, loader ?: main_map, LA_SER_RUNPATH,
                            &found_other_class);
        }
 
       /* Try the LD_LIBRARY_PATH environment variable.  */
       if (fd == -1 && env_path_list.dirs != (void *) -1)
-       fd = open_path (name, namelen, preloaded, &env_path_list,
+       fd = open_path (name, namelen, mode, &env_path_list,
                        &realname, &fb,
                        loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded,
                        LA_SER_LIBPATH, &found_other_class);
@@ -2080,35 +1999,47 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       if (fd == -1 && loader != NULL
          && cache_rpath (loader, &loader->l_runpath_dirs,
                          DT_RUNPATH, "RUNPATH"))
-       fd = open_path (name, namelen, preloaded,
+       fd = open_path (name, namelen, mode,
                        &loader->l_runpath_dirs, &realname, &fb, loader,
                        LA_SER_RUNPATH, &found_other_class);
 
+      if (fd == -1)
+        {
+          realname = _dl_sysdep_open_object (name, namelen, &fd);
+          if (realname != NULL)
+            {
+              fd = open_verify (realname, fd,
+                                &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
+                                LA_SER_CONFIG, mode, &found_other_class,
+                                false);
+              if (fd == -1)
+                free (realname);
+            }
+        }
+
+#ifdef USE_LDCONFIG
       if (fd == -1
-         && (__builtin_expect (! preloaded, 1)
-             || ! INTUSE(__libc_enable_secure)))
+         && (__glibc_likely ((mode & __RTLD_SECURE) == 0)
+             || ! __libc_enable_secure)
+         && __glibc_likely (GLRO(dl_inhibit_cache) == 0))
        {
          /* Check the list of libraries in the file /etc/ld.so.cache,
             for compatibility with Linux's ldconfig program.  */
-         const char *cached = _dl_load_cache_lookup (name);
+         char *cached = _dl_load_cache_lookup (name);
 
          if (cached != NULL)
            {
-#ifdef SHARED
              // XXX Correct to unconditionally default to namespace 0?
-             l = loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-#else
-             l = loader;
-#endif
+             l = (loader
+                  ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded
+# ifdef SHARED
+                  ?: &GL(dl_rtld_map)
+# endif
+                 );
 
              /* If the loader has the DF_1_NODEFLIB flag set we must not
                 use a cache entry from any of these directories.  */
-             if (
-#ifndef SHARED
-                 /* 'l' is always != NULL for dynamically linked objects.  */
-                 l != NULL &&
-#endif
-                 __builtin_expect (l->l_flags_1 & DF_1_NODEFLIB, 0))
+             if (__glibc_unlikely (l->l_flags_1 & DF_1_NODEFLIB))
                {
                  const char *dirp = system_dirs;
                  unsigned int cnt = 0;
@@ -2118,6 +2049,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
                      if (memcmp (cached, dirp, system_dirs_len[cnt]) == 0)
                        {
                          /* The prefix matches.  Don't use the entry.  */
+                         free (cached);
                          cached = NULL;
                          break;
                        }
@@ -2130,48 +2062,45 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
              if (cached != NULL)
                {
-                 fd = open_verify (cached,
+                 fd = open_verify (cached, -1,
                                    &fb, loader ?: GL(dl_ns)[nsid]._ns_loaded,
-                                   LA_SER_CONFIG, &found_other_class, false);
-                 if (__builtin_expect (fd != -1, 1))
-                   {
-                     realname = local_strdup (cached);
-                     if (realname == NULL)
-                       {
-                         __close (fd);
-                         fd = -1;
-                       }
-                   }
+                                   LA_SER_CONFIG, mode, &found_other_class,
+                                   false);
+                 if (__glibc_likely (fd != -1))
+                   realname = cached;
+                 else
+                   free (cached);
                }
            }
        }
+#endif
 
       /* Finally, try the default path.  */
       if (fd == -1
          && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
-             || __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
+             || __glibc_likely (!(l->l_flags_1 & DF_1_NODEFLIB)))
          && rtld_search_dirs.dirs != (void *) -1)
-       fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
+       fd = open_path (name, namelen, mode, &rtld_search_dirs,
                        &realname, &fb, l, LA_SER_DEFAULT, &found_other_class);
 
       /* Add another newline when we are tracing the library loading.  */
-      if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
-        _dl_debug_printf ("\n");
+      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
+       _dl_debug_printf ("\n");
     }
   else
     {
       /* The path may contain dynamic string tokens.  */
       realname = (loader
                  ? expand_dynamic_string_token (loader, name)
-                 : local_strdup (name));
+                 : __strdup (name));
       if (realname == NULL)
        fd = -1;
       else
        {
-         fd = open_verify (realname, &fb,
-                           loader ?: GL(dl_ns)[nsid]._ns_loaded, 0,
+         fd = open_verify (realname, -1, &fb,
+                           loader ?: GL(dl_ns)[nsid]._ns_loaded, 0, mode,
                            &found_other_class, true);
-         if (__builtin_expect (fd, 0) == -1)
+         if (__glibc_unlikely (fd == -1))
            free (realname);
        }
     }
@@ -2185,10 +2114,10 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
   if (mode & __RTLD_CALLMAP)
     loader = NULL;
 
-  if (__builtin_expect (fd, 0) == -1)
+  if (__glibc_unlikely (fd == -1))
     {
       if (trace_mode
-         && __builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK, 0) == 0)
+         && __glibc_likely ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK) == 0))
        {
          /* We haven't found an appropriate library.  But since we
             are only interested in the list of libraries this isn't
@@ -2196,8 +2125,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
             have.  */
          static const Elf_Symndx dummy_bucket = STN_UNDEF;
 
-         /* Enter the new object in the list of loaded objects.  */
-         if ((name_copy = local_strdup (name)) == NULL
+         /* Allocate a new object map.  */
+         if ((name_copy = __strdup (name)) == NULL
              || (l = _dl_new_object (name_copy, name, type, loader,
                                      mode, nsid)) == NULL)
            {
@@ -2214,6 +2143,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
          l->l_nbuckets = 1;
          l->l_relocated = 1;
 
+         /* Enter the object in the object list.  */
+         _dl_add_to_namespace_list (l, nsid);
+
          return l;
        }
       else if (found_other_class)
@@ -2227,13 +2159,51 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
     }
 
   void *stack_end = __libc_stack_end;
-  return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
-                                &stack_end, nsid);
+  return _dl_map_object_from_fd (name, origname, fd, &fb, realname, loader,
+                                type, mode, &stack_end, nsid);
 }
 
+struct add_path_state
+{
+  bool counting;
+  unsigned int idx;
+  Dl_serinfo *si;
+  char *allocptr;
+};
+
+static void
+add_path (struct add_path_state *p, const struct r_search_path_struct *sps,
+         unsigned int flags)
+{
+  if (sps->dirs != (void *) -1)
+    {
+      struct r_search_path_elem **dirs = sps->dirs;
+      do
+       {
+         const struct r_search_path_elem *const r = *dirs++;
+         if (p->counting)
+           {
+             p->si->dls_cnt++;
+             p->si->dls_size += MAX (2, r->dirnamelen);
+           }
+         else
+           {
+             Dl_serpath *const sp = &p->si->dls_serpath[p->idx++];
+             sp->dls_name = p->allocptr;
+             if (r->dirnamelen < 2)
+               *p->allocptr++ = r->dirnamelen ? '/' : '.';
+             else
+               p->allocptr = __mempcpy (p->allocptr,
+                                         r->dirname, r->dirnamelen - 1);
+             *p->allocptr++ = '\0';
+             sp->dls_flags = flags;
+           }
+       }
+      while (*dirs != NULL);
+    }
+}
 
 void
-internal_function
 _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
 {
   if (counting)
@@ -2242,35 +2212,15 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
       si->dls_size = 0;
     }
 
-  unsigned int idx = 0;
-  char *allocptr = (char *) &si->dls_serpath[si->dls_cnt];
-  void add_path (const struct r_search_path_struct *sps, unsigned int flags)
-# define add_path(sps, flags) add_path(sps, 0) /* XXX */
+  struct add_path_state p =
     {
-      if (sps->dirs != (void *) -1)
-       {
-         struct r_search_path_elem **dirs = sps->dirs;
-         do
-           {
-             const struct r_search_path_elem *const r = *dirs++;
-             if (counting)
-               {
-                 si->dls_cnt++;
-                 si->dls_size += r->dirnamelen;
-               }
-             else
-               {
-                 Dl_serpath *const sp = &si->dls_serpath[idx++];
-                 sp->dls_name = allocptr;
-                 allocptr = __mempcpy (allocptr,
-                                       r->dirname, r->dirnamelen - 1);
-                 *allocptr++ = '\0';
-                 sp->dls_flags = flags;
-               }
-           }
-         while (*dirs != NULL);
-       }
-    }
+      .counting = counting,
+      .idx = 0,
+      .si = si,
+      .allocptr = (char *) &si->dls_serpath[si->dls_cnt]
+    };
+
+# define add_path(p, sps, flags) add_path(p, sps, 0) /* XXX */
 
   /* When the object has the RUNPATH information we don't use any RPATHs.  */
   if (loader->l_info[DT_RUNPATH] == NULL)
@@ -2282,7 +2232,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
       do
        {
          if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
-           add_path (&l->l_rpath_dirs, XXX_RPATH);
+           add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
          l = l->l_loader;
        }
       while (l != NULL);
@@ -2293,16 +2243,16 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
          l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
          if (l != NULL && l->l_type != lt_loaded && l != loader)
            if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
-             add_path (&l->l_rpath_dirs, XXX_RPATH);
+             add_path (&p, &l->l_rpath_dirs, XXX_RPATH);
        }
     }
 
   /* Try the LD_LIBRARY_PATH environment variable.  */
-  add_path (&env_path_list, XXX_ENV);
+  add_path (&p, &env_path_list, XXX_ENV);
 
   /* Look at the RUNPATH information for this binary.  */
   if (cache_rpath (loader, &loader->l_runpath_dirs, DT_RUNPATH, "RUNPATH"))
-    add_path (&loader->l_runpath_dirs, XXX_RUNPATH);
+    add_path (&p, &loader->l_runpath_dirs, XXX_RUNPATH);
 
   /* XXX
      Here is where ld.so.cache gets checked, but we don't have
@@ -2310,7 +2260,7 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
 
   /* Finally, try the default path.  */
   if (!(loader->l_flags_1 & DF_1_NODEFLIB))
-    add_path (&rtld_search_dirs, XXX_default);
+    add_path (&p, &rtld_search_dirs, XXX_default);
 
   if (counting)
     /* Count the struct size before the string area, which we didn't