about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--elf/dl-close.c64
-rw-r--r--elf/dl-fini.c177
-rw-r--r--sysdeps/generic/ldsodefs.h5
4 files changed, 152 insertions, 103 deletions
diff --git a/ChangeLog b/ChangeLog
index c2f12b6085..608538fd98 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2005-03-18  Ulrich Drepper  <drepper@redhat.com>
+
+	* elf/dl-fini.c (_dl_fini): Split sorting of the maps in separate
+	function _dl_sort_fini.
+	(_dl_sort_fini): New function.
+	* sysdeps/generic/ldsodefs.h: Declare _dl_sort_fini.
+	* elf/dl-close.c (_dl_close): Call _dl_sort_fini before running
+	destructors to call them in the right order.
+
 2005-02-07  Steven Munroe  <sjmunroe@us.ibm.com>
 
 	* sysdeps/powerpc/bits/link.h (La_ppc64_regs): Add lr_vrsave.
diff --git a/elf/dl-close.c b/elf/dl-close.c
index 51b958dfa7..cd4fa7cfbe 100644
--- a/elf/dl-close.c
+++ b/elf/dl-close.c
@@ -136,15 +136,9 @@ _dl_close (void *_map)
       return;
     }
 
-#define NWORDS(n) (((n) + 8 * sizeof (unsigned long int) - 1) \
-		   / (sizeof (unsigned long int)))
-#define SETBIT(a, n) a[(n) / sizeof (unsigned long int)] \
-		       |= 1 << ((n) % (sizeof (unsigned long int)))
-#define ISSET(a, n) (a[(n) / sizeof (unsigned long int)] \
-		     & 1 << ((n) % (sizeof (unsigned long int))))
   const unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
-  unsigned long int used[NWORDS (nloaded)];
-  unsigned long int done[NWORDS (nloaded)];
+  char used[nloaded];
+  char done[nloaded];
   struct link_map *maps[nloaded];
 
   /* Run over the list and assign indeces to the link maps and enter
@@ -168,7 +162,7 @@ _dl_close (void *_map)
     {
       struct link_map *l = maps[done_index];
 
-      if (ISSET (done, done_index))
+      if (done[done_index])
 	/* Already handled.  */
 	continue;
 
@@ -176,12 +170,14 @@ _dl_close (void *_map)
       if (l->l_type == lt_loaded
 	  && l->l_direct_opencount == 0
 	  && (l->l_flags_1 & DF_1_NODELETE) == 0
-	  && !ISSET (used, done_index))
+	  && !used[done_index])
 	continue;
 
       /* We need this object and we handle it now.  */
-      SETBIT (done, done_index);
-      SETBIT (used, done_index);
+      done[done_index] = 1;
+      used[done_index] = 1;
+      /* Signal the object is still needed.  */
+      l->l_idx = -1;
 
       /* Mark all dependencies as used.  */
       if (l->l_initfini != NULL)
@@ -189,13 +185,16 @@ _dl_close (void *_map)
 	  struct link_map **lp = &l->l_initfini[1];
 	  while (*lp != NULL)
 	    {
-	      assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
-
-	      if (!ISSET (used, (*lp)->l_idx))
+	      if ((*lp)->l_idx != -1)
 		{
-		  SETBIT (used, (*lp)->l_idx);
-		  if ((*lp)->l_idx - 1 < done_index)
-		    done_index = (*lp)->l_idx - 1;
+		  assert ((*lp)->l_idx >= 0 && (*lp)->l_idx < nloaded);
+
+		  if (!used[(*lp)->l_idx])
+		    {
+		      used[(*lp)->l_idx] = 1;
+		      if ((*lp)->l_idx - 1 < done_index)
+			done_index = (*lp)->l_idx - 1;
+		    }
 		}
 
 	      ++lp;
@@ -207,17 +206,23 @@ _dl_close (void *_map)
 	  {
 	    struct link_map *jmap = l->l_reldeps[j];
 
-	    assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
-
-	    if (!ISSET (used, jmap->l_idx))
+	    if (jmap->l_idx != -1)
 	      {
-		SETBIT (used, jmap->l_idx);
-		if (jmap->l_idx - 1 < done_index)
-		  done_index = jmap->l_idx - 1;
+		assert (jmap->l_idx >= 0 && jmap->l_idx < nloaded);
+
+		if (!used[jmap->l_idx])
+		  {
+		    used[jmap->l_idx] = 1;
+		    if (jmap->l_idx - 1 < done_index)
+		      done_index = jmap->l_idx - 1;
+		  }
 	      }
 	  }
     }
 
+  /* Sort the entries.  */
+  _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nloaded, used, ns);
+
   /* Call all termination functions at once.  */
 #ifdef SHARED
   bool do_audit = GLRO(dl_naudit) > 0 && !GL(dl_ns)[ns]._ns_loaded->l_auditing;
@@ -231,7 +236,7 @@ _dl_close (void *_map)
       /* All elements must be in the same namespace.  */
       assert (imap->l_ns == ns);
 
-      if (!ISSET (used, i))
+      if (!used[i])
 	{
 	  assert (imap->l_type == lt_loaded
 		  && (imap->l_flags_1 & DF_1_NODELETE) == 0);
@@ -291,7 +296,7 @@ _dl_close (void *_map)
 	  if (i < first_loaded)
 	    first_loaded = i;
 	}
-      /* Else ISSET (used, i).  */
+      /* Else used[i].  */
       else if (imap->l_type == lt_loaded)
 	{
 	  if (imap->l_searchlist.r_list == NULL
@@ -320,8 +325,9 @@ _dl_close (void *_map)
 		  }
 	    }
 
-	  /* The loader is gone, so mark the object as not having one.  */
-	  if (imap->l_loader != NULL && !ISSET (used, imap->l_loader->l_idx))
+	  /* The loader is gone, so mark the object as not having one.
+	     Note: l_idx == -1 -> object will be removed.  */
+	  if (imap->l_loader != NULL && imap->l_loader->l_idx != -1)
 	    imap->l_loader = NULL;
 
 	  /* Remember where the first dynamically loaded object is.  */
@@ -370,7 +376,7 @@ _dl_close (void *_map)
   for (i = first_loaded; i < nloaded; ++i)
     {
       struct link_map *imap = maps[i];
-      if (!ISSET (used, i))
+      if (!used[i])
 	{
 	  assert (imap->l_type == lt_loaded);
 
diff --git a/elf/dl-fini.c b/elf/dl-fini.c
index a01b998ef0..3cd7e7bbff 100644
--- a/elf/dl-fini.c
+++ b/elf/dl-fini.c
@@ -29,6 +29,94 @@ typedef void (*fini_t) (void);
 
 void
 internal_function
+_dl_sort_fini (struct link_map *l, struct link_map **maps, size_t nmaps,
+	       char *used, Lmid_t ns)
+{
+  if (ns == LM_ID_BASE)
+    /* The main executable always comes first.  */
+    l = l->l_next;
+
+  for (; l != NULL; l = l->l_next)
+    /* Do not handle ld.so in secondary namespaces and object which
+       are not removed.  */
+    if (l == l->l_real && l->l_idx != -1)
+      {
+	/* Find the place in the 'maps' array.  */
+	unsigned int j;
+	for (j = ns == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
+	  assert (j < nmaps);
+
+	/* Find all object for which the current one is a dependency
+	   and move the found object (if necessary) in front.  */
+	for (unsigned int k = j + 1; k < nmaps; ++k)
+	  {
+	    struct link_map **runp = maps[k]->l_initfini;
+	    if (runp != NULL)
+	      {
+		while (*runp != NULL)
+		  if (*runp == l)
+		    {
+		      struct link_map *here = maps[k];
+
+		      /* Move it now.  */
+		      memmove (&maps[j] + 1,
+			       &maps[j], (k - j) * sizeof (struct link_map *));
+		      maps[j] = here;
+
+		      if (used != NULL)
+			{
+			  char here_used = used[k];
+
+			  memmove (&used[j] + 1,
+				   &used[j], (k - j) * sizeof (char));
+			  used[j] = here_used;
+			}
+
+		      ++j;
+
+		      break;
+		    }
+		  else
+		    ++runp;
+	      }
+
+	    if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
+	      {
+		unsigned int m = maps[k]->l_reldepsact;
+		struct link_map **relmaps = maps[k]->l_reldeps;
+
+		while (m-- > 0)
+		  {
+		    if (relmaps[m] == l)
+		      {
+			struct link_map *here = maps[k];
+
+			/* Move it now.  */
+			memmove (&maps[j] + 1,
+				 &maps[j],
+				 (k - j) * sizeof (struct link_map *));
+			maps[j] = here;
+
+			if (used != NULL)
+			  {
+			    char here_used = used[k];
+
+			    memmove (&used[j] + 1,
+				     &used[j], (k - j) * sizeof (char));
+			    used[j] = here_used;
+			  }
+
+			break;
+		      }
+		  }
+	      }
+	  }
+      }
+}
+
+
+void
+internal_function
 _dl_fini (void)
 {
   /* Lots of fun ahead.  We have to call the destructors for all still
@@ -52,25 +140,25 @@ _dl_fini (void)
   int do_audit = 0;
  again:
 #endif
-  for (Lmid_t cnt = DL_NNS - 1; cnt >= 0; --cnt)
+  for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns)
     {
       /* Protect against concurrent loads and unloads.  */
       __rtld_lock_lock_recursive (GL(dl_load_lock));
 
       unsigned int nmaps = 0;
-      unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded;
+      unsigned int nloaded = GL(dl_ns)[ns]._ns_nloaded;
       /* No need to do anything for empty namespaces or those used for
 	 auditing DSOs.  */
       if (nloaded == 0
 #ifdef SHARED
-	  || GL(dl_ns)[cnt]._ns_loaded->l_auditing != do_audit
+	  || GL(dl_ns)[ns]._ns_loaded->l_auditing != do_audit
 #endif
 	  )
 	goto out;
 
       /* XXX Could it be (in static binaries) that there is no object
 	 loaded?  */
-      assert (cnt != LM_ID_BASE || nloaded > 0);
+      assert (ns != LM_ID_BASE || nloaded > 0);
 
       /* Now we can allocate an array to hold all the pointers and copy
 	 the pointers in.  */
@@ -89,87 +177,28 @@ _dl_fini (void)
 
       unsigned int i;
       struct link_map *l;
-      assert (nloaded != 0 || GL(dl_ns)[cnt]._ns_loaded == NULL);
-      for (l = GL(dl_ns)[cnt]._ns_loaded, i = 0; l != NULL; l = l->l_next)
+      assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL);
+      for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next)
 	/* Do not handle ld.so in secondary namespaces.  */
 	if (l == l->l_real)
 	  {
 	    assert (i < nloaded);
 
-	    maps[i++] = l;
+	    maps[i] = l;
+	    l->l_idx = i;
+	    ++i;
 
 	    /* Bump l_direct_opencount of all objects so that they are
 	       not dlclose()ed from underneath us.  */
 	    ++l->l_direct_opencount;
 	  }
-      assert (cnt != LM_ID_BASE || i == nloaded);
-      assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1);
+      assert (ns != LM_ID_BASE || i == nloaded);
+      assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1);
       nmaps = i;
 
       if (nmaps != 0)
-	{
-	  /* Now we have to do the sorting.  */
-	  l = GL(dl_ns)[cnt]._ns_loaded;
-	  if (cnt == LM_ID_BASE)
-	    /* The main executable always comes first.  */
-	    l = l->l_next;
-	  for (; l != NULL; l = l->l_next)
-	    /* Do not handle ld.so in secondary namespaces.  */
-	    if (l == l->l_real)
-	      {
-		/* Find the place in the 'maps' array.  */
-		unsigned int j;
-		for (j = cnt == LM_ID_BASE ? 1 : 0; maps[j] != l; ++j)
-		  assert (j < nmaps);
-
-		/* Find all object for which the current one is a dependency
-		   and move the found object (if necessary) in front.  */
-		for (unsigned int k = j + 1; k < nmaps; ++k)
-		  {
-		    struct link_map **runp = maps[k]->l_initfini;
-		    if (runp != NULL)
-		      {
-			while (*runp != NULL)
-			  if (*runp == l)
-			    {
-			      struct link_map *here = maps[k];
-
-			      /* Move it now.  */
-			      memmove (&maps[j] + 1,
-				       &maps[j],
-				       (k - j) * sizeof (struct link_map *));
-			      maps[j++] = here;
-
-			      break;
-			    }
-			  else
-			    ++runp;
-		      }
-
-		    if (__builtin_expect (maps[k]->l_reldeps != NULL, 0))
-		      {
-			unsigned int m = maps[k]->l_reldepsact;
-			struct link_map **relmaps = maps[k]->l_reldeps;
-
-			while (m-- > 0)
-			  {
-			    if (relmaps[m] == l)
-			      {
-				struct link_map *here = maps[k];
-
-				/* Move it now.  */
-				memmove (&maps[j] + 1,
-					 &maps[j],
-					 (k - j) * sizeof (struct link_map *));
-				maps[j] = here;
-
-				break;
-			      }
-			  }
-		      }
-		  }
-	      }
-	}
+	/* Now we have to do the sorting.  */
+	_dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns);
 
       /* We do not rely on the linked list of loaded object anymore from
 	 this point on.  We have our own list here (maps).  The various
@@ -200,7 +229,7 @@ _dl_fini (void)
 					& DL_DEBUG_IMPCALLS, 0))
 		    _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n",
 				      l->l_name[0] ? l->l_name : rtld_progname,
-				      cnt);
+				      ns);
 
 		  /* First see whether an array is given.  */
 		  if (l->l_info[DT_FINI_ARRAY] != NULL)
@@ -247,7 +276,6 @@ _dl_fini (void)
       do_audit = 1;
       goto again;
     }
-#endif
 
   if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0))
     _dl_debug_printf ("\nruntime linker statistics:\n"
@@ -255,4 +283,5 @@ _dl_fini (void)
 		      "final number of relocations from cache: %lu\n",
 		      GL(dl_num_relocations),
 		      GL(dl_num_cache_relocations));
+#endif
 }
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
index a3cef20251..dd1b2c8345 100644
--- a/sysdeps/generic/ldsodefs.h
+++ b/sysdeps/generic/ldsodefs.h
@@ -892,6 +892,11 @@ extern void _dl_init (struct link_map *main_map, int argc, char **argv,
    initializer functions have completed.  */
 extern void _dl_fini (void) internal_function;
 
+/* Sort array MAPS according to dependencies of the contained objects.  */
+extern void _dl_sort_fini (struct link_map *l, struct link_map **maps,
+			   size_t nmaps, char *used, Lmid_t ns)
+     internal_function;
+
 /* The dynamic linker calls this function before and having changing
    any shared object mappings.  The `r_state' member of `struct r_debug'
    says what change is taking place.  This function's address is