diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | elf/dl-close.c | 64 | ||||
-rw-r--r-- | elf/dl-fini.c | 177 | ||||
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 5 |
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 |