diff options
author | Ulrich Drepper <drepper@redhat.com> | 2000-03-30 16:30:49 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2000-03-30 16:30:49 +0000 |
commit | dacc8ffa420575038f04c543c31065fea81d5732 (patch) | |
tree | e48ee55d563a39779776f3c7e02d76bc05a4cbb4 /elf/dl-fini.c | |
parent | 38e986ecd8aba6953cfa4e7f104c671100f00999 (diff) | |
download | glibc-dacc8ffa420575038f04c543c31065fea81d5732.zip glibc-dacc8ffa420575038f04c543c31065fea81d5732.tar.gz glibc-dacc8ffa420575038f04c543c31065fea81d5732.tar.bz2 |
Update.
2000-03-30 Ulrich Drepper <drepper@redhat.com>
Implement dynamic determination of constructor/destructor order in
the dynamic linker.
* elf/Versions [ld.so] (GLIBC_2.0): Remove _dl_init_next.
(GLIBC_2.2): Add _dl_init.
* elf/dl-close.c: Also call all destructors in FINI_ARRAY.
r_duplist is not anymore allocated separately. l_initfini is and
therefore free it if necessary.
* elf/dl-deps.c: If a searchlist has to be allocated, put all in one
malloc block. Otherwise allocate l_initfini list only.
Put dependencies for the object in l_initfini list.
Sort dependencies for the object to be loaded topologically.
* elf/dl-fini.c: Before running the destructors sort the topologically.
* elf/dl-init.c (_dl_init): Renamed from _dl_init_next. Rewrite to
call constructors instead of iterating over the pointers. Get list of
objects for which to run constructors from l_initfini element. Accept
argc, argv, and env as parameters and pass them to the constructors.
* elf/ld-load.c (_dl_map_object_from_fd): Initialize l_ldnum member
with size of dynamic section.
* elf/dl-open.c (dl_open_worker): Only call _dl_init instead of
_dl_init_next and calling constructors ourself.
* elf/dl-preinit.c (_dl_preinit): Renamed from _dl_preinit_next.
Take argc, argv, and env as parameters and pass them to the
constructors. Rewrite to call all constructors and not iterate over
the pointers.
* elf/dynamic-link.h: Don't relocate DT_FINI_ARRAY entry. Don't
precompute l_initcount and l_preinitcount.
* elf/link.h (struct link_map): Add l_ldnum member.
Make l_phdr_allocated part of the bitfield. Remove l_runcount,
l_initcount, and l_preinitcount. Add l_initfini.
* sysdeps/generic/ldsodefs.h: Replace _dl_init_next prototype with
one for _dl_init.
* sysdeps/i386/dl-machine (RTLD_START): Rewrite to match new init
function interface.
* sysdeps/unix/sysv/linux/init-first.h: Removed.
* sysdeps/unix/sysv/linux/Dist: Delete file here as well.
* sysdeps/unix/sysv/linux/init-first.c [PIC]: Don't use
SYSDEP_CALL_INIT. Make _init a strong alias of init. The calling
conventions now match.
* sysdeps/generic/libc-start.c: Calling __libc_init_first has no
effect for shared objects. Don't emit message and call only for
static library.
Diffstat (limited to 'elf/dl-fini.c')
-rw-r--r-- | elf/dl-fini.c | 163 |
1 files changed, 116 insertions, 47 deletions
diff --git a/elf/dl-fini.c b/elf/dl-fini.c index 41637c5..61dedd5 100644 --- a/elf/dl-fini.c +++ b/elf/dl-fini.c @@ -17,59 +17,128 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include <assert.h> +#include <string.h> #include <ldsodefs.h> + +/* Type of the constructor functions. */ +typedef void (*fini_t) (void); + + void internal_function _dl_fini (void) { + /* Lots of fun ahead. We have to call the destructors for all still + loaded objects. The problem is that the ELF specification now + demands that dependencies between the modules are taken into account. + I.e., the destructor for a module is called before the ones for any + of its dependencies. + + To make things more complicated, we cannot simply use the reverse + order of the constructors. Since the user might have loaded objects + using `dlopen' there are possibly several other modules with its + dependencies to be taken into account. Therefore we have to start + determining the order of the modules once again from the beginning. */ + unsigned int nloaded = 0; + unsigned int i; struct link_map *l; + struct link_map **maps; + + /* First count how many objects are there. */ + for (l = _dl_loaded; l != NULL; l = l->l_next) + ++nloaded; + + /* XXX Could it be (in static binaries) that there is no object loaded? */ + assert (nloaded > 0); + + /* Now we can allocate an array to hold all the pointers and copy + the pointers in. */ + maps = (struct link_map **) alloca (nloaded * sizeof (struct link_map *)); + for (l = _dl_loaded, nloaded = 0; l != NULL; l = l->l_next) + maps[nloaded++] = l; + + /* Now we have to do the sorting. */ + for (l = _dl_loaded->l_next; l != NULL; l = l->l_next) + { + unsigned int j; + unsigned int k; + + /* Find the place in the `maps' array. */ + for (j = 1; maps[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 < nloaded; ++k) + { + struct link_map **runp; + + 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; + } + } + } + + /* `maps' now contains the objects in the right order. Now call the + destructors. We have the process this array from the front. */ + for (i = 0; i < nloaded; ++i) + { + l = maps[i]; + + if (l->l_init_called) + { + /* 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) + continue; + + /* When debugging print a message first. */ + if (_dl_debug_impcalls) + _dl_debug_message (1, "\ncalling fini: ", + l->l_name[0] ? l->l_name : _dl_argv[0], + "\n\n", NULL); + + /* 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 sz = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + unsigned int cnt; + + for (cnt = 0; cnt < sz; ++cnt) + ((fini_t) (l->l_addr + array[cnt])) (); + } - for (l = _dl_loaded; l; l = l->l_next) - if (l->l_init_called) - { - int first = 1; - - /* 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; - - /* 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 sz = (l->l_info[DT_FINI_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))); - unsigned int cnt; - - for (cnt = 0; cnt < sz; ++cnt) - { - /* When debugging print a message first. */ - if (_dl_debug_impcalls && first) - _dl_debug_message (1, "\ncalling fini: ", - l->l_name[0] ? l->l_name : _dl_argv[0], - "\n\n", NULL); - first = 0; - - (*(void (*) (void)) (l->l_addr + array[cnt])) (); - } - } - - /* Next try the old-style destructor. */ - if (l->l_info[DT_FINI]) - { - /* When debugging print a message first. */ - if (_dl_debug_impcalls && first) - _dl_debug_message (1, "\ncalling fini: ", - l->l_name[0] ? l->l_name : _dl_argv[0], - "\n\n", NULL); - - (*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); - } - } + /* Next try the old-style destructor. */ + if (l->l_info[DT_FINI] != NULL) + ((fini_t) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) (); + } + } } |