summary refs log tree commit diff
path: root/elf/rtld.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2004-10-14 02:08:23 +0000
committerUlrich Drepper <drepper@redhat.com>2004-10-14 02:08:23 +0000
commitc0f62c56788c48b9fb36dc609c0a9f9db3667306 (patch)
tree79c7e9692bb59dc90e4466e238cd4578c2d5c8f3 /elf/rtld.c
parent8e9185fb1c0294d2eb4bee0797d7e1c2850111ea (diff)
downloadglibc-c0f62c56788c48b9fb36dc609c0a9f9db3667306.tar.gz
glibc-c0f62c56788c48b9fb36dc609c0a9f9db3667306.tar.xz
glibc-c0f62c56788c48b9fb36dc609c0a9f9db3667306.zip
[BZ #77]
Update.
	Add support for namespaces in the dynamic linker.
	* dlfcn/Makefile (libdl-routines): Add dlmopen.
	* dlfcn/Versions [libdl, GLIBC_2.3.4]: Add dlmopen.
	* dlfcn/dlfcn.h: Define Lmid_t, LM_ID_BASE, and LM_ID_NEWLM.
	Declare dlmopen.  Document RTLD_DI_LMID.
	* dlfcn/dlinfo.c: Handle RTLD_DI_LMID.
	* dlfcn/dlmopen.c: New file.
	* dlfcn/dlopen.c: Pass new parameter to _dl_open.
	* dlfcn/dlopenold.c: Likewise.
	* elf/dl-addr.c: Adjust for removal of GL(dl_loaded).
	* elf/dl-caller.c: Likewise.
	* elf/dl-close.c: Likewise.
	* elf/dl-conflict.c: Likewise.
	* elf/dl-debug.c: Likewise.
	* elf/dl-lookup.c: Likewise.
	* elf/dl-sym.c: Likewise.
	* elf/dl-version.c: Likewise.
	* elf/do-lookup.h: Likewise.
	* elf/rtld.c: Likewise.
	* sysdeps/unix/sysv/linux/i386/dl-librecon.h: Likewise.
	* elf/dl-depsc: Likewise.  Add new parameter to _dl_map_object.
	* elf/dl-fini.c: Call destructors in all namespaces.
	* elf/dl-iteratephdr.c: Compute total nloaded.  Adjust for removal of
	GL(dl_loaded).
	* elf/dl-libc.c: Pass new parameter to _dl_open.  Adjust for removal
	of GL(dl_loaded).
	* elf/dl-load.c (_dl_map_object_from_fd): Don't load ld.so a second
	time.  Reuse the one from the main namespace in all others.
	Pass new parameter to _dl_new_object.
	Adjust for removal of GL(dl_loaded).
	* elf/dl-object.c: Take new parameter.  Use it to initialize l_ns.
	Adjust for removal of GL(dl_loaded).
	* elf/dl-open.c (_dl_open): Take new parameter.
	Adjust for removal of GL(dl_loaded).
	* elf/dl-support.c: Replace global _dl_loaded etc variables with
	_dl_ns variable.
	* include/dlfcn.h: Adjust prototype of _dl_open.
	Define __LM_ID_CALLER.
	* include/link.h: Add l_real, l_ns, and l_direct_opencount elements.
	* sysdeps/generic/dl-tls.c: Bump TLS_STATIC_SURPLUS.  Since libc is
	using TLS we need memory appropriate to the number of namespaces.
	* sysdeps/generic/ldsodefs.h (struct rtld_global): Replace _dl_loaded,
	_dl_nloaded, _dl_global_scope, _dl_main_searchlist, and
	_dl_global_scope_alloc with _dl_ns element.  Define DL_NNS.
	Adjust prototypes of _dl_map_object and member in rtld_global_ro.
	* malloc/malloc.c: Include <dlfcn.h>.
	* malloc/arena.c (ptmalloc_init): If libc is not in primary namespace,
	never use brk.
	* elf/Makefile: Add rules to build and run tst-dlmopen1 and
	tst-dlmopen2.
	* elf/tst-dlmopen1.c: New file.
	* elf/tst-dlmopen1mod.c: New file.
	* elf/tst-dlmopen2.c: New file.

	* elf/dl-close.c: Improve reference counting by tracking direct loads.
	* elf/dl-lookup.c (add_dependency): Likewise.
	* elf/dl-open.c (dl_open_worker): Likewise.
	* elf/rtld.c (dl_main): Likewise.

2004-09-09  GOTO Masanori  <gotom@debian.or.jp>

	[BZ #77]
	* elf/dl-close.c: Count down l_opencount to check not only for
	l_reldeps, but also l_initfini.

2004-10-13  Ulrich Drepper  <drepper@redhat.com>
Diffstat (limited to 'elf/rtld.c')
-rw-r--r--elf/rtld.c245
1 files changed, 129 insertions, 116 deletions
diff --git a/elf/rtld.c b/elf/rtld.c
index 5e18a49267..3346abf6ce 100644
--- a/elf/rtld.c
+++ b/elf/rtld.c
@@ -269,6 +269,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
   GL(dl_rtld_map).l_mach = info->l.l_mach;
 #endif
   _dl_setup_hash (&GL(dl_rtld_map));
+  GL(dl_rtld_map).l_real = &GL(dl_rtld_map);
   GL(dl_rtld_map).l_opencount = 1;
   GL(dl_rtld_map).l_map_start = (ElfW(Addr)) _begin;
   GL(dl_rtld_map).l_map_end = (ElfW(Addr)) _end;
@@ -585,14 +586,16 @@ map_doit (void *a)
 {
   struct map_args *args = (struct map_args *) a;
   args->map = _dl_map_object (args->loader, args->str,
-			      args->is_preloaded, lt_library, 0, args->mode);
+			      args->is_preloaded, lt_library, 0, args->mode,
+			      LM_ID_BASE);
 }
 
 static void
 version_check_doit (void *a)
 {
   struct version_check_args *args = (struct version_check_args *) a;
-  if (_dl_check_all_versions (GL(dl_loaded), 1, args->dotrace) && args->doexit)
+  if (_dl_check_all_versions (GL(dl_ns)[LM_ID_BASE]._ns_loaded, 1,
+			      args->dotrace) && args->doexit)
     /* We cannot start the application.  Abort now.  */
     _exit (1);
 }
@@ -601,11 +604,12 @@ version_check_doit (void *a)
 static inline struct link_map *
 find_needed (const char *name)
 {
-  unsigned int n = GL(dl_loaded)->l_searchlist.r_nlist;
+  struct r_scope_elem *scope = &GL(dl_ns)[LM_ID_BASE]._ns_loaded->l_searchlist;
+  unsigned int n = scope->r_nlist;
 
   while (n-- > 0)
-    if (_dl_name_match_p (name, GL(dl_loaded)->l_searchlist.r_list[n]))
-      return GL(dl_loaded)->l_searchlist.r_list[n];
+    if (_dl_name_match_p (name, scope->r_list[n]))
+      return scope->r_list[n];
 
   /* Should never happen.  */
   return NULL;
@@ -685,6 +689,7 @@ dl_main (const ElfW(Phdr) *phdr,
   enum mode mode;
   struct link_map **preloads;
   unsigned int npreloads;
+  struct link_map *main_map;
   size_t file_size;
   char *file;
   bool has_interp = false;
@@ -860,31 +865,35 @@ of this helper program; chances are you did not intend to run this program.\n\
 	{
 	  HP_TIMING_NOW (start);
 	  _dl_map_object (NULL, rtld_progname, 0, lt_library, 0,
-			  __RTLD_OPENEXEC);
+			  __RTLD_OPENEXEC, LM_ID_BASE);
 	  HP_TIMING_NOW (stop);
 
 	  HP_TIMING_DIFF (load_time, start, stop);
 	}
 
-      phdr = GL(dl_loaded)->l_phdr;
-      phnum = GL(dl_loaded)->l_phnum;
+      /* Now the map for the main executable is available.  */
+      main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+      phdr = main_map->l_phdr;
+      phnum = main_map->l_phnum;
       /* We overwrite here a pointer to a malloc()ed string.  But since
 	 the malloc() implementation used at this point is the dummy
 	 implementations which has no real free() function it does not
 	 makes sense to free the old string first.  */
-      GL(dl_loaded)->l_name = (char *) "";
-      *user_entry = GL(dl_loaded)->l_entry;
+      main_map->l_name = (char *) "";
+      *user_entry = main_map->l_entry;
     }
   else
     {
       /* Create a link_map for the executable itself.
 	 This will be what dlopen on "" returns.  */
-      _dl_new_object ((char *) "", "", lt_executable, NULL, 0);
-      if (GL(dl_loaded) == NULL)
+      _dl_new_object ((char *) "", "", lt_executable, NULL, 0, LM_ID_BASE);
+      main_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+      if (main_map == NULL)
 	_dl_fatal_printf ("cannot allocate memory for link map\n");
-      GL(dl_loaded)->l_phdr = phdr;
-      GL(dl_loaded)->l_phnum = phnum;
-      GL(dl_loaded)->l_entry = *user_entry;
+      main_map->l_phdr = phdr;
+      main_map->l_phnum = phnum;
+      main_map->l_entry = *user_entry;
 
       /* At this point we are in a bit of trouble.  We would have to
 	 fill in the values for l_dev and l_ino.  But in general we
@@ -905,12 +914,14 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 information for the program.  */
     }
 
-  GL(dl_loaded)->l_map_end = 0;
-  GL(dl_loaded)->l_text_end = 0;
+  main_map->l_map_end = 0;
+  main_map->l_text_end = 0;
   /* Perhaps the executable has no PT_LOAD header entries at all.  */
-  GL(dl_loaded)->l_map_start = ~0;
+  main_map->l_map_start = ~0;
   /* We opened the file, account for it.  */
-  ++GL(dl_loaded)->l_opencount;
+  ++main_map->l_opencount;
+  /* 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)
@@ -918,12 +929,12 @@ of this helper program; chances are you did not intend to run this program.\n\
       {
       case PT_PHDR:
 	/* Find out the load address.  */
-	GL(dl_loaded)->l_addr = (ElfW(Addr)) phdr - ph->p_vaddr;
+	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.  */
-	GL(dl_loaded)->l_ld = (void *) GL(dl_loaded)->l_addr + ph->p_vaddr;
+	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
@@ -932,7 +943,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	   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 *) GL(dl_loaded)->l_addr
+	_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;
@@ -968,17 +979,16 @@ of this helper program; chances are you did not intend to run this program.\n\
 	  ElfW(Addr) allocend;
 
 	  /* Remember where the main program starts in memory.  */
-	  mapstart = (GL(dl_loaded)->l_addr
-		      + (ph->p_vaddr & ~(ph->p_align - 1)));
-	  if (GL(dl_loaded)->l_map_start > mapstart)
-	    GL(dl_loaded)->l_map_start = mapstart;
+	  mapstart = (main_map->l_addr + (ph->p_vaddr & ~(ph->p_align - 1)));
+	  if (main_map->l_map_start > mapstart)
+	    main_map->l_map_start = mapstart;
 
 	  /* Also where it ends.  */
-	  allocend = GL(dl_loaded)->l_addr + ph->p_vaddr + ph->p_memsz;
-	  if (GL(dl_loaded)->l_map_end < allocend)
-	    GL(dl_loaded)->l_map_end = allocend;
-	  if ((ph->p_flags & PF_X) && allocend > GL(dl_loaded)->l_text_end)
-	    GL(dl_loaded)->l_text_end = allocend;
+	  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;
 #ifdef USE_TLS
@@ -989,18 +999,18 @@ of this helper program; chances are you did not intend to run this program.\n\
 	       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.  */
-	    GL(dl_loaded)->l_tls_blocksize = ph->p_memsz;
-	    GL(dl_loaded)->l_tls_align = ph->p_align;
+	    main_map->l_tls_blocksize = ph->p_memsz;
+	    main_map->l_tls_align = ph->p_align;
 	    if (ph->p_align == 0)
-	      GL(dl_loaded)->l_tls_firstbyte_offset = 0;
+	      main_map->l_tls_firstbyte_offset = 0;
 	    else
-	      GL(dl_loaded)->l_tls_firstbyte_offset = (ph->p_vaddr
-						       & (ph->p_align - 1));
-	    GL(dl_loaded)->l_tls_initimage_size = ph->p_filesz;
-	    GL(dl_loaded)->l_tls_initimage = (void *) ph->p_vaddr;
+	      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) = GL(dl_loaded)->l_tls_modid = 1;
+	    GL(dl_tls_max_dtv_idx) = main_map->l_tls_modid = 1;
 	  }
 	break;
 #endif
@@ -1009,21 +1019,21 @@ of this helper program; chances are you did not intend to run this program.\n\
 	break;
 
       case PT_GNU_RELRO:
-	GL(dl_loaded)->l_relro_addr = ph->p_vaddr;
-	GL(dl_loaded)->l_relro_size = ph->p_memsz;
+	main_map->l_relro_addr = ph->p_vaddr;
+	main_map->l_relro_size = ph->p_memsz;
 	break;
       }
 #ifdef USE_TLS
     /* Adjust the address of the TLS initialization image in case
        the executable is actually an ET_DYN object.  */
-    if (GL(dl_loaded)->l_tls_initimage != NULL)
-      GL(dl_loaded)->l_tls_initimage
-	= (char *) GL(dl_loaded)->l_tls_initimage + GL(dl_loaded)->l_addr;
+    if (main_map->l_tls_initimage != NULL)
+      main_map->l_tls_initimage
+	= (char *) main_map->l_tls_initimage + main_map->l_addr;
 #endif
-  if (! GL(dl_loaded)->l_map_end)
-    GL(dl_loaded)->l_map_end = ~0;
-  if (! GL(dl_loaded)->l_text_end)
-    GL(dl_loaded)->l_text_end = ~0;
+  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
@@ -1038,9 +1048,9 @@ 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 (GL(dl_loaded), NULL);
+      elf_get_dynamic_info (main_map, NULL);
       /* Set up our cache of pointers into the hash table.  */
-      _dl_setup_hash (GL(dl_loaded));
+      _dl_setup_hash (main_map);
     }
 
   if (__builtin_expect (mode, normal) == verify)
@@ -1049,7 +1059,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 executable using us as the program interpreter.  Exit with an
 	 error if we were not able to load the binary or no interpreter
 	 is specified (i.e., this is no dynamically linked binary.  */
-      if (GL(dl_loaded)->l_ld == NULL)
+      if (main_map->l_ld == NULL)
 	_exit (1);
 
       /* We allow here some platform specific code.  */
@@ -1072,16 +1082,16 @@ of this helper program; chances are you did not intend to run this program.\n\
        found by the PT_INTERP name.  */
     GL(dl_rtld_map).l_name = (char *) GL(dl_rtld_map).l_libname->name;
   GL(dl_rtld_map).l_type = lt_library;
-  GL(dl_loaded)->l_next = &GL(dl_rtld_map);
-  GL(dl_rtld_map).l_prev = GL(dl_loaded);
-  ++GL(dl_nloaded);
+  main_map->l_next = &GL(dl_rtld_map);
+  GL(dl_rtld_map).l_prev = main_map;
+  ++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) = (GL(dl_loaded)->l_addr == 0) ? -1 : 0;
+    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.  */
@@ -1125,8 +1135,9 @@ of this helper program; chances are you did not intend to run this program.\n\
 	    && (__builtin_expect (! INTUSE(__libc_enable_secure), 1)
 		|| strchr (p, '/') == NULL))
 	  {
-	    struct link_map *new_map = _dl_map_object (GL(dl_loaded), p, 1,
-						       lt_library, 0, 0);
+	    struct link_map *new_map = _dl_map_object (main_map, p, 1,
+						       lt_library, 0, 0,
+						       LM_ID_BASE);
 	    if (++new_map->l_opencount == 1)
 	      /* It is no duplicate.  */
 	      ++npreloads;
@@ -1208,7 +1219,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 		    struct map_args args;
 
 		    args.str = p;
-		    args.loader = GL(dl_loaded);
+		    args.loader = main_map;
 		    args.is_preloaded = 1;
 		    args.mode = 0;
 
@@ -1231,8 +1242,9 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
 	  if (problem != NULL)
 	    {
 	      char *p = strndupa (problem, file_size - (problem - file));
-	      struct link_map *new_map = _dl_map_object (GL(dl_loaded), p, 1,
-							 lt_library, 0, 0);
+	      struct link_map *new_map = _dl_map_object (main_map, p, 1,
+							 lt_library, 0, 0,
+							 LM_ID_BASE);
 	      if (++new_map->l_opencount == 1)
 		/* It is no duplicate.  */
 		++npreloads;
@@ -1272,7 +1284,7 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
 	 We just want our data structures to describe it as if we had just
 	 mapped and relocated it normally.  */
       struct link_map *l = _dl_new_object ((char *) "", "", lt_library, NULL,
-					   0);
+					   0, LM_ID_BASE);
       if (__builtin_expect (l != NULL, 1))
 	{
 	  static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
@@ -1337,18 +1349,18 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
      specified some libraries to load, these are inserted before the actual
      dependencies in the executable's searchlist for symbol resolution.  */
   HP_TIMING_NOW (start);
-  _dl_map_object_deps (GL(dl_loaded), preloads, npreloads, mode == trace, 0);
+  _dl_map_object_deps (main_map, preloads, npreloads, mode == trace, 0);
   HP_TIMING_NOW (stop);
   HP_TIMING_DIFF (diff, start, stop);
   HP_TIMING_ACCUM_NT (load_time, diff);
 
   /* Mark all objects as being in the global scope and set the open
      counter.  */
-  for (i = GL(dl_loaded)->l_searchlist.r_nlist; i > 0; )
+  for (i = main_map->l_searchlist.r_nlist; i > 0; )
     {
       --i;
-      GL(dl_loaded)->l_searchlist.r_list[i]->l_global = 1;
-      ++GL(dl_loaded)->l_searchlist.r_list[i]->l_opencount;
+      main_map->l_searchlist.r_list[i]->l_global = 1;
+      ++main_map->l_searchlist.r_list[i]->l_opencount;
     }
 
 #ifndef MAP_ANON
@@ -1369,13 +1381,13 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
 	 chain in symbol search order because gdb uses the chain's order as
 	 its symbol search order.  */
       i = 1;
-      while (GL(dl_loaded)->l_searchlist.r_list[i] != &GL(dl_rtld_map))
+      while (main_map->l_searchlist.r_list[i] != &GL(dl_rtld_map))
 	++i;
-      GL(dl_rtld_map).l_prev = GL(dl_loaded)->l_searchlist.r_list[i - 1];
+      GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1];
       if (__builtin_expect (mode, normal) == normal)
 	{
-	  GL(dl_rtld_map).l_next = (i + 1 < GL(dl_loaded)->l_searchlist.r_nlist
-				    ? GL(dl_loaded)->l_searchlist.r_list[i + 1]
+	  GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist
+				    ? main_map->l_searchlist.r_list[i + 1]
 				    : NULL);
 #ifdef NEED_DL_SYSINFO
 	  if (sysinfo_map != NULL
@@ -1459,7 +1471,7 @@ ERROR: ld.so: object '%s' from %s cannot be preloaded: ignored.\n",
       GL(dl_tls_dtv_slotinfo_list)->next = NULL;
 
       /* Fill in the information from the loaded modules.  */
-      for (l = GL(dl_loaded), i = 0; l != NULL; l = l->l_next)
+      for (l = main_map, i = 0; l != NULL; l = l->l_next)
 	if (l->l_tls_blocksize != 0)
 	  /* This is a module with TLS data.  Store the map reference.
 	     The generation counter is zero.  */
@@ -1495,7 +1507,7 @@ cannot allocate TLS data structures for initial thread");
 
       if (GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
 	{
-	  struct r_scope_elem *scope = &GL(dl_loaded)->l_searchlist;
+	  struct r_scope_elem *scope = &main_map->l_searchlist;
 
 	  for (i = 0; i < scope->r_nlist; i++)
 	    {
@@ -1531,7 +1543,7 @@ cannot allocate TLS data structures for initial thread");
 	  /* Look through the dependencies of the main executable
 	     and determine which of them is not actually
 	     required.  */
-	  struct link_map *l = GL(dl_loaded);
+	  struct link_map *l = main_map;
 
 	  /* Relocate the main executable.  */
 	  struct relocate_args args = { .l = l, .lazy = GLRO(dl_lazy) };
@@ -1539,7 +1551,7 @@ cannot allocate TLS data structures for initial thread");
 
 	  /* This loop depends on the dependencies of the executable to
 	     correspond in number and order to the DT_NEEDED entries.  */
-	  ElfW(Dyn) *dyn = GL(dl_loaded)->l_ld;
+	  ElfW(Dyn) *dyn = main_map->l_ld;
 	  bool first = true;
 	  while (dyn->d_tag != DT_NULL)
 	    {
@@ -1564,11 +1576,11 @@ cannot allocate TLS data structures for initial thread");
 
 	  _exit (first != true);
 	}
-      else if (! GL(dl_loaded)->l_info[DT_NEEDED])
+      else if (! main_map->l_info[DT_NEEDED])
 	_dl_printf ("\tstatically linked\n");
       else
 	{
-	  for (l = GL(dl_loaded)->l_next; l; l = l->l_next)
+	  for (l = 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);
@@ -1589,8 +1601,8 @@ cannot allocate TLS data structures for initial thread");
 	    ElfW(Addr) loadbase;
 	    lookup_t result;
 
-	    result = _dl_lookup_symbol_x (INTUSE(_dl_argv)[i], GL(dl_loaded),
-					  &ref, GL(dl_loaded)->l_scope, NULL,
+	    result = _dl_lookup_symbol_x (INTUSE(_dl_argv)[i], main_map,
+					  &ref, main_map->l_scope, NULL,
 					  ELF_RTYPE_CLASS_PLT,
 					  DL_LOOKUP_ADD_DEPENDENCY, NULL);
 
@@ -1613,7 +1625,7 @@ cannot allocate TLS data structures for initial thread");
 
 	      args.lazy = GLRO(dl_lazy);
 
-	      l = GL(dl_loaded);
+	      l = main_map;
 	      while (l->l_next)
 		l = l->l_next;
 	      do
@@ -1629,7 +1641,7 @@ cannot allocate TLS data structures for initial thread");
 
 	      if ((GLRO(dl_debug_mask) & DL_DEBUG_PRELINK)
 		  && GL(dl_rtld_map).l_opencount > 1)
-		_dl_relocate_object (&GL(dl_rtld_map), GL(dl_loaded)->l_scope,
+		_dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope,
 				     0, 0);
 	    }
 
@@ -1639,9 +1651,9 @@ cannot allocate TLS data structures for initial thread");
 	      /* Print more information.  This means here, print information
 		 about the versions needed.  */
 	      int first = 1;
-	      struct link_map *map = GL(dl_loaded);
+	      struct link_map *map;
 
-	      for (map = GL(dl_loaded); map != NULL; map = map->l_next)
+	      for (map = main_map; map != NULL; map = map->l_next)
 		{
 		  const char *strtab;
 		  ElfW(Dyn) *dyn = map->l_info[VERNEEDTAG];
@@ -1709,28 +1721,27 @@ cannot allocate TLS data structures for initial thread");
       _exit (0);
     }
 
-  if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]
+  if (main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]
       && ! __builtin_expect (GLRO(dl_profile) != NULL, 0))
     {
       ElfW(Lib) *liblist, *liblistend;
       struct link_map **r_list, **r_listend, *l;
-      const char *strtab = (const void *) D_PTR (GL(dl_loaded),
-						 l_info[DT_STRTAB]);
+      const char *strtab = (const void *) D_PTR (main_map, l_info[DT_STRTAB]);
 
-      assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
+      assert (main_map->l_info[VALIDX (DT_GNU_LIBLISTSZ)] != NULL);
       liblist = (ElfW(Lib) *)
-		GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
+		main_map->l_info[ADDRIDX (DT_GNU_LIBLIST)]->d_un.d_ptr;
       liblistend = (ElfW(Lib) *)
-		   ((char *) liblist
-		    + GL(dl_loaded)->l_info [VALIDX (DT_GNU_LIBLISTSZ)]->d_un.d_val);
-      r_list = GL(dl_loaded)->l_searchlist.r_list;
-      r_listend = r_list + GL(dl_loaded)->l_searchlist.r_nlist;
+		   ((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 == GL(dl_loaded))
+	  if (l == main_map)
 	    continue;
 
 	  /* If the library is not mapped where it should, fail.  */
@@ -1767,9 +1778,7 @@ cannot allocate TLS data structures for initial thread");
   /* Initialize _r_debug.  */
   struct r_debug *r = _dl_debug_initialize (GL(dl_rtld_map).l_addr);
   {
-    struct link_map *l;
-
-    l = GL(dl_loaded);
+    struct link_map *l = main_map;
 
 #ifdef ELF_MACHINE_DEBUG_SETUP
 
@@ -1793,18 +1802,18 @@ cannot allocate TLS data structures for initial thread");
   }
 
   /* Now set up the variable which helps the assembler startup code.  */
-  GL(dl_main_searchlist) = &GL(dl_loaded)->l_searchlist;
-  GL(dl_global_scope)[0] = &GL(dl_loaded)->l_searchlist;
+  GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist = &main_map->l_searchlist;
+  GL(dl_ns)[LM_ID_BASE]._ns_global_scope[0] = &main_map->l_searchlist;
 
   /* Save the information about the original global scope list since
      we need it in the memory handling later.  */
-  GLRO(dl_initial_searchlist) = *GL(dl_main_searchlist);
+  GLRO(dl_initial_searchlist) = *GL(dl_ns)[LM_ID_BASE]._ns_main_searchlist;
 
   if (prelinked)
     {
       struct link_map *l;
 
-      if (GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
+      if (main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)] != NULL)
 	{
 	  ElfW(Rela) *conflict, *conflictend;
 #ifndef HP_TIMING_NONAVAIL
@@ -1813,20 +1822,20 @@ cannot allocate TLS data structures for initial thread");
 #endif
 
 	  HP_TIMING_NOW (start);
-	  assert (GL(dl_loaded)->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
+	  assert (main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)] != NULL);
 	  conflict = (ElfW(Rela) *)
-	    GL(dl_loaded)->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
+	    main_map->l_info [ADDRIDX (DT_GNU_CONFLICT)]->d_un.d_ptr;
 	  conflictend = (ElfW(Rela) *)
 	    ((char *) conflict
-	     + GL(dl_loaded)->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
-	  _dl_resolve_conflicts (GL(dl_loaded), conflict, conflictend);
+	     + main_map->l_info [VALIDX (DT_GNU_CONFLICTSZ)]->d_un.d_val);
+	  _dl_resolve_conflicts (main_map, conflict, conflictend);
 	  HP_TIMING_NOW (stop);
 	  HP_TIMING_DIFF (relocate_time, start, stop);
 	}
 
 
       /* Mark all the objects so we know they have been already relocated.  */
-      for (l = GL(dl_loaded); l != NULL; l = l->l_next)
+      for (l = main_map; l != NULL; l = l->l_next)
 	{
 	  l->l_relocated = 1;
 	  if (l->l_relro_size)
@@ -1857,7 +1866,7 @@ cannot allocate TLS data structures for initial thread");
       /* If we are profiling we also must do lazy reloaction.  */
       GLRO(dl_lazy) |= consider_profiling;
 
-      l = GL(dl_loaded);
+      l = main_map;
       while (l->l_next)
 	l = l->l_next;
 
@@ -1906,7 +1915,7 @@ cannot allocate TLS data structures for initial thread");
 	  /* There was an explicit ref to the dynamic linker as a shared lib.
 	     Re-relocate ourselves with user-controlled symbol definitions.  */
 	  HP_TIMING_NOW (start);
-	  _dl_relocate_object (&GL(dl_rtld_map), GL(dl_loaded)->l_scope, 0, 0);
+	  _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0);
 	  HP_TIMING_NOW (stop);
 	  HP_TIMING_DIFF (add, start, stop);
 	  HP_TIMING_ACCUM_NT (relocate_time, add);
@@ -2323,20 +2332,24 @@ print_statistics (hp_timing_t *rtld_total_timep)
 #endif
 
   unsigned long int num_relative_relocations = 0;
-  struct r_scope_elem *scope = &GL(dl_loaded)->l_searchlist;
-  unsigned int i;
-
-  for (i = 0; i < scope->r_nlist; i++)
+  for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
     {
-      struct link_map *l = scope->r_list [i];
+      struct r_scope_elem *scope = &GL(dl_ns)[ns]._ns_loaded->l_searchlist;
 
-      if (!l->l_addr)
-	continue;
+      for (unsigned int i = 0; i < scope->r_nlist; i++)
+	{
+	  struct link_map *l = scope->r_list [i];
+
+	  if (!l->l_addr)
+	    continue;
 
-      if (l->l_info[VERSYMIDX (DT_RELCOUNT)])
-	num_relative_relocations += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val;
-      if (l->l_info[VERSYMIDX (DT_RELACOUNT)])
-	num_relative_relocations += l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val;
+	  if (l->l_info[VERSYMIDX (DT_RELCOUNT)])
+	    num_relative_relocations
+	      += l->l_info[VERSYMIDX (DT_RELCOUNT)]->d_un.d_val;
+	  if (l->l_info[VERSYMIDX (DT_RELACOUNT)])
+	    num_relative_relocations
+	      += l->l_info[VERSYMIDX (DT_RELACOUNT)]->d_un.d_val;
+	}
     }
 
   _dl_debug_printf ("                 number of relocations: %lu\n"