diff options
Diffstat (limited to 'elf/dl-fini.c')
-rw-r--r-- | elf/dl-fini.c | 271 |
1 files changed, 104 insertions, 167 deletions
diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 3cd7e7bbff..f43f4a00ed 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -1,5 +1,5 @@ /* Call the termination functions of loaded shared objects. - Copyright (C) 1995,96,1998-2002,2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1995,96,1998-2002,2004 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -29,94 +29,6 @@ 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 @@ -136,29 +48,16 @@ _dl_fini (void) /* We run the destructors of the main namespaces last. As for the other namespaces, we pick run the destructors in them in reverse order of the namespace ID. */ -#ifdef SHARED - int do_audit = 0; - again: -#endif - for (Lmid_t ns = DL_NNS - 1; ns >= 0; --ns) + for (Lmid_t cnt = DL_NNS - 1; cnt >= 0; --cnt) { /* Protect against concurrent loads and unloads. */ __rtld_lock_lock_recursive (GL(dl_load_lock)); - unsigned int nmaps = 0; - 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)[ns]._ns_loaded->l_auditing != do_audit -#endif - ) - goto out; + unsigned int nloaded = GL(dl_ns)[cnt]._ns_nloaded; /* XXX Could it be (in static binaries) that there is no object loaded? */ - assert (ns != LM_ID_BASE || nloaded > 0); + assert (cnt != LM_ID_BASE || nloaded > 0); /* Now we can allocate an array to hold all the pointers and copy the pointers in. */ @@ -177,28 +76,86 @@ _dl_fini (void) unsigned int i; struct link_map *l; - 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) + for (l = GL(dl_ns)[cnt]._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; - l->l_idx = i; - ++i; + maps[i++] = l; - /* Bump l_direct_opencount of all objects so that they are - not dlclose()ed from underneath us. */ - ++l->l_direct_opencount; + /* Bump l_opencount of all objects so that they are not + dlclose()ed from underneath us. */ + ++l->l_opencount; } - assert (ns != LM_ID_BASE || i == nloaded); - assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1); - nmaps = i; + assert (cnt != LM_ID_BASE || i == nloaded); + assert (cnt == LM_ID_BASE || i == nloaded || i == nloaded - 1); + unsigned int nmaps = i; if (nmaps != 0) - /* Now we have to do the sorting. */ - _dl_sort_fini (GL(dl_ns)[ns]._ns_loaded, maps, nmaps, NULL, ns); + { + /* 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; + } + } + } + } + } + } /* 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 @@ -206,7 +163,6 @@ _dl_fini (void) high and will be decremented in this loop. So we release the lock so that some code which might be called from a destructor can directly or indirectly access the lock. */ - out: __rtld_lock_unlock_recursive (GL(dl_load_lock)); /* 'maps' now contains the objects in the right order. Now call the @@ -220,68 +176,49 @@ _dl_fini (void) /* Make sure nothing happens if we are called twice. */ l->l_init_called = 0; + /* Don't call the destructors for objects we are not + supposed to. */ + if (l->l_name[0] == '\0' && l->l_type == lt_executable) + continue; + /* Is there a destructor function? */ - if (l->l_info[DT_FINI_ARRAY] != NULL - || l->l_info[DT_FINI] != NULL) + if (l->l_info[DT_FINI_ARRAY] == NULL + && l->l_info[DT_FINI] == NULL) + continue; + + /* When debugging print a message first. */ + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_IMPCALLS, + 0)) + _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", + l->l_name[0] ? l->l_name : rtld_progname, + cnt); + + /* First see whether an array is given. */ + if (l->l_info[DT_FINI_ARRAY] != NULL) { - /* When debugging print a message first. */ - if (__builtin_expect (GLRO(dl_debug_mask) - & DL_DEBUG_IMPCALLS, 0)) - _dl_debug_printf ("\ncalling fini: %s [%lu]\n\n", - l->l_name[0] ? l->l_name : rtld_progname, - ns); - - /* First see whether an array is given. */ - if (l->l_info[DT_FINI_ARRAY] != NULL) - { - ElfW(Addr) *array = - (ElfW(Addr) *) (l->l_addr - + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); - unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))); - while (i-- > 0) - ((fini_t) array[i]) (); - } - - /* Next try the old-style destructor. */ - if (l->l_info[DT_FINI] != NULL) - ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + ElfW(Addr) *array = + (ElfW(Addr) *) (l->l_addr + + l->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int i = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + while (i-- > 0) + ((fini_t) array[i]) (); } -#ifdef SHARED - /* Auditing checkpoint: another object closed. */ - if (!do_audit && __builtin_expect (GLRO(dl_naudit) > 0, 0)) - { - struct audit_ifaces *afct = GLRO(dl_audit); - for (unsigned int cnt = 0; cnt < GLRO(dl_naudit); ++cnt) - { - if (afct->objclose != NULL) - /* Return value is ignored. */ - (void) afct->objclose (&l->l_audit[cnt].cookie); - - afct = afct->next; - } - } -#endif + /* Next try the old-style destructor. */ + if (l->l_info[DT_FINI] != NULL) + ((fini_t) DL_DT_FINI_ADDRESS (l, l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); } /* Correct the previous increment. */ - --l->l_direct_opencount; + --l->l_opencount; } } -#ifdef SHARED - if (! do_audit && GLRO(dl_naudit) > 0) - { - do_audit = 1; - goto again; - } - if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_STATISTICS, 0)) _dl_debug_printf ("\nruntime linker statistics:\n" " final number of relocations: %lu\n" "final number of relocations from cache: %lu\n", GL(dl_num_relocations), GL(dl_num_cache_relocations)); -#endif } |