summaryrefslogtreecommitdiff
path: root/elf/dl-deps.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-01-19 15:32:35 -0500
committerUlrich Drepper <drepper@gmail.com>2011-01-19 16:00:11 -0500
commit968dad0ab1f367a087ff4ad503b511dd0c565adc (patch)
treed13459628d20f7c091850755ebc120fb81156ca3 /elf/dl-deps.c
parent86e9235918a715095a1f5bb1c1db28fae7fca22b (diff)
Fix ordering of DSO constructors and destructors.
Diffstat (limited to 'elf/dl-deps.c')
-rw-r--r--elf/dl-deps.c86
1 files changed, 49 insertions, 37 deletions
diff --git a/elf/dl-deps.c b/elf/dl-deps.c
index a51fb6e414..440fb563da 100644
--- a/elf/dl-deps.c
+++ b/elf/dl-deps.c
@@ -1,5 +1,5 @@
/* Load the dependencies of a mapped object.
- Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010
+ Copyright (C) 1996-2003, 2004, 2005, 2006, 2007, 2010, 2011
Free Software Foundation, Inc.
This file is part of the GNU C Library.
@@ -591,7 +591,7 @@ Filters not supported with LD_TRACE_PRELINKING"));
/* Need to allocate new array of relocation dependencies. */
struct link_map_reldeps *l_reldeps;
l_reldeps = malloc (sizeof (*l_reldeps)
- + map->l_reldepsmax
+ + map->l_reldepsmax
* sizeof (struct link_map *));
if (l_reldeps == NULL)
/* Bad luck, keep the reldeps duplicated between
@@ -616,48 +616,60 @@ Filters not supported with LD_TRACE_PRELINKING"));
/* Now determine the order in which the initialization has to happen. */
memcpy (l_initfini, map->l_searchlist.r_list,
nlist * sizeof (struct link_map *));
+
/* We can skip looking for the binary itself which is at the front
- of the search list. Look through the list backward so that circular
- dependencies are not changing the order. */
- for (i = 1; i < nlist; ++i)
+ of the search list. */
+ assert (nlist > 1);
+ i = 1;
+ bool seen[nlist];
+ memset (seen, false, nlist * sizeof (seen[0]));
+ while (1)
{
- struct link_map *l = map->l_searchlist.r_list[i];
- unsigned int j;
- unsigned int k;
-
- /* Find the place in the initfini list where the map is currently
- located. */
- for (j = 1; l_initfini[j] != l; ++j)
- ;
-
- /* Find all object for which the current one is a dependency and
- move the found object (if necessary) in front. */
- for (k = j + 1; k < nlist; ++k)
+ /* Keep track of which object we looked at this round. */
+ seen[i] = true;
+ struct link_map *thisp = l_initfini[i];
+
+ /* Find the last object in the list for which the current one is
+ a dependency and move the current object behind the object
+ with the dependency. */
+ unsigned int k = nlist - 1;
+ while (k > i)
{
- struct link_map **runp;
-
- runp = l_initfini[k]->l_initfini;
+ struct link_map **runp = l_initfini[k]->l_initfini;
if (runp != NULL)
- {
- while (*runp != NULL)
- if (__builtin_expect (*runp++ == l, 0))
- {
- struct link_map *here = l_initfini[k];
-
- /* Move it now. */
- memmove (&l_initfini[j] + 1, &l_initfini[j],
- (k - j) * sizeof (struct link_map *));
- l_initfini[j] = here;
+ /* Look through the dependencies of the object. */
+ while (*runp != NULL)
+ if (__builtin_expect (*runp++ == thisp, 0))
+ {
+ /* Move the current object to the back past the last
+ object with it as the dependency. */
+ memmove (&l_initfini[i], &l_initfini[i + 1],
+ (k - i) * sizeof (l_initfini[0]));
+ l_initfini[k] = thisp;
+
+ if (seen[i + 1])
+ {
+ ++i;
+ goto next_clear;
+ }
+
+ memmove (&seen[i], &seen[i + 1], (k - i) * sizeof (seen[0]));
+ seen[k] = true;
+
+ goto next;
+ }
+
+ --k;
+ }
- /* Don't insert further matches before the last
- entry moved to the front. */
- ++j;
+ if (++i == nlist)
+ break;
+ next_clear:
+ memset (&seen[i], false, (nlist - i) * sizeof (seen[0]));
- break;
- }
- }
- }
+ next:;
}
+
/* Terminate the list of dependencies. */
l_initfini[nlist] = NULL;
atomic_write_barrier ();