]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/rtld.c
elf: Fix hwcaps string size overestimation
[thirdparty/glibc.git] / elf / rtld.c
index 8e35c3a330726134d491b74f6de834846d8a5e5a..3e771a93d83457665d0e143cf6c22ace592ec6ac 100644 (file)
@@ -1,5 +1,5 @@
 /* Run time dynamic linker.
-   Copyright (C) 1995-2020 Free Software Foundation, Inc.
+   Copyright (C) 1995-2022 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
@@ -32,8 +32,6 @@
 #include <fpu_control.h>
 #include <hp-timing.h>
 #include <libc-lock.h>
-#include "dynamic-link.h"
-#include <dl-librecon.h>
 #include <unsecvars.h>
 #include <dl-cache.h>
 #include <dl-osinfo.h>
 #include <array_length.h>
 #include <libc-early-init.h>
 #include <dl-main.h>
+#include <gnu/lib-names.h>
+#include <dl-tunables.h>
+#include <get-dynamic-info.h>
+#include <dl-execve.h>
+#include <dl-find_object.h>
+#include <dl-audit-check.h>
 
 #include <assert.h>
 
+/* This #define produces dynamic linking inline functions for
+   bootstrap relocation instead of general-purpose relocation.
+   Since ld.so must not have any undefined symbols the result
+   is trivial: always the map of ld.so itself.  */
+#define RTLD_BOOTSTRAP
+#define RESOLVE_MAP(map, scope, sym, version, flags) map
+#include "dynamic-link.h"
+
+/* Must include after <dl-machine.h> for DT_MIPS definition.  */
+#include <dl-debug.h>
+
 /* Only enables rtld profiling for architectures which provides non generic
    hp-timing support.  The generic support requires either syscall
    (clock_gettime), which will incur in extra overhead on loading time.
@@ -138,18 +153,11 @@ static void dl_main_state_init (struct dl_main_state *state);
 /* Process all environments variables the dynamic linker must recognize.
    Since all of them start with `LD_' we are a bit smarter while finding
    all the entries.  */
+extern char **_environ attribute_hidden;
 static void process_envvars (struct dl_main_state *state);
 
-#ifdef DL_ARGV_NOT_RELRO
-int _dl_argc attribute_hidden;
-char **_dl_argv = NULL;
-/* Nonzero if we were run directly.  */
-unsigned int _dl_skip_args attribute_hidden;
-#else
 int _dl_argc attribute_relro attribute_hidden;
 char **_dl_argv attribute_relro = NULL;
-unsigned int _dl_skip_args attribute_relro attribute_hidden;
-#endif
 rtld_hidden_data_def (_dl_argv)
 
 #ifndef THREAD_SET_STACK_GUARD
@@ -160,8 +168,7 @@ uintptr_t __stack_chk_guard attribute_relro;
 
 /* Only exported for architectures that don't store the pointer guard
    value in thread local area.  */
-uintptr_t __pointer_chk_guard_local
-     attribute_relro attribute_hidden __attribute__ ((nocommon));
+uintptr_t __pointer_chk_guard_local attribute_relro attribute_hidden;
 #ifndef THREAD_SET_POINTER_GUARD
 strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
 #endif
@@ -286,8 +293,11 @@ dl_main_state_init (struct dl_main_state *state)
 {
   audit_list_init (&state->audit_list);
   state->library_path = NULL;
+  state->library_path_source = NULL;
   state->preloadlist = NULL;
   state->preloadarg = NULL;
+  state->glibc_hwcaps_prepend = NULL;
+  state->glibc_hwcaps_mask = NULL;
   state->mode = rtld_mode_normal;
   state->any_debug = false;
   state->version_info = false;
@@ -317,6 +327,7 @@ struct rtld_global _rtld_global =
 #ifdef _LIBC_REENTRANT
     ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
     ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+    ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
 #endif
     ._dl_nns = 1,
     ._dl_ns =
@@ -329,7 +340,7 @@ struct rtld_global _rtld_global =
   };
 /* If we would use strong_alias here the compiler would see a
    non-hidden definition.  This would undo the effect of the previous
-   declaration.  So spell out was strong_alias does plus add the
+   declaration.  So spell out what strong_alias does plus add the
    visibility attribute.  */
 extern struct rtld_global _rtld_local
     __attribute__ ((alias ("_rtld_global"), visibility ("hidden")));
@@ -345,8 +356,6 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_sysinfo = DL_SYSINFO_DEFAULT,
 #endif
     ._dl_debug_fd = STDERR_FILENO,
-    ._dl_use_load_bias = -2,
-    ._dl_correct_cache_id = _DL_CACHE_DEFAULT_ID,
 #if !HAVE_TUNABLES
     ._dl_hwcap_mask = HWCAP_IMPORTANT,
 #endif
@@ -361,10 +370,10 @@ struct rtld_global_ro _rtld_global_ro attribute_relro =
     ._dl_lookup_symbol_x = _dl_lookup_symbol_x,
     ._dl_open = _dl_open,
     ._dl_close = _dl_close,
+    ._dl_catch_error = _rtld_catch_error,
+    ._dl_error_free = _dl_error_free,
     ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
-#ifdef HAVE_DL_DISCOVER_OSVERSION
-    ._dl_discover_osversion = _dl_discover_osversion
-#endif
+    ._dl_libc_freeres = __rtld_libc_freeres,
   };
 /* If we would use strong_alias here the compiler would see a
    non-hidden definition.  This would undo the effect of the previous
@@ -402,7 +411,7 @@ DL_SYSINFO_IMPLEMENTATION
    is fine, too.  The latter is important here.  We can avoid setting
    up a temporary link map for ld.so if we can mark _rtld_global as
    hidden.  */
-#ifdef PI_STATIC_AND_HIDDEN
+#ifndef HIDDEN_VAR_NEEDS_DYNAMIC_RELOC
 # define DONT_USE_BOOTSTRAP_MAP        1
 #endif
 
@@ -418,8 +427,8 @@ static ElfW(Addr) _dl_start_final (void *arg,
                                   struct dl_start_final_info *info);
 #endif
 
-/* These defined magically in the linker script.  */
-extern char _begin[] attribute_hidden;
+/* These are defined magically by the linker.  */
+extern const ElfW(Ehdr) __ehdr_start attribute_hidden;
 extern char _etext[] attribute_hidden;
 extern char _end[] attribute_hidden;
 
@@ -446,6 +455,10 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
 {
   ElfW(Addr) start_addr;
 
+  /* Do not use an initializer for these members because it would
+     intefere with __rtld_static_init.  */
+  GLRO (dl_find_object) = &_dl_find_object;
+
   /* If it hasn't happen yet record the startup time.  */
   rtld_timer_start (&start_time);
 #if !defined DONT_USE_BOOTSTRAP_MAP
@@ -456,6 +469,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
 #ifndef DONT_USE_BOOTSTRAP_MAP
   GL(dl_rtld_map).l_addr = info->l.l_addr;
   GL(dl_rtld_map).l_ld = info->l.l_ld;
+  GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly;
   memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
          sizeof GL(dl_rtld_map).l_info);
   GL(dl_rtld_map).l_mach = info->l.l_mach;
@@ -463,7 +477,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
 #endif
   _dl_setup_hash (&GL(dl_rtld_map));
   GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
-  GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
+  GL(dl_rtld_map).l_map_start = (ElfW(Addr)) &__ehdr_start;
   GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
   GL(dl_rtld_map).l_text_end = (ElfW(Addr)) _etext;
   /* Copy the TLS related data if necessary.  */
@@ -489,31 +503,25 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
       print_statistics (RTLD_TIMING_REF(rtld_total_time));
     }
 
-  return start_addr;
+#ifndef ELF_MACHINE_START_ADDRESS
+# define ELF_MACHINE_START_ADDRESS(map, start) (start)
+#endif
+  return ELF_MACHINE_START_ADDRESS (GL(dl_ns)[LM_ID_BASE]._ns_loaded, start_addr);
 }
 
-static ElfW(Addr) __attribute_used__
-_dl_start (void *arg)
-{
 #ifdef DONT_USE_BOOTSTRAP_MAP
 # define bootstrap_map GL(dl_rtld_map)
 #else
-  struct dl_start_final_info info;
 # define bootstrap_map info.l
 #endif
 
-  /* This #define produces dynamic linking inline functions for
-     bootstrap relocation instead of general-purpose relocation.
-     Since ld.so must not have any undefined symbols the result
-     is trivial: always the map of ld.so itself.  */
-#define RTLD_BOOTSTRAP
-#define BOOTSTRAP_MAP (&bootstrap_map)
-#define RESOLVE_MAP(sym, version, flags) BOOTSTRAP_MAP
-#include "dynamic-link.h"
-
+static ElfW(Addr) __attribute_used__
+_dl_start (void *arg)
+{
 #ifdef DONT_USE_BOOTSTRAP_MAP
   rtld_timer_start (&start_time);
 #else
+  struct dl_start_final_info info;
   rtld_timer_start (&info.start_time);
 #endif
 
@@ -539,22 +547,23 @@ _dl_start (void *arg)
 
   /* Read our own dynamic section and fill in the info array.  */
   bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
-  elf_get_dynamic_info (&bootstrap_map, NULL);
+  bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
+  elf_get_dynamic_info (&bootstrap_map, true, false);
 
 #if NO_TLS_OFFSET != 0
   bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
 #endif
 
 #ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
-  ELF_MACHINE_BEFORE_RTLD_RELOC (bootstrap_map.l_info);
+  ELF_MACHINE_BEFORE_RTLD_RELOC (&bootstrap_map, bootstrap_map.l_info);
 #endif
 
-  if (bootstrap_map.l_addr || ! bootstrap_map.l_info[VALIDX(DT_GNU_PRELINKED)])
+  if (bootstrap_map.l_addr)
     {
       /* Relocate ourselves so we can do normal function calls and
         data access using the global offset table.  */
 
-      ELF_DYNAMIC_RELOCATE (&bootstrap_map, 0, 0, 0);
+      ELF_DYNAMIC_RELOCATE (&bootstrap_map, NULL, 0, 0, 0);
     }
   bootstrap_map.l_relocated = 1;
 
@@ -571,19 +580,11 @@ _dl_start (void *arg)
 
   __rtld_malloc_init_stubs ();
 
-  {
 #ifdef DONT_USE_BOOTSTRAP_MAP
-    ElfW(Addr) entry = _dl_start_final (arg);
+  return _dl_start_final (arg);
 #else
-    ElfW(Addr) entry = _dl_start_final (arg, &info);
-#endif
-
-#ifndef ELF_MACHINE_START_ADDRESS
-# define ELF_MACHINE_START_ADDRESS(map, start) (start)
+  return _dl_start_final (arg, &info);
 #endif
-
-    return ELF_MACHINE_START_ADDRESS (GL(dl_ns)[LM_ID_BASE]._ns_loaded, entry);
-  }
 }
 
 
@@ -798,6 +799,7 @@ cannot allocate TLS data structures for initial thread\n");
   const char *lossage = TLS_INIT_TP (tcbp);
   if (__glibc_unlikely (lossage != NULL))
     _dl_fatal_printf ("cannot set up thread-local storage: %s\n", lossage);
+  __tls_init_tp ();
   tls_init_tp_called = true;
 
   return tcbp;
@@ -834,22 +836,6 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded (%s): ignored.\n",
   return 0;
 }
 
-#if defined SHARED && defined _LIBC_REENTRANT \
-    && defined __rtld_lock_default_lock_recursive
-static void
-rtld_lock_default_lock_recursive (void *lock)
-{
-  __rtld_lock_default_lock_recursive (lock);
-}
-
-static void
-rtld_lock_default_unlock_recursive (void *lock)
-{
-  __rtld_lock_default_unlock_recursive (lock);
-}
-#endif
-
-
 static void
 security_init (void)
 {
@@ -996,7 +982,7 @@ file=%s [%lu]; audit interface function la_version returned zero; ignored.\n",
       return;
     }
 
-  if (lav > LAV_CURRENT)
+  if (!_dl_audit_check_version (lav))
     {
       _dl_debug_printf ("\
 ERROR: audit interface '%s' requires version %d (maximum supported version %d); ignored.\n",
@@ -1021,13 +1007,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
     "la_objsearch\0"
     "la_objopen\0"
     "la_preinit\0"
-#if __ELF_NATIVE_CLASS == 32
-    "la_symbind32\0"
-#elif __ELF_NATIVE_CLASS == 64
-    "la_symbind64\0"
-#else
-# error "__ELF_NATIVE_CLASS must be defined"
-#endif
+    LA_SYMBIND "\0"
 #define STRING(s) __STRING (s)
     "la_" STRING (ARCH_LA_PLTENTER) "\0"
     "la_" STRING (ARCH_LA_PLTEXIT) "\0"
@@ -1069,25 +1049,6 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
   dlmargs.map->l_auditing = 1;
 }
 
-/* Notify the the audit modules that the object MAP has already been
-   loaded.  */
-static void
-notify_audit_modules_of_loaded_object (struct link_map *map)
-{
-  struct audit_ifaces *afct = GLRO(dl_audit);
-  for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
-    {
-      if (afct->objopen != NULL)
-       {
-         struct auditstate *state = link_map_audit_state (map, cnt);
-         state->bindflags = afct->objopen (map, LM_ID_BASE, &state->cookie);
-         map->l_audit_any_plt |= state->bindflags != 0;
-       }
-
-      afct = afct->next;
-    }
-}
-
 /* Load all audit modules.  */
 static void
 load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
@@ -1106,9 +1067,286 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
      program and the dynamic linker itself).  */
   if (GLRO(dl_naudit) > 0)
     {
-      notify_audit_modules_of_loaded_object (main_map);
-      notify_audit_modules_of_loaded_object (&GL(dl_rtld_map));
+      _dl_audit_objopen (main_map, LM_ID_BASE);
+      _dl_audit_objopen (&GL(dl_rtld_map), LM_ID_BASE);
+    }
+}
+
+/* Check if the executable is not actualy dynamically linked, and
+   invoke it directly in that case.  */
+static void
+rtld_chain_load (struct link_map *main_map, char *argv0)
+{
+  /* The dynamic loader run against itself.  */
+  const char *rtld_soname
+    = ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
+       + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val);
+  if (main_map->l_info[DT_SONAME] != NULL
+      && strcmp (rtld_soname,
+                ((const char *) D_PTR (main_map, l_info[DT_STRTAB])
+                 + main_map->l_info[DT_SONAME]->d_un.d_val)) == 0)
+    _dl_fatal_printf ("%s: loader cannot load itself\n", rtld_soname);
+
+  /* With DT_NEEDED dependencies, the executable is dynamically
+     linked.  */
+  if (__glibc_unlikely (main_map->l_info[DT_NEEDED] != NULL))
+    return;
+
+  /* If the executable has program interpreter, it is dynamically
+     linked.  */
+  for (size_t i = 0; i < main_map->l_phnum; ++i)
+    if (main_map->l_phdr[i].p_type == PT_INTERP)
+      return;
+
+  const char *pathname = _dl_argv[0];
+  if (argv0 != NULL)
+    _dl_argv[0] = argv0;
+  int errcode = __rtld_execve (pathname, _dl_argv, _environ);
+  const char *errname = strerrorname_np (errcode);
+  if (errname != NULL)
+    _dl_fatal_printf("%s: cannot execute %s: %s\n",
+                    rtld_soname, pathname, errname);
+  else
+    _dl_fatal_printf("%s: cannot execute %s: %d\n",
+                    rtld_soname, pathname, errcode);
+}
+
+/* Called to complete the initialization of the link map for the main
+   executable.  Returns true if there is a PT_INTERP segment.  */
+static bool
+rtld_setup_main_map (struct link_map *main_map)
+{
+  /* This have already been filled in right after _dl_new_object, or
+     as part of _dl_map_object.  */
+  const ElfW(Phdr) *phdr = main_map->l_phdr;
+  ElfW(Word) phnum = main_map->l_phnum;
+
+  bool has_interp = false;
+
+  main_map->l_map_end = 0;
+  main_map->l_text_end = 0;
+  /* Perhaps the executable has no PT_LOAD header entries at all.  */
+  main_map->l_map_start = ~0;
+  /* And it was opened directly.  */
+  ++main_map->l_direct_opencount;
+  main_map->l_contiguous = 1;
+
+  /* A PT_LOAD segment at an unexpected address will clear the
+     l_contiguous flag.  The ELF specification says that PT_LOAD
+     segments need to be sorted in in increasing order, but perhaps
+     not all executables follow this requirement.  Having l_contiguous
+     equal to 1 is just an optimization, so the code below does not
+     try to sort the segments in case they are unordered.
+
+     There is one corner case in which l_contiguous is not set to 1,
+     but where it could be set: If a PIE (ET_DYN) binary is loaded by
+     glibc itself (not the kernel), it is always contiguous due to the
+     way the glibc loader works.  However, the kernel loader may still
+     create holes in this case, and the code here still uses 0
+     conservatively for the glibc-loaded case, too.  */
+  ElfW(Addr) expected_load_address = 0;
+
+  /* Scan the program header table for the dynamic section.  */
+  for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
+    switch (ph->p_type)
+      {
+      case PT_PHDR:
+       /* Find out the load address.  */
+       main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
+       break;
+      case PT_DYNAMIC:
+       /* This tells us where to find the dynamic section,
+          which tells us everything we need to do.  */
+       main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
+       main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+       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.  */
+       _dl_rtld_libname.name = ((const char *) main_map->l_addr
+                                + ph->p_vaddr);
+       /* _dl_rtld_libname.next = NULL;        Already zero.  */
+       GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
+
+       /* Ordinarilly, we would get additional names for the loader from
+          our DT_SONAME.  This can't happen if we were actually linked as
+          a static executable (detect this case when we have no DYNAMIC).
+          If so, assume the filename component of the interpreter path to
+          be our SONAME, and add it to our name list.  */
+       if (GL(dl_rtld_map).l_ld == NULL)
+         {
+           const char *p = NULL;
+           const char *cp = _dl_rtld_libname.name;
+
+           /* Find the filename part of the path.  */
+           while (*cp != '\0')
+             if (*cp++ == '/')
+               p = cp;
+
+           if (p != NULL)
+             {
+               _dl_rtld_libname2.name = p;
+               /* _dl_rtld_libname2.next = NULL;  Already zero.  */
+               _dl_rtld_libname.next = &_dl_rtld_libname2;
+             }
+         }
+
+       has_interp = true;
+       break;
+      case PT_LOAD:
+       {
+         ElfW(Addr) mapstart;
+         ElfW(Addr) allocend;
+
+         /* Remember where the main program starts in memory.  */
+         mapstart = (main_map->l_addr
+                     + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
+         if (main_map->l_map_start > mapstart)
+           main_map->l_map_start = mapstart;
+
+         if (main_map->l_contiguous && expected_load_address != 0
+             && expected_load_address != mapstart)
+           main_map->l_contiguous = 0;
+
+         /* Also where it ends.  */
+         allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
+         if (main_map->l_map_end < allocend)
+           main_map->l_map_end = allocend;
+         if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
+           main_map->l_text_end = allocend;
+
+         /* The next expected address is the page following this load
+            segment.  */
+         expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
+                                  & ~(GLRO(dl_pagesize) - 1));
+       }
+       break;
+
+      case PT_TLS:
+       if (ph->p_memsz > 0)
+         {
+           /* Note that in the case the dynamic linker we duplicate work
+              here since we read the PT_TLS entry already in
+              _dl_start_final.  But the result is repeatable so do not
+              check for this special but unimportant case.  */
+           main_map->l_tls_blocksize = ph->p_memsz;
+           main_map->l_tls_align = ph->p_align;
+           if (ph->p_align == 0)
+             main_map->l_tls_firstbyte_offset = 0;
+           else
+             main_map->l_tls_firstbyte_offset = (ph->p_vaddr
+                                                 & (ph->p_align - 1));
+           main_map->l_tls_initimage_size = ph->p_filesz;
+           main_map->l_tls_initimage = (void *) ph->p_vaddr;
+
+           /* This image gets the ID one.  */
+           GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
+         }
+       break;
+
+      case PT_GNU_STACK:
+       GL(dl_stack_flags) = ph->p_flags;
+       break;
+
+      case PT_GNU_RELRO:
+       main_map->l_relro_addr = ph->p_vaddr;
+       main_map->l_relro_size = ph->p_memsz;
+       break;
+      }
+  /* Process program headers again, but scan them backwards so
+     that PT_NOTE can be skipped if PT_GNU_PROPERTY exits.  */
+  for (const ElfW(Phdr) *ph = &phdr[phnum]; ph != phdr; --ph)
+    switch (ph[-1].p_type)
+      {
+      case PT_NOTE:
+       _dl_process_pt_note (main_map, -1, &ph[-1]);
+       break;
+      case PT_GNU_PROPERTY:
+       _dl_process_pt_gnu_property (main_map, -1, &ph[-1]);
+       break;
+      }
+
+  /* Adjust the address of the TLS initialization image in case
+     the executable is actually an ET_DYN object.  */
+  if (main_map->l_tls_initimage != NULL)
+    main_map->l_tls_initimage
+      = (char *) main_map->l_tls_initimage + main_map->l_addr;
+  if (! main_map->l_map_end)
+    main_map->l_map_end = ~0;
+  if (! main_map->l_text_end)
+    main_map->l_text_end = ~0;
+  if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
+    {
+      /* We were invoked directly, so the program might not have a
+        PT_INTERP.  */
+      _dl_rtld_libname.name = GL(dl_rtld_map).l_name;
+      /* _dl_rtld_libname.next = NULL; Already zero.  */
+      GL(dl_rtld_map).l_libname =  &_dl_rtld_libname;
+    }
+  else
+    assert (GL(dl_rtld_map).l_libname); /* How else did we get here?  */
+
+  return has_interp;
+}
+
+/* Adjusts the contents of the stack and related globals for the user
+   entry point.  The ld.so processed skip_args arguments and bumped
+   _dl_argv and _dl_argc accordingly.  Those arguments are removed from
+   argv here.  */
+static void
+_dl_start_args_adjust (int skip_args)
+{
+  void **sp = (void **) (_dl_argv - skip_args - 1);
+  void **p = sp + skip_args;
+
+  if (skip_args == 0)
+    return;
+
+  /* Sanity check.  */
+  intptr_t argc __attribute__ ((unused)) = (intptr_t) sp[0] - skip_args;
+  assert (argc == _dl_argc);
+
+  /* Adjust argc on stack.  */
+  sp[0] = (void *) (intptr_t) _dl_argc;
+
+  /* Update globals in rtld.  */
+  _dl_argv -= skip_args;
+  _environ -= skip_args;
+
+  /* Shuffle argv down.  */
+  do
+    *++sp = *++p;
+  while (*p != NULL);
+
+  assert (_environ == (char **) (sp + 1));
+
+  /* Shuffle envp down.  */
+  do
+    *++sp = *++p;
+  while (*p != NULL);
+
+#ifdef HAVE_AUX_VECTOR
+  void **auxv = (void **) GLRO(dl_auxv) - skip_args;
+  GLRO(dl_auxv) = (ElfW(auxv_t) *) auxv; /* Aliasing violation.  */
+  assert (auxv == sp + 1);
+
+  /* Shuffle auxv down. */
+  ElfW(auxv_t) ax;
+  char *oldp = (char *) (p + 1);
+  char *newp = (char *) (sp + 1);
+  do
+    {
+      memcpy (&ax, oldp, sizeof (ax));
+      memcpy (newp, &ax, sizeof (ax));
+      oldp += sizeof (ax);
+      newp += sizeof (ax);
     }
+  while (ax.a_type != AT_NULL);
+#endif
 }
 
 static void
@@ -1117,30 +1355,23 @@ dl_main (const ElfW(Phdr) *phdr,
         ElfW(Addr) *user_entry,
         ElfW(auxv_t) *auxv)
 {
-  const ElfW(Phdr) *ph;
   struct link_map *main_map;
   size_t file_size;
   char *file;
-  bool has_interp = false;
   unsigned int i;
-  bool prelinked = false;
   bool rtld_is_main = false;
   void *tcbp = NULL;
 
   struct dl_main_state state;
   dl_main_state_init (&state);
 
-  GL(dl_init_static_tls) = &_dl_nothread_init_static_tls;
-
-#if defined SHARED && defined _LIBC_REENTRANT \
-    && defined __rtld_lock_default_lock_recursive
-  GL(dl_rtld_lock_recursive) = rtld_lock_default_lock_recursive;
-  GL(dl_rtld_unlock_recursive) = rtld_lock_default_unlock_recursive;
-#endif
+  __tls_pre_init_tp ();
 
+#if !PTHREAD_IN_LIBC
   /* The explicit initialization here is cheaper than processing the reloc
      in the _rtld_local definition's initializer.  */
   GL(dl_make_stack_executable_hook) = &_dl_make_stack_executable;
+#endif
 
   /* Process the environment variable which control the behaviour.  */
   process_envvars (&state);
@@ -1150,6 +1381,7 @@ dl_main (const ElfW(Phdr) *phdr,
   _dl_starting_up = 1;
 #endif
 
+  const char *ld_so_name = _dl_argv[0];
   if (*user_entry == (ElfW(Addr)) ENTRY_POINT)
     {
       /* Ho ho.  We are not the program interpreter!  We are the program
@@ -1170,6 +1402,7 @@ dl_main (const ElfW(Phdr) *phdr,
       rtld_is_main = true;
 
       char *argv0 = NULL;
+      char **orig_argv = _dl_argv;
 
       /* Note the place where the dynamic linker actually came from.  */
       GL(dl_rtld_map).l_name = rtld_progname;
@@ -1177,25 +1410,27 @@ dl_main (const ElfW(Phdr) *phdr,
       while (_dl_argc > 1)
        if (! strcmp (_dl_argv[1], "--list"))
          {
-           state.mode = rtld_mode_list;
-           GLRO(dl_lazy) = -1; /* This means do no dependency analysis.  */
+           if (state.mode != rtld_mode_help)
+             {
+              state.mode = rtld_mode_list;
+               /* This means do no dependency analysis.  */
+               GLRO(dl_lazy) = -1;
+             }
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
        else if (! strcmp (_dl_argv[1], "--verify"))
          {
-           state.mode = rtld_mode_verify;
+           if (state.mode != rtld_mode_help)
+             state.mode = rtld_mode_verify;
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
        else if (! strcmp (_dl_argv[1], "--inhibit-cache"))
          {
            GLRO(dl_inhibit_cache) = 1;
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
@@ -1203,8 +1438,8 @@ dl_main (const ElfW(Phdr) *phdr,
                 && _dl_argc > 2)
          {
            state.library_path = _dl_argv[2];
+           state.library_path_source = "--library-path";
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1213,7 +1448,6 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            GLRO(dl_inhibit_rpath) = _dl_argv[2];
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1221,14 +1455,12 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            audit_list_add_string (&state.audit_list, _dl_argv[2]);
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
        else if (! strcmp (_dl_argv[1], "--preload") && _dl_argc > 2)
          {
            state.preloadarg = _dl_argv[2];
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1236,49 +1468,87 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            argv0 = _dl_argv[2];
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
-       else
-         break;
-
-      /* If we have no further argument the program was called incorrectly.
-        Grant the user some education.  */
-      if (_dl_argc < 2)
-       _dl_fatal_printf ("\
-Usage: ld.so [OPTION]... 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\
-in executable files using ELF shared libraries tell the system's program\n\
-loader to load the helper program from this file.  This helper program loads\n\
-the shared libraries needed by the program executable, prepares the program\n\
-to run, and runs it.  You may invoke this helper program directly from the\n\
-command line to load and run an ELF executable file; this is like executing\n\
-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\
-\n\
-  --list                list all dependencies and how they are resolved\n\
-  --verify              verify that given object really is a dynamically linked\n\
-                       object we can handle\n\
-  --inhibit-cache       Do not use " LD_SO_CACHE "\n\
-  --library-path PATH   use given PATH instead of content of the environment\n\
-                       variable LD_LIBRARY_PATH\n\
-  --inhibit-rpath LIST  ignore RUNPATH and RPATH information in object names\n\
-                       in LIST\n\
-  --audit LIST          use objects named in LIST as auditors\n\
-  --preload LIST        preload objects named in LIST\n\
-  --argv0 STRING        set argv[0] to STRING before running\n");
-
-      ++_dl_skip_args;
-      --_dl_argc;
-      ++_dl_argv;
+       else if (strcmp (_dl_argv[1], "--glibc-hwcaps-prepend") == 0
+                && _dl_argc > 2)
+         {
+           state.glibc_hwcaps_prepend = _dl_argv[2];
+           _dl_argc -= 2;
+           _dl_argv += 2;
+         }
+       else if (strcmp (_dl_argv[1], "--glibc-hwcaps-mask") == 0
+                && _dl_argc > 2)
+         {
+           state.glibc_hwcaps_mask = _dl_argv[2];
+           _dl_argc -= 2;
+           _dl_argv += 2;
+         }
+#if HAVE_TUNABLES
+       else if (! strcmp (_dl_argv[1], "--list-tunables"))
+         {
+           state.mode = rtld_mode_list_tunables;
 
-      /* The initialization of _dl_stack_flags done below assumes the
-        executable's PT_GNU_STACK may have been honored by the kernel, and
-        so a PT_GNU_STACK with PF_X set means the stack started out with
+           --_dl_argc;
+           ++_dl_argv;
+         }
+#endif
+       else if (! strcmp (_dl_argv[1], "--list-diagnostics"))
+         {
+           state.mode = rtld_mode_list_diagnostics;
+
+           --_dl_argc;
+           ++_dl_argv;
+         }
+       else if (strcmp (_dl_argv[1], "--help") == 0)
+         {
+           state.mode = rtld_mode_help;
+           --_dl_argc;
+           ++_dl_argv;
+         }
+       else if (strcmp (_dl_argv[1], "--version") == 0)
+         _dl_version ();
+       else if (_dl_argv[1][0] == '-' && _dl_argv[1][1] == '-')
+         {
+          if (_dl_argv[1][1] == '\0')
+            /* End of option list.  */
+            break;
+          else
+            /* Unrecognized option.  */
+            _dl_usage (ld_so_name, _dl_argv[1]);
+         }
+       else
+         break;
+
+#if HAVE_TUNABLES
+      if (__glibc_unlikely (state.mode == rtld_mode_list_tunables))
+       {
+         __tunables_print ();
+         _exit (0);
+       }
+#endif
+
+      if (state.mode == rtld_mode_list_diagnostics)
+       _dl_print_diagnostics (_environ);
+
+      /* If we have no further argument the program was called incorrectly.
+        Grant the user some education.  */
+      if (_dl_argc < 2)
+       {
+         if (state.mode == rtld_mode_help)
+           /* --help without an executable is not an error.  */
+           _dl_help (ld_so_name, &state);
+         else
+           _dl_usage (ld_so_name, NULL);
+       }
+
+      --_dl_argc;
+      ++_dl_argv;
+
+      /* The initialization of _dl_stack_flags done below assumes the
+        executable's PT_GNU_STACK may have been honored by the kernel, and
+        so a PT_GNU_STACK with PF_X set means the stack started out with
         execute permission.  However, this is not really true if the
         dynamic linker is the executable the kernel loaded.  For this
         case, we must reinitialize _dl_stack_flags to match the dynamic
@@ -1288,14 +1558,15 @@ of this helper program; chances are you did not intend to run this program.\n\
         load the program below unless it has a PT_GNU_STACK indicating
         nonexecutable stack is ok.  */
 
-      for (ph = phdr; ph < &phdr[phnum]; ++ph)
+      for (const ElfW(Phdr) *ph = phdr; ph < &phdr[phnum]; ++ph)
        if (ph->p_type == PT_GNU_STACK)
          {
            GL(dl_stack_flags) = ph->p_flags;
            break;
          }
 
-      if (__glibc_unlikely (state.mode == rtld_mode_verify))
+      if (__glibc_unlikely (state.mode == rtld_mode_verify
+                           || state.mode == rtld_mode_help))
        {
          const char *objname;
          const char *err_str = NULL;
@@ -1308,9 +1579,16 @@ of this helper program; chances are you did not intend to run this program.\n\
          (void) _dl_catch_error (&objname, &err_str, &malloced, map_doit,
                                  &args);
          if (__glibc_unlikely (err_str != NULL))
-           /* We don't free the returned string, the programs stops
-              anyway.  */
-           _exit (EXIT_FAILURE);
+           {
+             /* We don't free the returned string, the programs stops
+                anyway.  */
+             if (state.mode == rtld_mode_help)
+               /* Mask the failure to load the main object.  The help
+                  message contains less information in this case.  */
+               _dl_help (ld_so_name, &state);
+             else
+               _exit (EXIT_FAILURE);
+           }
        }
       else
        {
@@ -1324,14 +1602,8 @@ of this helper program; chances are you did not intend to run this program.\n\
       /* Now the map for the main executable is available.  */
       main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
 
-      if (__glibc_likely (state.mode == rtld_mode_normal)
-         && GL(dl_rtld_map).l_info[DT_SONAME] != NULL
-         && main_map->l_info[DT_SONAME] != NULL
-         && strcmp ((const char *) D_PTR (&GL(dl_rtld_map), l_info[DT_STRTAB])
-                    + GL(dl_rtld_map).l_info[DT_SONAME]->d_un.d_val,
-                    (const char *) D_PTR (main_map, l_info[DT_STRTAB])
-                    + main_map->l_info[DT_SONAME]->d_un.d_val) == 0)
-       _dl_fatal_printf ("loader cannot load itself\n");
+      if (__glibc_likely (state.mode == rtld_mode_normal))
+       rtld_chain_load (main_map, argv0);
 
       phdr = main_map->l_phdr;
       phnum = main_map->l_phnum;
@@ -1342,6 +1614,9 @@ of this helper program; chances are you did not intend to run this program.\n\
       main_map->l_name = (char *) "";
       *user_entry = main_map->l_entry;
 
+      /* Set bit indicating this is the main program map.  */
+      main_map->l_main_map = 1;
+
 #ifdef HAVE_AUX_VECTOR
       /* Adjust the on-stack auxiliary vector so that it looks like the
         binary was executed directly.  */
@@ -1366,6 +1641,9 @@ of this helper program; chances are you did not intend to run this program.\n\
       /* Set the argv[0] string now that we've processed the executable.  */
       if (argv0 != NULL)
         _dl_argv[0] = argv0;
+
+      /* Adjust arguments for the application entry point.  */
+      _dl_start_args_adjust (_dl_argv - orig_argv);
     }
   else
     {
@@ -1402,146 +1680,7 @@ of this helper program; chances are you did not intend to run this program.\n\
         information for the program.  */
     }
 
-  main_map->l_map_end = 0;
-  main_map->l_text_end = 0;
-  /* Perhaps the executable has no PT_LOAD header entries at all.  */
-  main_map->l_map_start = ~0;
-  /* And it was opened directly.  */
-  ++main_map->l_direct_opencount;
-
-  /* Scan the program header table for the dynamic section.  */
-  for (ph = phdr; ph < &phdr[phnum]; ++ph)
-    switch (ph->p_type)
-      {
-      case PT_PHDR:
-       /* Find out the load address.  */
-       main_map->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
-       break;
-      case PT_DYNAMIC:
-       /* This tells us where to find the dynamic section,
-          which tells us everything we need to do.  */
-       main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
-       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.  */
-       _dl_rtld_libname.name = ((const char *) main_map->l_addr
-                                + ph->p_vaddr);
-       /* _dl_rtld_libname.next = NULL;        Already zero.  */
-       GL(dl_rtld_map).l_libname = &_dl_rtld_libname;
-
-       /* Ordinarilly, we would get additional names for the loader from
-          our DT_SONAME.  This can't happen if we were actually linked as
-          a static executable (detect this case when we have no DYNAMIC).
-          If so, assume the filename component of the interpreter path to
-          be our SONAME, and add it to our name list.  */
-       if (GL(dl_rtld_map).l_ld == NULL)
-         {
-           const char *p = NULL;
-           const char *cp = _dl_rtld_libname.name;
-
-           /* Find the filename part of the path.  */
-           while (*cp != '\0')
-             if (*cp++ == '/')
-               p = cp;
-
-           if (p != NULL)
-             {
-               _dl_rtld_libname2.name = p;
-               /* _dl_rtld_libname2.next = NULL;  Already zero.  */
-               _dl_rtld_libname.next = &_dl_rtld_libname2;
-             }
-         }
-
-       has_interp = true;
-       break;
-      case PT_LOAD:
-       {
-         ElfW(Addr) mapstart;
-         ElfW(Addr) allocend;
-
-         /* Remember where the main program starts in memory.  */
-         mapstart = (main_map->l_addr
-                     + (ph->p_vaddr & ~(GLRO(dl_pagesize) - 1)));
-         if (main_map->l_map_start > mapstart)
-           main_map->l_map_start = mapstart;
-
-         /* Also where it ends.  */
-         allocend = main_map->l_addr + ph->p_vaddr + ph->p_memsz;
-         if (main_map->l_map_end < allocend)
-           main_map->l_map_end = allocend;
-         if ((ph->p_flags & PF_X) && allocend > main_map->l_text_end)
-           main_map->l_text_end = allocend;
-       }
-       break;
-
-      case PT_TLS:
-       if (ph->p_memsz > 0)
-         {
-           /* Note that in the case the dynamic linker we duplicate work
-              here since we read the PT_TLS entry already in
-              _dl_start_final.  But the result is repeatable so do not
-              check for this special but unimportant case.  */
-           main_map->l_tls_blocksize = ph->p_memsz;
-           main_map->l_tls_align = ph->p_align;
-           if (ph->p_align == 0)
-             main_map->l_tls_firstbyte_offset = 0;
-           else
-             main_map->l_tls_firstbyte_offset = (ph->p_vaddr
-                                                 & (ph->p_align - 1));
-           main_map->l_tls_initimage_size = ph->p_filesz;
-           main_map->l_tls_initimage = (void *) ph->p_vaddr;
-
-           /* This image gets the ID one.  */
-           GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
-         }
-       break;
-
-      case PT_GNU_STACK:
-       GL(dl_stack_flags) = ph->p_flags;
-       break;
-
-      case PT_GNU_RELRO:
-       main_map->l_relro_addr = ph->p_vaddr;
-       main_map->l_relro_size = ph->p_memsz;
-       break;
-      }
-  /* Process program headers again, but scan them backwards so
-     that PT_NOTE can be skipped if PT_GNU_PROPERTY exits.  */
-  for (ph = &phdr[phnum]; ph != phdr; --ph)
-    switch (ph[-1].p_type)
-      {
-      case PT_NOTE:
-       _dl_process_pt_note (main_map, &ph[-1]);
-       break;
-      case PT_GNU_PROPERTY:
-       _dl_process_pt_gnu_property (main_map, &ph[-1]);
-       break;
-      }
-
-  /* Adjust the address of the TLS initialization image in case
-     the executable is actually an ET_DYN object.  */
-  if (main_map->l_tls_initimage != NULL)
-    main_map->l_tls_initimage
-      = (char *) main_map->l_tls_initimage + main_map->l_addr;
-  if (! main_map->l_map_end)
-    main_map->l_map_end = ~0;
-  if (! main_map->l_text_end)
-    main_map->l_text_end = ~0;
-  if (! GL(dl_rtld_map).l_libname && GL(dl_rtld_map).l_name)
-    {
-      /* We were invoked directly, so the program might not have a
-        PT_INTERP.  */
-      _dl_rtld_libname.name = GL(dl_rtld_map).l_name;
-      /* _dl_rtld_libname.next = NULL; Already zero.  */
-      GL(dl_rtld_map).l_libname =  &_dl_rtld_libname;
-    }
-  else
-    assert (GL(dl_rtld_map).l_libname); /* How else did we get here?  */
+  bool has_interp = rtld_setup_main_map (main_map);
 
   /* If the current libname is different from the SONAME, add the
      latter as well.  */
@@ -1566,7 +1705,17 @@ of this helper program; chances are you did not intend to run this program.\n\
   if (! rtld_is_main)
     {
       /* Extract the contents of the dynamic section for easy access.  */
-      elf_get_dynamic_info (main_map, NULL);
+      elf_get_dynamic_info (main_map, false, false);
+
+      /* If the main map is libc.so, update the base namespace to
+        refer to this map.  If libc.so is loaded later, this happens
+        in _dl_map_object_from_fd.  */
+      if (main_map->l_info[DT_SONAME] != NULL
+         && (strcmp (((const char *) D_PTR (main_map, l_info[DT_STRTAB])
+                     + main_map->l_info[DT_SONAME]->d_un.d_val), LIBC_SO)
+             == 0))
+       GL(dl_ns)[LM_ID_BASE].libc_map = main_map;
+
       /* Set up our cache of pointers into the hash table.  */
       _dl_setup_hash (main_map);
     }
@@ -1580,10 +1729,6 @@ of this helper program; chances are you did not intend to run this program.\n\
       if (main_map->l_ld == NULL)
        _exit (1);
 
-      /* We allow here some platform specific code.  */
-#ifdef DISTINGUISH_LIB_VERSIONS
-      DISTINGUISH_LIB_VERSIONS;
-#endif
       _exit (has_interp ? 0 : 2);
     }
 
@@ -1595,15 +1740,11 @@ of this helper program; chances are you did not intend to run this program.\n\
   /* With vDSO setup we can initialize the function pointers.  */
   setup_vdso_pointers ();
 
-#ifdef DL_SYSDEP_OSCHECK
-  DL_SYSDEP_OSCHECK (_dl_fatal_printf);
-#endif
-
   /* Initialize the data structures for the search paths for shared
      objects.  */
   call_init_paths (&state);
 
-  /* Initialize _r_debug.  */
+  /* Initialize _r_debug_extended.  */
   struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr,
                                            LM_ID_BASE);
   r->r_state = RT_CONSISTENT;
@@ -1621,27 +1762,15 @@ of this helper program; chances are you did not intend to run this program.\n\
   ++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
   ++GL(dl_load_adds);
 
-  /* If LD_USE_LOAD_BIAS env variable has not been seen, default
-     to not using bias for non-prelinked PIEs and libraries
-     and using it for executables or prelinked PIEs or libraries.  */
-  if (GLRO(dl_use_load_bias) == (ElfW(Addr)) -2)
-    GLRO(dl_use_load_bias) = main_map->l_addr == 0 ? -1 : 0;
-
-  /* Set up the program header information for the dynamic linker
-     itself.  It is needed in the dl_iterate_phdr callbacks.  */
-  const ElfW(Ehdr) *rtld_ehdr;
-
   /* Starting from binutils-2.23, the linker will define the magic symbol
      __ehdr_start to point to our own ELF header if it is visible in a
      segment that also includes the phdrs.  If that's not available, we use
      the old method that assumes the beginning of the file is part of the
      lowest-addressed PT_LOAD segment.  */
-#ifdef HAVE_EHDR_START
-  extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden")));
-  rtld_ehdr = &__ehdr_start;
-#else
-  rtld_ehdr = (void *) GL(dl_rtld_map).l_map_start;
-#endif
+
+  /* Set up the program header information for the dynamic linker
+     itself.  It is needed in the dl_iterate_phdr callbacks.  */
+  const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
   assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
   assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
 
@@ -1664,11 +1793,16 @@ of this helper program; chances are you did not intend to run this program.\n\
   /* Add the dynamic linker to the TLS list if it also uses TLS.  */
   if (GL(dl_rtld_map).l_tls_blocksize != 0)
     /* Assign a module ID.  Do this before loading any audit modules.  */
-    GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid ();
+    _dl_assign_tls_modid (&GL(dl_rtld_map));
 
   audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_AUDIT);
   audit_list_add_dynamic_tag (&state.audit_list, main_map, DT_DEPAUDIT);
 
+  /* At this point, all data has been obtained that is included in the
+     --help output.  */
+  if (__glibc_unlikely (state.mode == rtld_mode_help))
+    _dl_help (ld_so_name, &state);
+
   /* If we have auditing DSOs to load, do it now.  */
   bool need_security_init = true;
   if (state.audit_list.length > 0)
@@ -1698,21 +1832,7 @@ of this helper program; chances are you did not intend to run this program.\n\
   size_t count_modids = _dl_count_modids ();
 
   /* Set up debugging before the debugger is notified for the first time.  */
-#ifdef ELF_MACHINE_DEBUG_SETUP
-  /* Some machines (e.g. MIPS) don't use DT_DEBUG in this way.  */
-  ELF_MACHINE_DEBUG_SETUP (main_map, r);
-  ELF_MACHINE_DEBUG_SETUP (&GL(dl_rtld_map), r);
-#else
-  if (main_map->l_info[DT_DEBUG] != NULL)
-    /* There is a DT_DEBUG entry in the dynamic section.  Fill it in
-       with the run-time address of the r_debug structure  */
-    main_map->l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
-
-  /* Fill in the pointer in the dynamic linker's own dynamic section, in
-     case you run gdb on the dynamic linker directly.  */
-  if (GL(dl_rtld_map).l_info[DT_DEBUG] != NULL)
-    GL(dl_rtld_map).l_info[DT_DEBUG]->d_un.d_ptr = (ElfW(Addr)) r;
-#endif
+  elf_setup_debug_entry (main_map, r);
 
   /* We start adding objects.  */
   r->r_state = RT_ADD;
@@ -1721,18 +1841,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 
   /* Auditing checkpoint: we are ready to signal that the initial map
      is being constructed.  */
-  if (__glibc_unlikely (GLRO(dl_naudit) > 0))
-    {
-      struct audit_ifaces *afct = GLRO(dl_audit);
-      for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
-       {
-         if (afct->activity != NULL)
-           afct->activity (&link_map_audit_state (main_map, cnt)->cookie,
-                           LA_ACT_ADD);
-
-         afct = afct->next;
-       }
-    }
+  _dl_audit_activity_map (main_map, LA_ACT_ADD);
 
   /* We have two ways to specify objects to preload: via environment
      variable and via the file /etc/ld.so.preload.  The latter can also
@@ -1856,6 +1965,12 @@ of this helper program; chances are you did not intend to run this program.\n\
       assert (i == npreloads);
     }
 
+#ifdef NEED_DL_SYSINFO_DSO
+  /* Now that the audit modules are opened, call la_objopen for the vDSO.  */
+  if (GLRO(dl_sysinfo_map) != NULL)
+    _dl_audit_objopen (GLRO(dl_sysinfo_map), LM_ID_BASE);
+#endif
+
   /* Load all the libraries specified by DT_NEEDED entries.  If LD_PRELOAD
      specified some libraries to load, these are inserted before the actual
      dependencies in the executable's searchlist for symbol resolution.  */
@@ -1952,37 +2067,7 @@ of this helper program; chances are you did not intend to run this program.\n\
         after relocation.  */
       struct link_map *l;
 
-      if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
-       {
-         struct r_scope_elem *scope = &main_map->l_searchlist;
-
-         for (i = 0; i < scope->r_nlist; i++)
-           {
-             l = scope->r_list [i];
-             if (l->l_faked)
-               {
-                 _dl_printf ("\t%s => not found\n", l->l_libname->name);
-                 continue;
-               }
-             if (_dl_name_match_p (GLRO(dl_trace_prelink), l))
-               GLRO(dl_trace_prelink_map) = l;
-             _dl_printf ("\t%s => %s (0x%0*Zx, 0x%0*Zx)",
-                         DSO_FILENAME (l->l_libname->name),
-                         DSO_FILENAME (l->l_name),
-                         (int) sizeof l->l_map_start * 2,
-                         (size_t) l->l_map_start,
-                         (int) sizeof l->l_addr * 2,
-                         (size_t) l->l_addr);
-
-             if (l->l_tls_modid)
-               _dl_printf (" TLS(0x%Zx, 0x%0*Zx)\n", l->l_tls_modid,
-                           (int) sizeof l->l_tls_offset * 2,
-                           (size_t) l->l_tls_offset);
-             else
-               _dl_printf ("\n");
-           }
-       }
-      else if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
+      if (GLRO(dl_debug_mask) & DL_DEBUG_UNUSED)
        {
          /* Look through the dependencies of the main executable
             and determine which of them is not actually
@@ -2032,18 +2117,24 @@ of this helper program; chances are you did not intend to run this program.\n\
        _dl_printf ("\tstatically linked\n");
       else
        {
-         for (l = main_map->l_next; l; l = l->l_next)
+         for (l = state.mode_trace_program ? main_map : main_map->l_next;
+              l; l = l->l_next) {
            if (l->l_faked)
              /* The library was not found.  */
-             _dl_printf ("\t%s => not found\n", l->l_libname->name);
+             _dl_printf ("\t%s => not found\n",  l->l_libname->name);
            else if (strcmp (l->l_libname->name, l->l_name) == 0)
+             /* Print vDSO like libraries without duplicate name.  Some
+                consumers depend of this format.  */
              _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
                          (int) sizeof l->l_map_start * 2,
                          (size_t) l->l_map_start);
            else
-             _dl_printf ("\t%s => %s (0x%0*Zx)\n", l->l_libname->name,
-                         l->l_name, (int) sizeof l->l_map_start * 2,
+             _dl_printf ("\t%s => %s (0x%0*Zx)\n",
+                         DSO_FILENAME (l->l_libname->name),
+                         DSO_FILENAME (l->l_name),
+                         (int) sizeof l->l_map_start * 2,
                          (size_t) l->l_map_start);
+         }
        }
 
       if (__glibc_unlikely (state.mode != rtld_mode_trace))
@@ -2090,14 +2181,6 @@ of this helper program; chances are you did not intend to run this program.\n\
                    }
                }
 
-             if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
-                 && rtld_multiple_ref)
-               {
-                 /* Mark the link map as not yet relocated again.  */
-                 GL(dl_rtld_map).l_relocated = 0;
-                 _dl_relocate_object (&GL(dl_rtld_map),
-                                      main_map->l_scope, __RTLD_NOIFUNC, 0);
-               }
            }
 #define VERNEEDTAG (DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGIDX (DT_VERNEED))
          if (state.version_info)
@@ -2174,61 +2257,6 @@ of this helper program; chances are you did not intend to run this program.\n\
       _exit (0);
     }
 
-  if (main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]
-      && ! __builtin_expect (GLRO(dl_profile) != NULL, 0)
-      && ! __builtin_expect (GLRO(dl_dynamic_weak), 0))
-    {
-      ElfW(Lib) *liblist, *liblistend;
-      struct link_map **r_list, **r_listend, *l;
-      const char *strtab = (const void *) D_PTR (main_map, l_info[DT_STRTAB]);
-
-      assert (main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
-      liblist = (ElfW(Lib) *)
-               main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
-      liblistend = (ElfW(Lib) *)
-                  ((char *) liblist
-                   + main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
-      r_list = main_map->l_searchlist.r_list;
-      r_listend = r_list + main_map->l_searchlist.r_nlist;
-
-      for (; r_list < r_listend && liblist < liblistend; r_list++)
-       {
-         l = *r_list;
-
-         if (l == main_map)
-           continue;
-
-         /* If the library is not mapped where it should, fail.  */
-         if (l->l_addr)
-           break;
-
-         /* Next, check if checksum matches.  */
-         if (l->l_info [VALIDX(DT_CHECKSUM)] == NULL
-             || l->l_info [VALIDX(DT_CHECKSUM)]->d_un.d_val
-                != liblist->l_checksum)
-           break;
-
-         if (l->l_info [VALIDX(DT_GNU_PRELINKED)] == NULL
-             || l->l_info [VALIDX(DT_GNU_PRELINKED)]->d_un.d_val
-                != liblist->l_time_stamp)
-           break;
-
-         if (! _dl_name_match_p (strtab + liblist->l_name, l))
-           break;
-
-         ++liblist;
-       }
-
-
-      if (r_list == r_listend && liblist == liblistend)
-       prelinked = true;
-
-      if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_LIBS))
-       _dl_debug_printf ("\nprelink checking: %s\n",
-                         prelinked ? "ok" : "failed");
-    }
-
-
   /* Now set up the variable which helps the assembler startup code.  */
   GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist;
 
@@ -2253,97 +2281,59 @@ of this helper program; chances are you did not intend to run this program.\n\
 
   _rtld_main_check (main_map, _dl_argv[0]);
 
-  if (prelinked)
-    {
-      if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
-       {
-         ElfW(Rela) *conflict, *conflictend;
-
-         RTLD_TIMING_VAR (start);
-         rtld_timer_start (&start);
-
-         assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
-         conflict = (ElfW(Rela) *)
-           main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
-         conflictend = (ElfW(Rela) *)
-           ((char *) conflict
-            + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
-         _dl_resolve_conflicts (main_map, conflict, conflictend);
-
-         rtld_timer_stop (&relocate_time, start);
-       }
-
-      /* The library defining malloc has already been relocated due to
-        prelinking.  Resolve the malloc symbols for the dynamic
-        loader.  */
-      __rtld_malloc_init_real (main_map);
-
-      /* Mark all the objects so we know they have been already relocated.  */
-      for (struct link_map *l = main_map; l != NULL; l = l->l_next)
-       {
-         l->l_relocated = 1;
-         if (l->l_relro_size)
-           _dl_protect_relro (l);
+  /* Now we have all the objects loaded.  Relocate them all except for
+     the dynamic linker itself.  We do this in reverse order so that copy
+     relocs of earlier objects overwrite the data written by later
+     objects.  We do not re-relocate the dynamic linker itself in this
+     loop because that could result in the GOT entries for functions we
+     call being changed, and that would break us.  It is safe to relocate
+     the dynamic linker out of order because it has no copy relocs (we
+     know that because it is self-contained).  */
 
-         /* Add object to slot information data if necessasy.  */
-         if (l->l_tls_blocksize != 0 && tls_init_tp_called)
-           _dl_add_to_slotinfo (l, true);
-       }
-    }
-  else
-    {
-      /* Now we have all the objects loaded.  Relocate them all except for
-        the dynamic linker itself.  We do this in reverse order so that copy
-        relocs of earlier objects overwrite the data written by later
-        objects.  We do not re-relocate the dynamic linker itself in this
-        loop because that could result in the GOT entries for functions we
-        call being changed, and that would break us.  It is safe to relocate
-        the dynamic linker out of order because it has no copy relocs (we
-        know that because it is self-contained).  */
+  int consider_profiling = GLRO(dl_profile) != NULL;
 
-      int consider_profiling = GLRO(dl_profile) != NULL;
+  /* If we are profiling we also must do lazy reloaction.  */
+  GLRO(dl_lazy) |= consider_profiling;
 
-      /* If we are profiling we also must do lazy reloaction.  */
-      GLRO(dl_lazy) |= consider_profiling;
+  RTLD_TIMING_VAR (start);
+  rtld_timer_start (&start);
+  {
+    unsigned i = main_map->l_searchlist.r_nlist;
+    while (i-- > 0)
+      {
+       struct link_map *l = main_map->l_initfini[i];
 
-      RTLD_TIMING_VAR (start);
-      rtld_timer_start (&start);
-      unsigned i = main_map->l_searchlist.r_nlist;
-      while (i-- > 0)
-       {
-         struct link_map *l = main_map->l_initfini[i];
+       /* While we are at it, help the memory handling a bit.  We have to
+          mark some data structures as allocated with the fake malloc()
+          implementation in ld.so.  */
+       struct libname_list *lnp = l->l_libname->next;
 
-         /* While we are at it, help the memory handling a bit.  We have to
-            mark some data structures as allocated with the fake malloc()
-            implementation in ld.so.  */
-         struct libname_list *lnp = l->l_libname->next;
+       while (__builtin_expect (lnp != NULL, 0))
+         {
+           lnp->dont_free = 1;
+           lnp = lnp->next;
+         }
+       /* Also allocated with the fake malloc().  */
+       l->l_free_initfini = 0;
 
-         while (__builtin_expect (lnp != NULL, 0))
-           {
-             lnp->dont_free = 1;
-             lnp = lnp->next;
-           }
-         /* Also allocated with the fake malloc().  */
-         l->l_free_initfini = 0;
+       if (l != &GL(dl_rtld_map))
+         _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
+                              consider_profiling);
 
-         if (l != &GL(dl_rtld_map))
-           _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0,
-                                consider_profiling);
+       /* Add object to slot information data if necessasy.  */
+       if (l->l_tls_blocksize != 0 && tls_init_tp_called)
+         _dl_add_to_slotinfo (l, true);
+      }
+  }
+  rtld_timer_stop (&relocate_time, start);
 
-         /* Add object to slot information data if necessasy.  */
-         if (l->l_tls_blocksize != 0 && tls_init_tp_called)
-           _dl_add_to_slotinfo (l, true);
-       }
-      rtld_timer_stop (&relocate_time, start);
-
-      /* Now enable profiling if needed.  Like the previous call,
-        this has to go here because the calls it makes should use the
-        rtld versions of the functions (particularly calloc()), but it
-        needs to have _dl_profile_map set up by the relocator.  */
-      if (__glibc_unlikely (GL(dl_profile_map) != NULL))
-       /* We must prepare the profiling.  */
-       _dl_start_profile ();
-    }
+  /* Now enable profiling if needed.  Like the previous call,
+     this has to go here because the calls it makes should use the
+     rtld versions of the functions (particularly calloc()), but it
+     needs to have _dl_profile_map set up by the relocator.  */
+  if (__glibc_unlikely (GL(dl_profile_map) != NULL))
+    /* We must prepare the profiling.  */
+    _dl_start_profile ();
 
   if ((!was_tls_init_tp_called && GL(dl_tls_max_dtv_idx) > 0)
       || count_modids != _dl_count_modids ())
@@ -2354,7 +2344,7 @@ of this helper program; chances are you did not intend to run this program.\n\
      into the main thread's TLS area, which we allocated above.
      Note: thread-local variables must only be accessed after completing
      the next step.  */
-  _dl_allocate_tls_init (tcbp);
+  _dl_allocate_tls_init (tcbp, false);
 
   /* And finally install it for the main thread.  */
   if (! tls_init_tp_called)
@@ -2363,12 +2353,13 @@ of this helper program; chances are you did not intend to run this program.\n\
       if (__glibc_unlikely (lossage != NULL))
        _dl_fatal_printf ("cannot set up thread-local storage: %s\n",
                          lossage);
+      __tls_init_tp ();
     }
 
   /* Make sure no new search directories have been added.  */
   assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs));
 
-  if (! prelinked && rtld_multiple_ref)
+  if (rtld_multiple_ref)
     {
       /* There was an explicit ref to the dynamic linker as a shared lib.
         Re-relocate ourselves with user-controlled symbol definitions.
@@ -2377,11 +2368,17 @@ of this helper program; chances are you did not intend to run this program.\n\
         re-relocation, we might call a user-supplied function
         (e.g. calloc from _dl_relocate_object) that uses TLS data.  */
 
+      /* Set up the object lookup structures.  */
+      _dl_find_object_init ();
+
       /* The malloc implementation has been relocated, so resolving
         its symbols (and potentially calling IFUNC resolvers) is safe
         at this point.  */
       __rtld_malloc_init_real (main_map);
 
+      /* Likewise for the locking implementation.  */
+      __rtld_mutex_init ();
+
       RTLD_TIMING_VAR (start);
       rtld_timer_start (&start);
 
@@ -2406,28 +2403,12 @@ of this helper program; chances are you did not intend to run this program.\n\
 
 #ifdef SHARED
   /* Auditing checkpoint: we have added all objects.  */
-  if (__glibc_unlikely (GLRO(dl_naudit) > 0))
-    {
-      struct link_map *head = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
-      /* Do not call the functions for any auditing object.  */
-      if (head->l_auditing == 0)
-       {
-         struct audit_ifaces *afct = GLRO(dl_audit);
-         for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt)
-           {
-             if (afct->activity != NULL)
-               afct->activity (&link_map_audit_state (head, cnt)->cookie,
-                               LA_ACT_CONSISTENT);
-
-             afct = afct->next;
-           }
-       }
-    }
+  _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT);
 #endif
 
   /* Notify the debugger all new objects are now ready to go.  We must re-get
      the address since by now the variable might be in another object.  */
-  r = _dl_debug_initialize (0, LM_ID_BASE);
+  r = _dl_debug_update (LM_ID_BASE);
   r->r_state = RT_CONSISTENT;
   _dl_debug_state ();
   LIBC_PROBE (init_complete, 2, LM_ID_BASE, r);
@@ -2569,12 +2550,6 @@ a filename can be specified using the LD_DEBUG_OUTPUT environment variable.\n");
     }
 }
 \f
-/* Process all environments variables the dynamic linker must recognize.
-   Since all of them start with `LD_' we are a bit smarter while finding
-   all the entries.  */
-extern char **_environ attribute_hidden;
-
-
 static void
 process_envvars (struct dl_main_state *state)
 {
@@ -2679,6 +2654,7 @@ process_envvars (struct dl_main_state *state)
              && memcmp (envline, "LIBRARY_PATH", 12) == 0)
            {
              state->library_path = &envline[13];
+             state->library_path_source = "LD_LIBRARY_PATH";
              break;
            }
 
@@ -2694,20 +2670,6 @@ process_envvars (struct dl_main_state *state)
            GLRO(dl_dynamic_weak) = 1;
          break;
 
-       case 13:
-         /* We might have some extra environment variable with length 13
-            to handle.  */
-#ifdef EXTRA_LD_ENVVARS_13
-         EXTRA_LD_ENVVARS_13
-#endif
-         if (!__libc_enable_secure
-             && memcmp (envline, "USE_LOAD_BIAS", 13) == 0)
-           {
-             GLRO(dl_use_load_bias) = envline[14] == '1' ? -1 : 0;
-             break;
-           }
-         break;
-
        case 14:
          /* Where to place the profiling data file.  */
          if (!__libc_enable_secure
@@ -2716,45 +2678,23 @@ process_envvars (struct dl_main_state *state)
            GLRO(dl_profile_output) = &envline[15];
          break;
 
-       case 16:
+       case 20:
          /* The mode of the dynamic linker can be set.  */
-         if (memcmp (envline, "TRACE_PRELINKING", 16) == 0)
+         if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0)
            {
              state->mode = rtld_mode_trace;
-             GLRO(dl_verbose) = 1;
-             GLRO(dl_debug_mask) |= DL_DEBUG_PRELINK;
-             GLRO(dl_trace_prelink) = &envline[17];
+             state->mode_trace_program
+               = _dl_strtoul (&envline[21], NULL) > 1;
            }
          break;
-
-       case 20:
-         /* The mode of the dynamic linker can be set.  */
-         if (memcmp (envline, "TRACE_LOADED_OBJECTS", 20) == 0)
-           state->mode = rtld_mode_trace;
-         break;
-
-         /* We might have some extra environment variable to handle.  This
-            is tricky due to the pre-processing of the length of the name
-            in the switch statement here.  The code here assumes that added
-            environment variables have a different length.  */
-#ifdef EXTRA_LD_ENVVARS
-         EXTRA_LD_ENVVARS
-#endif
        }
     }
 
   /* Extra security for SUID binaries.  Remove all dangerous environment
      variables.  */
-  if (__builtin_expect (__libc_enable_secure, 0))
+  if (__glibc_unlikely (__libc_enable_secure))
     {
-      static const char unsecure_envvars[] =
-#ifdef EXTRA_UNSECURE_ENVVARS
-       EXTRA_UNSECURE_ENVVARS
-#endif
-       UNSECURE_ENVVARS;
-      const char *nextp;
-
-      nextp = unsecure_envvars;
+      const char *nextp = UNSECURE_ENVVARS;
       do
        {
          unsetenv (nextp);
@@ -2860,9 +2800,8 @@ print_statistics (const hp_timing_t *rtld_total_timep)
              += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val;
 #ifndef ELF_MACHINE_REL_RELATIVE
          /* Relative relocations are processed on these architectures if
-            library is loaded to different address than p_vaddr or
-            if not prelinked.  */
-         if ((l->l_addr != 0 || !l->l_info[VALIDX(DT_GNU_PRELINKED)])
+            library is loaded to different address than p_vaddr.  */
+         if ((l->l_addr != 0)
              && l->l_info[VERSYMIDX (DT_RELACOUNT)])
 #else
          /* On e.g. IA-64 or Alpha, relative relocations are processed