about summary refs log tree commit diff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/Makefile2
-rw-r--r--elf/dl-close.c23
-rw-r--r--elf/dl-object.c6
-rw-r--r--elf/dl-open.c50
4 files changed, 78 insertions, 3 deletions
diff --git a/elf/Makefile b/elf/Makefile
index 0831662715..160d901526 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -106,7 +106,7 @@ tests = loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
 	reldep reldep2 reldep3 reldep4 $(tests-nodelete-$(have-z-nodelete)) \
 	$(tests-nodlopen-$(have-z-nodlopen)) neededtest neededtest2 \
 	neededtest3 neededtest4 unload2 lateglobal initfirst global \
-	restest2 next #dblload dblunload
+	restest2 next dblload dblunload
 test-srcs = tst-pathopt
 tests-vis-yes = vismain
 tests-nodelete-yes = nodelete
diff --git a/elf/dl-close.c b/elf/dl-close.c
index e83865f0a1..dfc204d478 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -146,6 +146,25 @@ _dl_close (void *_map)
 	      (imap, (void *) imap->l_addr
 		     + imap->l_info[DT_FINI]->d_un.d_ptr)) ();
 	}
+      else if (new_opencount[i] != 0 && imap->l_type == lt_loaded)
+	{
+	  /* The object is still used.  But the object we are unloading
+	     right now is responsible for loading it and therefore we
+	     have the search list of the current object in its scope.
+	     Remove it.  */
+	  struct r_scope_elem **runp = imap->l_scope;
+
+	  while (*runp != NULL)
+	    if (*runp == &map->l_searchlist)
+	      {
+		/* Copy all later elements.  */
+		while ((runp[0] = runp[1]) != NULL)
+		  ++runp;
+		break;
+	      }
+	  else
+	    ++runp;
+	}
 
       /* Store the new l_opencount value.  */
       imap->l_opencount = new_opencount[i];
@@ -241,6 +260,10 @@ _dl_close (void *_map)
 	  if (imap != map)
 	      free (imap->l_initfini);
 
+	  /* Remove the scope array if we allocated it.  */
+	  if (imap->l_scope != imap->l_scope_mem)
+	    free (imap->l_scope);
+
 	  if (imap->l_phdr_allocated)
 	    free ((void *) imap->l_phdr);
 
diff --git a/elf/dl-object.c b/elf/dl-object.c
index 07e428e8e6..9c32c08ff2 100644
--- a/elf/dl-object.c
+++ b/elf/dl-object.c
@@ -50,6 +50,12 @@ _dl_new_object (char *realname, const char *libname, int type,
   new->l_loader = loader;
   /* new->l_global = 0;	We use calloc therefore not necessary.  */
 
+  /* Use the 'l_scope_mem' array by default for the the 'l_scope'
+     information.  If we need more entries we will allocate a large
+     array dynamically.  */
+  new->l_scope = new->l_scope_mem;
+  new->l_scope_max = sizeof (new->l_scope_mem) / sizeof (new->l_scope_mem[0]);
+
   /* Counter for the scopes we have to handle.  */
   idx = 0;
 
diff --git a/elf/dl-open.c b/elf/dl-open.c
index ec88c79a27..f79c317da8 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -295,9 +295,55 @@ dl_open_worker (void *a)
       l = l->l_prev;
     }
 
-  /* Increment the open count for all dependencies.  */
+  /* Increment the open count for all dependencies.  If the file is
+     not loaded as a dependency here add the search list of the newly
+     loaded object to the scope.  */
   for (i = 0; i < new->l_searchlist.r_nlist; ++i)
-    ++new->l_searchlist.r_list[i]->l_opencount;
+    if (++new->l_searchlist.r_list[i]->l_opencount > 1
+	&& new->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;
+	size_t cnt = 0;
+
+	while (*runp != NULL)
+	  {
+	    ++cnt;
+	    ++runp;
+	  }
+
+	if (__builtin_expect (cnt + 1 < imap->l_scope_max, 0))
+	  {
+	    /* The 'r_scope' array is too small.  Allocate a new one
+	       dynamically.  */
+	    struct r_scope_elem **newp;
+	    size_t new_size = imap->l_scope_max * 2;
+
+	    if (imap->l_scope == imap->l_scope_mem)
+	      {
+		newp = (struct r_scope_elem **)
+		  malloc (new_size * sizeof (struct r_scope_elem *));
+		if (newp == NULL)
+		  _dl_signal_error (ENOMEM, "dlopen", NULL,
+				    N_("cannot create scope list"));
+		imap->l_scope = memcpy (newp, imap->l_scope,
+					cnt * imap->l_scope_max);
+	      }
+	    else
+	      {
+		newp = (struct r_scope_elem **)
+		  realloc (imap->l_scope,
+			   new_size * sizeof (struct r_scope_elem *));
+		if (newp == NULL)
+		  _dl_signal_error (ENOMEM, "dlopen", NULL,
+				    N_("cannot create scope list"));
+		imap->l_scope = newp;
+	      }
+
+	    imap->l_scope[cnt++] = &new->l_searchlist;
+	    imap->l_scope[cnt] = NULL;
+	  }
+      }
 
   /* Run the initializer functions of new objects.  */
   _dl_init (new, __libc_argc, __libc_argv, __environ);