summary refs log tree commit diff
path: root/elf/dl-open.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-open.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-open.c')
-rw-r--r--elf/dl-open.c129
1 files changed, 84 insertions, 45 deletions
diff --git a/elf/dl-open.c b/elf/dl-open.c
index c9b4a45596..34e2aff15e 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -72,6 +72,8 @@ struct dl_open_args
   /* This is the caller if _dl_open().  */
   const void *caller_dl_open;
   struct link_map *map;
+  /* Namespace ID.  */
+  Lmid_t nsid;
 };
 
 
@@ -101,15 +103,17 @@ add_to_global (struct link_map *new)
      in an realloc() call.  Therefore we allocate a completely new
      array the first time we have to add something to the locale scope.  */
 
-  if (GL(dl_global_scope_alloc) == 0)
+  if (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc == 0)
     {
       /* This is the first dynamic object given global scope.  */
-      GL(dl_global_scope_alloc) = GL(dl_main_searchlist)->r_nlist + to_add + 8;
+      GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
+	= GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add + 8;
       new_global = (struct link_map **)
-	malloc (GL(dl_global_scope_alloc) * sizeof (struct link_map *));
+	malloc (GL(dl_ns)[new->l_ns]._ns_global_scope_alloc
+		* sizeof (struct link_map *));
       if (new_global == NULL)
 	{
-	  GL(dl_global_scope_alloc) = 0;
+	  GL(dl_ns)[new->l_ns]._ns_global_scope_alloc = 0;
 	nomem:
 	  GLRO(dl_signal_error) (ENOMEM, new->l_libname->name, NULL,
 				 N_("cannot extend global scope"));
@@ -117,25 +121,26 @@ add_to_global (struct link_map *new)
 	}
 
       /* Copy over the old entries.  */
-      memcpy (new_global, GL(dl_main_searchlist)->r_list,
-	      (GL(dl_main_searchlist)->r_nlist * sizeof (struct link_map *)));
-
-      GL(dl_main_searchlist)->r_list = new_global;
+      GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list
+	= memcpy (new_global,
+		  GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
+		  (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist
+		   * sizeof (struct link_map *)));
     }
-  else if (GL(dl_main_searchlist)->r_nlist + to_add
-	   > GL(dl_global_scope_alloc))
+  else if (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist + to_add
+	   > GL(dl_ns)[new->l_ns]._ns_global_scope_alloc)
     {
       /* We have to extend the existing array of link maps in the
 	 main map.  */
       new_global = (struct link_map **)
-	realloc (GL(dl_main_searchlist)->r_list,
-		 ((GL(dl_global_scope_alloc) + to_add + 8)
+	realloc (GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list,
+		 ((GL(dl_ns)[new->l_ns]._ns_global_scope_alloc + to_add + 8)
 		  * sizeof (struct link_map *)));
       if (new_global == NULL)
 	goto nomem;
 
-      GL(dl_global_scope_alloc) += to_add + 8;
-      GL(dl_main_searchlist)->r_list = new_global;
+      GL(dl_ns)[new->l_ns]._ns_global_scope_alloc += to_add + 8;
+      GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list = new_global;
     }
 
   /* Now add the new entries.  */
@@ -146,9 +151,9 @@ add_to_global (struct link_map *new)
       if (map->l_global == 0)
 	{
 	  map->l_global = 1;
-	  GL(dl_main_searchlist)->r_list[GL(dl_main_searchlist)->r_nlist]
+	  GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_list[GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist]
 	    = map;
-	  ++GL(dl_main_searchlist)->r_nlist;
+	  ++GL(dl_ns)[new->l_ns]._ns_main_searchlist->r_nlist;
 	}
     }
 
@@ -175,28 +180,34 @@ dl_open_worker (void *a)
     GLRO(dl_signal_error) (0, "dlopen", NULL, N_("invalid caller"));
 
   /* Determine the caller's map if necessary.  This is needed in case
-     we have a DST or when the file name has no path in which case we
-     need to look along the RUNPATH/RPATH of the caller.  */
+     we have a DST, when we don't know the namespace ID we have to put
+     the new object in, or when the file name has no path in which
+     case we need to look along the RUNPATH/RPATH of the caller.  */
   const char *dst = strchr (file, '$');
-  if (dst != NULL || strchr (file, '/') == NULL)
+  if (dst != NULL || args->nsid == __LM_ID_CALLER
+      || strchr (file, '/') == NULL)
     {
       const void *caller_dlopen = args->caller_dlopen;
 
-      /* We have to find out from which object the caller is calling.  */
-      call_map = NULL;
-      for (l = GL(dl_loaded); l; l = l->l_next)
-	if (caller_dlopen >= (const void *) l->l_map_start
-	    && caller_dlopen < (const void *) l->l_map_end)
-	  {
-	    /* There must be exactly one DSO for the range of the virtual
-	       memory.  Otherwise something is really broken.  */
-	    call_map = l;
-	    break;
-	  }
+      /* We have to find out from which object the caller is calling.
+	 By default we assume this is the main application.  */
+      call_map = GL(dl_ns)[LM_ID_BASE]._ns_loaded;
+
+      for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
+	for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
+	  if (caller_dlopen >= (const void *) l->l_map_start
+	      && caller_dlopen < (const void *) l->l_map_end)
+	    {
+	      /* There must be exactly one DSO for the range of the virtual
+		 memory.  Otherwise something is really broken.  */
+	      assert (ns == l->l_ns);
+	      call_map = l;
+	      goto found_caller;
+	    }
 
-      if (call_map == NULL)
-	/* In this case we assume this is the main application.  */
-	call_map = GL(dl_loaded);
+    found_caller:
+      if (args->nsid == __LM_ID_CALLER)
+	args->nsid = call_map->l_ns;
     }
 
   /* Maybe we have to expand a DST.  */
@@ -238,7 +249,7 @@ dl_open_worker (void *a)
 
   /* Load the named object.  */
   args->map = new = GLRO(dl_map_object) (call_map, file, 0, lt_loaded, 0,
-					 mode | __RTLD_CALLMAP);
+					 mode | __RTLD_CALLMAP, args->nsid);
 
   /* If the pointer returned is NULL this means the RTLD_NOLOAD flag is
      set and the object is not already loaded.  */
@@ -252,21 +263,30 @@ dl_open_worker (void *a)
     /* This happens only if we load a DSO for 'sprof'.  */
     return;
 
+  /* This object is directly loaded.  */
+  ++new->l_direct_opencount;
+
   /* It was already open.  */
   if (__builtin_expect (new->l_searchlist.r_list != NULL, 0))
     {
       /* Let the user know about the opencount.  */
       if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
-	GLRO(dl_debug_printf) ("opening file=%s; opencount == %u\n\n",
-			       new->l_name, new->l_opencount);
+	GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
+			       new->l_name, new->l_ns, new->l_opencount);
 
       /* If the user requested the object to be in the global namespace
 	 but it is not so far, add it now.  */
       if ((mode & RTLD_GLOBAL) && new->l_global == 0)
 	(void) add_to_global (new);
 
-      /* Increment just the reference counter of the object.  */
-      ++new->l_opencount;
+      if (new->l_direct_opencount == 1)
+	/* This is the only direct reference.  Increment all the
+	   dependencies' reference counter.  */
+	for (i = 0; i < new->l_searchlist.r_nlist; ++i)
+	  ++new->l_searchlist.r_list[i]->l_opencount;
+      else
+	/* Increment just the reference counter of the object.  */
+	++new->l_opencount;
 
       return;
     }
@@ -277,8 +297,9 @@ dl_open_worker (void *a)
 
   /* So far, so good.  Now check the versions.  */
   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
-    if (new->l_searchlist.r_list[i]->l_versions == NULL)
-      (void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i], 0, 0);
+    if (new->l_searchlist.r_list[i]->l_real->l_versions == NULL)
+      (void) GLRO(dl_check_map_versions) (new->l_searchlist.r_list[i]->l_real,
+					  0, 0);
 
 #ifdef SCOPE_DEBUG
   show_scope (new);
@@ -295,7 +316,7 @@ dl_open_worker (void *a)
     l = l->l_next;
   while (1)
     {
-      if (! l->l_relocated)
+      if (! l->l_real->l_relocated)
 	{
 #ifdef SHARED
 	  if (GLRO(dl_profile) != NULL)
@@ -349,7 +370,7 @@ dl_open_worker (void *a)
      loaded object to the scope.  */
   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
     if (++new->l_searchlist.r_list[i]->l_opencount > 1
-	&& new->l_searchlist.r_list[i]->l_type == lt_loaded)
+	&& new->l_real->l_searchlist.r_list[i]->l_type == lt_loaded)
       {
 	struct link_map *imap = new->l_searchlist.r_list[i];
 	struct r_scope_elem **runp = imap->l_scope;
@@ -503,14 +524,14 @@ cannot create TLS data structures"));
 
   /* Let the user know about the opencount.  */
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_FILES, 0))
-    GLRO(dl_debug_printf) ("opening file=%s; opencount == %u\n\n",
-			   new->l_name, new->l_opencount);
+    GLRO(dl_debug_printf) ("opening file=%s [%lu]; opencount=%u\n\n",
+			   new->l_name, new->l_ns, new->l_opencount);
 }
 
 
 void *
 internal_function
-_dl_open (const char *file, int mode, const void *caller_dlopen)
+_dl_open (const char *file, int mode, const void *caller_dlopen, Lmid_t nsid)
 {
   struct dl_open_args args;
   const char *objname;
@@ -525,11 +546,29 @@ _dl_open (const char *file, int mode, const void *caller_dlopen)
   /* Make sure we are alone.  */
   __rtld_lock_lock_recursive (GL(dl_load_lock));
 
+  if (nsid == LM_ID_NEWLM)
+    {
+      /* Find a new namespace.  */
+      for (nsid = 1; nsid < DL_NNS; ++nsid)
+	if (GL(dl_ns)[nsid]._ns_loaded == NULL)
+	  break;
+
+      if (nsid == DL_NNS)
+	{
+	  /* No more namespace available.  */
+	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+	  GLRO(dl_signal_error) (EINVAL, file, NULL, N_("\
+no more namespaces available for dlmopen()"));
+	}
+    }
+
   args.file = file;
   args.mode = mode;
   args.caller_dlopen = caller_dlopen;
   args.caller_dl_open = RETURN_ADDRESS (0);
   args.map = NULL;
+  args.nsid = nsid;
   errcode = GLRO(dl_catch_error) (&objname, &errstring, dl_open_worker, &args);
 
 #ifndef MAP_COPY