about summary refs log tree commit diff
path: root/elf/dl-load.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/dl-load.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/dl-load.c')
-rw-r--r--elf/dl-load.c90
1 files changed, 63 insertions, 27 deletions
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 15fff3c5e1..83d46f04ee 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -699,7 +699,7 @@ _dl_init_paths (const char *llp)
 
 #ifdef SHARED
   /* This points to the map of the main object.  */
-  l = GL(dl_loaded);
+  l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
   if (l != NULL)
     {
       assert (l->l_type != lt_loaded);
@@ -795,10 +795,10 @@ lose (int code, int fd, const char *name, char *realname, struct link_map *l,
       if (l->l_prev == NULL)
 	/* No other module loaded. This happens only in the static library,
 	   or in rtld under --verify.  */
-	GL(dl_loaded) = NULL;
+	GL(dl_ns)[l->l_ns]._ns_loaded = NULL;
       else
 	l->l_prev->l_next = NULL;
-      --GL(dl_nloaded);
+      --GL(dl_ns)[l->l_ns]._ns_nloaded;
       free (l);
     }
   free (realname);
@@ -815,7 +815,7 @@ static
 struct link_map *
 _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 			char *realname, struct link_map *loader, int l_type,
-			int mode, void **stack_endp)
+			int mode, void **stack_endp, Lmid_t nsid)
 {
   struct link_map *l = NULL;
   const ElfW(Ehdr) *header;
@@ -839,7 +839,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
     }
 
   /* Look again to see if the real name matched another already loaded.  */
-  for (l = GL(dl_loaded); l; l = l->l_next)
+  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
     if (l->l_ino == st.st_ino && l->l_dev == st.st_dev)
       {
 	/* The object is already loaded.
@@ -854,6 +854,31 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 	return l;
       }
 
+#ifdef SHARED
+  /* When loading into a namespace other than the base one we must
+     avoid loading ld.so since there can only be one copy.  Ever.  */
+  if (__builtin_expect (nsid != LM_ID_BASE, 0)
+      && ((st.st_ino == GL(dl_rtld_map).l_ino
+	   && st.st_dev == GL(dl_rtld_map).l_dev)
+	  || _dl_name_match_p (name, &GL(dl_rtld_map))))
+    {
+      /* This is indeed ld.so.  Create a new link_map which refers to
+	 the real one for almost everything.  */
+      l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+      if (l == NULL)
+	goto fail_new;
+
+      /* Refer to the real descriptor.  */
+      l->l_real = &GL(dl_rtld_map);
+
+      /* No need to bump the refcount of the real object, ld.so will
+	 never be unloaded.  */
+      __close (fd);
+
+      return l;
+    }
+#endif
+
   if (mode & RTLD_NOLOAD)
     /* We are not supposed to load the object unless it is already
        loaded.  So return now.  */
@@ -861,7 +886,7 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 
   /* Print debugging message.  */
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
-    _dl_debug_printf ("file=%s;  generating link map\n", name);
+    _dl_debug_printf ("file=%s [%lu];  generating link map\n", name, nsid);
 
   /* This is the ELF header.  We read it in `open_verify'.  */
   header = (void *) fbp->buf;
@@ -881,9 +906,10 @@ _dl_map_object_from_fd (const char *name, int fd, struct filebuf *fbp,
 #endif
 
   /* Enter the new object in the list of loaded objects.  */
-  l = _dl_new_object (realname, name, l_type, loader, mode);
-  if (__builtin_expect (! l, 0))
+  l = _dl_new_object (realname, name, l_type, loader, mode, nsid);
+  if (__builtin_expect (l == NULL, 0))
     {
+    fail_new:
       errstring = N_("cannot create shared object descriptor");
       goto call_lose_errno;
     }
@@ -1771,7 +1797,7 @@ open_path (const char *name, size_t namelen, int preloaded,
 struct link_map *
 internal_function
 _dl_map_object (struct link_map *loader, const char *name, int preloaded,
-		int type, int trace_mode, int mode)
+		int type, int trace_mode, int mode, Lmid_t nsid)
 {
   int fd;
   char *realname;
@@ -1779,8 +1805,11 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
   struct link_map *l;
   struct filebuf fb;
 
+  assert (nsid >= 0);
+  assert (nsid < DL_NNS);
+
   /* Look for this name among those already loaded.  */
-  for (l = GL(dl_loaded); l; l = l->l_next)
+  for (l = GL(dl_ns)[nsid]._ns_loaded; l; l = l->l_next)
     {
       /* If the requested name matches the soname of a loaded object,
 	 use that object.  Elide this check for names that have not
@@ -1812,9 +1841,9 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
   /* Display information if we are debugging.  */
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0)
       && loader != NULL)
-    _dl_debug_printf ("\nfile=%s;  needed by %s\n", name,
+    _dl_debug_printf ("\nfile=%s [%lu];  needed by %s [%lu]\n", name, nsid,
 			      loader->l_name[0]
-			      ? loader->l_name : rtld_progname);
+			      ? loader->l_name : rtld_progname, loader->l_ns);
 
   if (strchr (name, '/') == NULL)
     {
@@ -1823,7 +1852,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
       size_t namelen = strlen (name) + 1;
 
       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_LIBS, 0))
-	_dl_debug_printf ("find library=%s; searching\n", name);
+	_dl_debug_printf ("find library=%s [%lu]; searching\n", name, nsid);
 
       fd = -1;
 
@@ -1839,12 +1868,15 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 			      &realname, &fb);
 
 	  /* If dynamically linked, try the DT_RPATH of the executable
-             itself.  */
-	  l = GL(dl_loaded);
-	  if (fd == -1 && l && l->l_type != lt_loaded && l != loader
-	      && l->l_rpath_dirs.dirs != (void *) -1)
-	    fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
-			    &realname, &fb);
+             itself.  NB: we do this for lookups in any namespace.  */
+	  if (fd == -1)
+	    {
+	      l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+	      if (l && l->l_type != lt_loaded && l != loader
+		  && l->l_rpath_dirs.dirs != (void *) -1)
+		fd = open_path (name, namelen, preloaded, &l->l_rpath_dirs,
+				&realname, &fb);
+	    }
 	}
 
       /* Try the LD_LIBRARY_PATH environment variable.  */
@@ -1870,7 +1902,8 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 	  if (cached != NULL)
 	    {
 #ifdef SHARED
-	      l = loader ?: GL(dl_loaded);
+	      // XXX Correct to unconditionally default to namespace 0?
+	      l = loader ?: GL(dl_ns)[LM_ID_BASE]._ns_loaded;
 #else
 	      l = loader;
 #endif
@@ -1920,7 +1953,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
       /* Finally, try the default path.  */
       if (fd == -1
-	  && ((l = loader ?: GL(dl_loaded)) == NULL
+	  && ((l = loader ?: GL(dl_ns)[nsid]._ns_loaded) == NULL
 	      || __builtin_expect (!(l->l_flags_1 & DF_1_NODEFLIB), 1))
 	  && rtld_search_dirs.dirs != (void *) -1)
 	fd = open_path (name, namelen, preloaded, &rtld_search_dirs,
@@ -1966,7 +1999,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 	  /* Enter the new object in the list of loaded objects.  */
 	  if ((name_copy = local_strdup (name)) == NULL
 	      || (l = _dl_new_object (name_copy, name, type, loader,
-				      mode)) == NULL)
+				      mode, nsid)) == NULL)
 	    _dl_signal_error (ENOMEM, name, NULL,
 			      N_("cannot create shared object descriptor"));
 	  /* Signal that this is a faked entry.  */
@@ -1987,7 +2020,7 @@ _dl_map_object (struct link_map *loader, const char *name, int preloaded,
 
   void *stack_end = __libc_stack_end;
   return _dl_map_object_from_fd (name, fd, &fb, realname, loader, type, mode,
-				 &stack_end);
+				 &stack_end, nsid);
 }
 
 
@@ -2047,10 +2080,13 @@ _dl_rtld_di_serinfo (struct link_map *loader, Dl_serinfo *si, bool counting)
       while (l != NULL);
 
       /* If dynamically linked, try the DT_RPATH of the executable itself.  */
-      l = GL(dl_loaded);
-      if (l != NULL && l->l_type != lt_loaded && l != loader)
-	if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
-	  add_path (&l->l_rpath_dirs, XXX_RPATH);
+      if (loader->l_ns == LM_ID_BASE)
+	{
+	  l = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+	  if (l != NULL && l->l_type != lt_loaded && l != loader)
+	    if (cache_rpath (l, &l->l_rpath_dirs, DT_RPATH, "RPATH"))
+	      add_path (&l->l_rpath_dirs, XXX_RPATH);
+	}
     }
 
   /* Try the LD_LIBRARY_PATH environment variable.  */