]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - elf/rtld.c
install.texi: Build was tested with binutils 2.41 (just released)
[thirdparty/glibc.git] / elf / rtld.c
index 4e0581e2c6be103e2989fd9fbdfc957a151cd02d..a91e2a44710d068c813e0a3a13254c955ce216a7 100644 (file)
@@ -1,5 +1,5 @@
 /* Run time dynamic linker.
-   Copyright (C) 1995-2022 Free Software Foundation, Inc.
+   Copyright (C) 1995-2023 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,7 +32,6 @@
 #include <fpu_control.h>
 #include <hp-timing.h>
 #include <libc-lock.h>
-#include <dl-librecon.h>
 #include <unsecvars.h>
 #include <dl-cache.h>
 #include <dl-osinfo.h>
@@ -52,6 +51,8 @@
 #include <get-dynamic-info.h>
 #include <dl-execve.h>
 #include <dl-find_object.h>
+#include <dl-audit-check.h>
+#include <dl-call_tls_init_tp.h>
 
 #include <assert.h>
 
@@ -156,16 +157,8 @@ static void dl_main_state_init (struct dl_main_state *state);
 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
@@ -364,11 +357,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
     ._dl_lazy = 1,
     ._dl_fpu_control = _FPU_DEFAULT,
     ._dl_pagesize = EXEC_PAGESIZE,
@@ -380,13 +368,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_catch_error = _dl_catch_error,
     ._dl_error_free = _dl_error_free,
     ._dl_tls_get_addr_soft = _dl_tls_get_addr_soft,
     ._dl_libc_freeres = __rtld_libc_freeres,
-#ifdef HAVE_DL_DISCOVER_OSVERSION
-    ._dl_discover_osversion = _dl_discover_osversion
-#endif
   };
 /* If we would use strong_alias here the compiler would see a
    non-hidden definition.  This would undo the effect of the previous
@@ -424,7 +409,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
 
@@ -440,8 +425,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;
 
@@ -468,6 +453,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
+     interfere 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
@@ -486,7 +475,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.  */
@@ -512,7 +501,10 @@ _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);
 }
 
 #ifdef DONT_USE_BOOTSTRAP_MAP
@@ -564,7 +556,7 @@ _dl_start (void *arg)
   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.  */
@@ -586,23 +578,11 @@ _dl_start (void *arg)
 
   __rtld_malloc_init_stubs ();
 
-  /* Do not use an initializer for these members because it would
-     intefere with __rtld_static_init.  */
-  GLRO (dl_find_object) = &_dl_find_object;
-
-  {
 #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);
+  return _dl_start_final (arg, &info);
 #endif
-
-#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, entry);
-  }
 }
 
 
@@ -748,7 +728,7 @@ match_version (const char *string, struct link_map *map)
   return 0;
 }
 
-static bool tls_init_tp_called;
+bool __rtld_tls_init_tp_called;
 
 static void *
 init_tls (size_t naudit)
@@ -814,11 +794,8 @@ cannot allocate TLS data structures for initial thread\n");
   GL(dl_initial_dtv) = GET_DTV (tcbp);
 
   /* And finally install it for the main thread.  */
-  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;
+  call_tls_init_tp (tcbp);
+  __rtld_tls_init_tp_called = true;
 
   return tcbp;
 }
@@ -1000,7 +977,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",
@@ -1044,7 +1021,7 @@ ERROR: audit interface '%s' requires version %d (maximum supported version %d);
        newp->fptr[cnt] = NULL;
       ++cnt;
 
-      cp = rawmemchr (cp, '\0') + 1;
+      cp = strchr (cp, '\0') + 1;
     }
   while (*cp != '\0');
   assert (cnt == naudit_ifaces);
@@ -1090,7 +1067,7 @@ load_audit_modules (struct link_map *main_map, struct audit_list *audit_list)
     }
 }
 
-/* Check if the executable is not actualy dynamically linked, and
+/* Check if the executable is not actually dynamically linked, and
    invoke it directly in that case.  */
 static void
 rtld_chain_load (struct link_map *main_map, char *argv0)
@@ -1147,6 +1124,22 @@ rtld_setup_main_map (struct link_map *main_map)
   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)
@@ -1174,7 +1167,7 @@ rtld_setup_main_map (struct link_map *main_map)
        /* _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
+       /* Ordinarily, 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
@@ -1210,12 +1203,21 @@ rtld_setup_main_map (struct link_map *main_map)
          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;
 
@@ -1286,6 +1288,62 @@ rtld_setup_main_map (struct link_map *main_map)
   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
 dl_main (const ElfW(Phdr) *phdr,
         ElfW(Word) phnum,
@@ -1296,7 +1354,6 @@ dl_main (const ElfW(Phdr) *phdr,
   size_t file_size;
   char *file;
   unsigned int i;
-  bool prelinked = false;
   bool rtld_is_main = false;
   void *tcbp = NULL;
 
@@ -1340,6 +1397,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;
@@ -1354,7 +1412,6 @@ dl_main (const ElfW(Phdr) *phdr,
                GLRO(dl_lazy) = -1;
              }
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
@@ -1363,14 +1420,12 @@ dl_main (const ElfW(Phdr) *phdr,
            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;
          }
@@ -1380,7 +1435,6 @@ dl_main (const ElfW(Phdr) *phdr,
            state.library_path = _dl_argv[2];
            state.library_path_source = "--library-path";
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1389,7 +1443,6 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            GLRO(dl_inhibit_rpath) = _dl_argv[2];
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1397,14 +1450,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;
          }
@@ -1412,7 +1463,6 @@ dl_main (const ElfW(Phdr) *phdr,
          {
            argv0 = _dl_argv[2];
 
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1420,7 +1470,6 @@ dl_main (const ElfW(Phdr) *phdr,
                 && _dl_argc > 2)
          {
            state.glibc_hwcaps_prepend = _dl_argv[2];
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
@@ -1428,25 +1477,20 @@ dl_main (const ElfW(Phdr) *phdr,
                 && _dl_argc > 2)
          {
            state.glibc_hwcaps_mask = _dl_argv[2];
-           _dl_skip_args += 2;
            _dl_argc -= 2;
            _dl_argv += 2;
          }
-#if HAVE_TUNABLES
        else if (! strcmp (_dl_argv[1], "--list-tunables"))
          {
            state.mode = rtld_mode_list_tunables;
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
-#endif
        else if (! strcmp (_dl_argv[1], "--list-diagnostics"))
          {
            state.mode = rtld_mode_list_diagnostics;
 
-           ++_dl_skip_args;
            --_dl_argc;
            ++_dl_argv;
          }
@@ -1470,13 +1514,11 @@ dl_main (const ElfW(Phdr) *phdr,
        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);
@@ -1492,7 +1534,6 @@ dl_main (const ElfW(Phdr) *phdr,
            _dl_usage (ld_so_name, NULL);
        }
 
-      ++_dl_skip_args;
       --_dl_argc;
       ++_dl_argv;
 
@@ -1591,6 +1632,9 @@ dl_main (const ElfW(Phdr) *phdr,
       /* 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
     {
@@ -1676,10 +1720,6 @@ dl_main (const ElfW(Phdr) *phdr,
       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);
     }
 
@@ -1691,10 +1731,6 @@ dl_main (const ElfW(Phdr) *phdr,
   /* 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);
@@ -1717,18 +1753,11 @@ dl_main (const ElfW(Phdr) *phdr,
   ++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;
-
   /* 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.  */
-  extern const ElfW(Ehdr) __ehdr_start __attribute__ ((visibility ("hidden")));
 
   /* Set up the program header information for the dynamic linker
      itself.  It is needed in the dl_iterate_phdr callbacks.  */
@@ -2012,7 +2041,7 @@ dl_main (const ElfW(Phdr) *phdr,
      an old kernel that can't perform TLS_INIT_TP, even if no TLS is ever
      used.  Trying to do it lazily is too hairy to try when there could be
      multiple threads (from a non-TLS-using libpthread).  */
-  bool was_tls_init_tp_called = tls_init_tp_called;
+  bool was_tls_init_tp_called = __rtld_tls_init_tp_called;
   if (tcbp == NULL)
     tcbp = init_tls (0);
 
@@ -2029,37 +2058,7 @@ dl_main (const ElfW(Phdr) *phdr,
         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
@@ -2109,18 +2108,24 @@ dl_main (const ElfW(Phdr) *phdr,
        _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)
-             _dl_printf ("\t%s (0x%0*Zx)\n", l->l_libname->name,
+             /* 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))
@@ -2137,7 +2142,7 @@ dl_main (const ElfW(Phdr) *phdr,
 
            loadbase = LOOKUP_VALUE_ADDRESS (result, false);
 
-           _dl_printf ("%s found at 0x%0*Zd in object at 0x%0*Zd\n",
+           _dl_printf ("%s found at 0x%0*zd in object at 0x%0*zd\n",
                        _dl_argv[i],
                        (int) sizeof ref->st_value * 2,
                        (size_t) ref->st_value,
@@ -2167,14 +2172,6 @@ dl_main (const ElfW(Phdr) *phdr,
                    }
                }
 
-             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)
@@ -2251,61 +2248,6 @@ dl_main (const ElfW(Phdr) *phdr,
       _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;
 
@@ -2330,103 +2272,59 @@ dl_main (const ElfW(Phdr) *phdr,
 
   _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);
-       }
-
-      /* Set up the object lookup structures.  */
-      _dl_find_object_init ();
+  /* 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).  */
 
-      /* 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);
-
-      /* Likewise for the locking implementation.  */
-      __rtld_mutex_init ();
+  int consider_profiling = GLRO(dl_profile) != NULL;
 
-      /* 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);
+  /* If we are profiling we also must do lazy reloaction.  */
+  GLRO(dl_lazy) |= 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);
-       }
-    }
-  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;
-
-      /* 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 && __rtld_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 ())
@@ -2437,22 +2335,16 @@ dl_main (const ElfW(Phdr) *phdr,
      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)
-    {
-      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 ();
-    }
+  if (! __rtld_tls_init_tp_called)
+    call_tls_init_tp (tcbp);
 
   /* 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.
@@ -2494,10 +2386,8 @@ dl_main (const ElfW(Phdr) *phdr,
      _dl_relocate_object might need to call `mprotect' for DT_TEXTREL.  */
   _dl_sysdep_start_cleanup ();
 
-#ifdef SHARED
   /* Auditing checkpoint: we have added all objects.  */
   _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.  */
@@ -2725,15 +2615,6 @@ process_envvars (struct dl_main_state *state)
            _dl_show_auxv ();
          break;
 
-#if !HAVE_TUNABLES
-       case 10:
-         /* Mask for the important hardware capabilities.  */
-         if (!__libc_enable_secure
-             && memcmp (envline, "HWCAP_MASK", 10) == 0)
-           GLRO(dl_hwcap_mask) = _dl_strtoul (&envline[11], NULL);
-         break;
-#endif
-
        case 11:
          /* Path where the binary is found.  */
          if (!__libc_enable_secure
@@ -2763,20 +2644,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
@@ -2785,60 +2652,32 @@ 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);
-         /* We could use rawmemchr but this need not be fast.  */
-         nextp = (char *) (strchr) (nextp, '\0') + 1;
+         nextp = strchr (nextp, '\0') + 1;
        }
       while (*nextp != '\0');
 
       if (__access ("/etc/suid-debug", F_OK) != 0)
-       {
-#if !HAVE_TUNABLES
-         unsetenv ("MALLOC_CHECK_");
-#endif
-         GLRO(dl_debug_mask) = 0;
-       }
+       GLRO(dl_debug_mask) = 0;
 
       if (state->mode != rtld_mode_normal)
        _exit (5);
@@ -2929,9 +2768,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