From dacc8ffa420575038f04c543c31065fea81d5732 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 30 Mar 2000 16:30:49 +0000 Subject: Update. 2000-03-30 Ulrich Drepper 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. --- elf/Versions | 4 +- elf/dl-close.c | 41 ++++++++++---- elf/dl-deps.c | 95 +++++++++++++++++++++++++++---- elf/dl-fini.c | 163 ++++++++++++++++++++++++++++++++++++++--------------- elf/dl-init.c | 128 +++++++++++++++++++++++++---------------- elf/dl-load.c | 1 + elf/dl-open.c | 13 +---- elf/dl-preinit.c | 40 +++++++------ elf/dynamic-link.h | 13 ----- elf/link.h | 20 ++----- 10 files changed, 341 insertions(+), 177 deletions(-) (limited to 'elf') diff --git a/elf/Versions b/elf/Versions index b3d9d43..ca9b697 100644 --- a/elf/Versions +++ b/elf/Versions @@ -21,7 +21,7 @@ ld.so { # Those are in the dynamic linker, but used by libc.so. __libc_enable_secure; _dl_catch_error; _dl_check_all_versions; _dl_debug_initialize; _dl_debug_state; _dl_default_scope; - _dl_global_scope_end; _dl_init_next; _dl_lookup_symbol; + _dl_global_scope_end; _dl_lookup_symbol; _dl_map_object; _dl_map_object_deps; _dl_object_relocation_scope; _dl_relocate_object; _dl_signal_error; _dl_starting_up; _dl_sysdep_start; _r_debug; @@ -49,6 +49,6 @@ ld.so { _dl_dst_count; _dl_dst_substitute; } GLIBC_2.2 { - _dl_preinit_next; + _dl_preinit_next; _dl_init; } } diff --git a/elf/dl-close.c b/elf/dl-close.c index 0636d2e..7740787 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -1,5 +1,5 @@ /* Close a shared object opened by `_dl_open'. - Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1996, 1997, 1998, 1999, 2000 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 @@ -27,6 +27,10 @@ #include +/* Type of the constructor functions. */ +typedef void (*fini_t) (void); + + /* During the program run we must not modify the global data of loaded shared object simultanously in two threads. Therefore we protect `dlopen' and `dlclose' in dlclose.c. */ @@ -64,9 +68,9 @@ _dl_close (void *_map) /* Call all termination functions at once. */ for (i = 0; i < nsearchlist; ++i) { - struct link_map *imap = list[i]; + struct link_map *imap = map->l_initfini[i]; if (imap->l_opencount == 1 && imap->l_type == lt_loaded - && imap->l_info[DT_FINI] + && (imap->l_info[DT_FINI] || imap->l_info[DT_FINI_ARRAY]) /* Skip any half-cooked objects that were never initialized. */ && imap->l_init_called) { @@ -74,9 +78,25 @@ _dl_close (void *_map) if (_dl_debug_impcalls) _dl_debug_message (1, "\ncalling fini: ", imap->l_name, "\n\n", NULL); + /* Call its termination function. */ - (*(void (*) (void)) ((void *) imap->l_addr - + imap->l_info[DT_FINI]->d_un.d_ptr)) (); + if (imap->l_info[DT_FINI_ARRAY] != NULL) + { + ElfW(Addr) *array = + (ElfW(Addr) *) (imap->l_addr + + imap->l_info[DT_FINI_ARRAY]->d_un.d_ptr); + unsigned int sz = (imap->l_info[DT_FINI_ARRAYSZ]->d_un.d_val + / sizeof (ElfW(Addr))); + unsigned int cnt; + + for (cnt = 0; cnt < sz; ++cnt) + ((fini_t) (imap->l_addr + array[cnt])) (); + } + + /* Next try the old-style destructor. */ + if (imap->l_info[DT_FINI] != NULL) + (*(void (*) (void)) ((void *) imap->l_addr + + imap->l_info[DT_FINI]->d_un.d_ptr)) (); } } @@ -157,14 +177,13 @@ _dl_close (void *_map) while (lnp != NULL); /* Remove the searchlists. */ - if (imap->l_searchlist.r_duplist != imap->l_searchlist.r_list) + if (imap != map) { - /* If a r_list exists there always also is a r_duplist. */ - assert (imap->l_searchlist.r_list != NULL); - free (imap->l_searchlist.r_duplist); + if (imap->l_searchlist.r_list != NULL) + free (imap->l_searchlist.r_list); + else if (imap->l_initfini != NULL) + free (imap->l_initfini); } - if (imap != map && imap->l_searchlist.r_list != NULL) - free (imap->l_searchlist.r_list); if (imap->l_phdr_allocated) free ((void *) imap->l_phdr); diff --git a/elf/dl-deps.c b/elf/dl-deps.c index 26dd0f8..dc372e6 100644 --- a/elf/dl-deps.c +++ b/elf/dl-deps.c @@ -192,6 +192,17 @@ _dl_map_object_deps (struct link_map *map, for (runp = known; runp; ) { struct link_map *l = runp->map; + struct link_map **needed = NULL; + unsigned int nneeded = 0; + + /* Unless otherwise stated, this object is handled. */ + runp->done = 1; + + /* Allocate a temporary record to contain the references to the + dependencies of this object. */ + if (l->l_searchlist.r_list == NULL && l != map && l->l_ldnum > 0) + needed = (struct link_map **) alloca (l->l_ldnum + * sizeof (struct link_map *)); if (l->l_info[DT_NEEDED] || l->l_info[AUXTAG] || l->l_info[FILTERTAG]) { @@ -200,9 +211,6 @@ _dl_map_object_deps (struct link_map *map, struct list *orig; const ElfW(Dyn) *d; - /* Mark map as processed. */ - runp->done = 1; - args.strtab = strtab; args.map = l; args.trace_mode = trace_mode; @@ -250,6 +258,10 @@ _dl_map_object_deps (struct link_map *map, /* Set the mark bit that says it's already in the list. */ dep->l_reserved = 1; } + + /* Remember this dependency. */ + if (needed != NULL) + needed[nneeded++] = dep; } else if (d->d_tag == DT_AUXILIARY || d->d_tag == DT_FILTER) { @@ -320,6 +332,10 @@ _dl_map_object_deps (struct link_map *map, orig->done = 0; orig->map = args.aux; + /* Remember this dependency. */ + if (needed != NULL) + needed[nneeded++] = args.aux; + /* We must handle two situations here: the map is new, so we must add it in all three lists. If the map is already known, we have two further possibilities: @@ -427,9 +443,19 @@ _dl_map_object_deps (struct link_map *map, ++nduplist; } } - else - /* Mark as processed. */ - runp->done = 1; + + /* Terminate the list of dependencies and store the array address. */ + if (needed != NULL) + { + needed[nneeded++] = NULL; + + l->l_initfini = + (struct link_map **) malloc (nneeded * sizeof (struct link_map)); + if (l->l_initfini == NULL) + _dl_signal_error (ENOMEM, map->l_name, + "cannot allocate dependency list"); + memcpy (l->l_initfini, needed, nneeded * sizeof (struct link_map)); + } /* If we have no auxiliary objects just go on to the next map. */ if (runp->done) @@ -440,7 +466,9 @@ _dl_map_object_deps (struct link_map *map, /* Store the search list we built in the object. It will be used for searches in the scope of this object. */ - map->l_searchlist.r_list = malloc (nlist * sizeof (struct link_map *)); + map->l_searchlist.r_list = malloc ((2 * nlist + + (nlist == nduplist ? 0 : nduplist)) + * sizeof (struct link_map *)); if (map->l_searchlist.r_list == NULL) _dl_signal_error (ENOMEM, map->l_name, "cannot allocate symbol search list"); @@ -466,11 +494,7 @@ _dl_map_object_deps (struct link_map *map, { unsigned int cnt; - map->l_searchlist.r_duplist = malloc (nduplist - * sizeof (struct link_map *)); - if (map->l_searchlist.r_duplist == NULL) - _dl_signal_error (ENOMEM, map->l_name, - "cannot allocate symbol search list"); + map->l_searchlist.r_duplist = map->l_searchlist.r_list + nlist; for (cnt = 0, runp = known; runp; runp = runp->dup) if (trace_mode && runp->map->l_opencount == 0) @@ -479,4 +503,51 @@ _dl_map_object_deps (struct link_map *map, else map->l_searchlist.r_duplist[cnt++] = runp->map; } + + /* Now determine the order in which the initialization has to happen. */ + map->l_initfini = + (struct link_map **) memcpy (map->l_searchlist.r_duplist + nduplist, + 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) + { + 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; map->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) + { + struct link_map **runp; + + runp = map->l_initfini[k]->l_initfini; + if (runp != NULL) + { + while (*runp != NULL) + if (*runp == l) + { + struct link_map *here = map->l_initfini[k]; + + /* Move it now. */ + memmove (&map->l_initfini[j] + 1, + &map->l_initfini[j], + (k - j) * sizeof (struct link_map *)); + map->l_initfini[j] = here; + + break; + } + else + ++runp; + } + } + } } 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 +#include #include + +/* 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)) (); + } + } } diff --git a/elf/dl-init.c b/elf/dl-init.c index c1e9271..c50c16a 100644 --- a/elf/dl-init.c +++ b/elf/dl-init.c @@ -21,82 +21,112 @@ #include -/* Run initializers for MAP and its dependencies, in inverse dependency - order (that is, leaf nodes first). */ +/* Type of the initializer. */ +typedef void (*init_t) (int, char **, char **); -ElfW(Addr) + +static void internal_function -_dl_init_next (struct r_scope_elem *searchlist) +_dl_init_rec (struct link_map *map, int argc, char **argv, char **env) { unsigned int i; - /* The search list for symbol lookup is a flat list in top-down - dependency order, so processing that list from back to front gets us - breadth-first leaf-to-root order. */ + /* Stupid users forces the ELF specification to be changed. It now + says that the dynamic loader is responsible for determining the + order in which the constructors have to run. The constructors + for all dependencies of an object must run before the constructor + for the object itself. Circular dependencies are left unspecified. + + This is highly questionable since it puts the burden on the dynamic + loader which has to find the dependencies at runtime instead of + letting the user do it right. Stupidity rules! */ - i = searchlist->r_nlist; + i = map->l_searchlist.r_nlist; while (i-- > 0) { - struct link_map *l = searchlist->r_list[i]; - ElfW(Addr) *array; + struct link_map *l = map->l_initfini[i]; + int message_written; + init_t init; if (l->l_init_called) /* This object is all done. */ continue; - /* Check for object which constructors we do not run here. - XXX Maybe this should be pre-computed, but where? */ - if (l->l_name[0] == '\0' && l->l_type == lt_executable) - { - l->l_init_called = 1; - continue; - } + /* Avoid handling this constructor again in case we have a circular + dependency. */ + l->l_init_called = 1; - /* Account for running next constructor. */ - ++l->l_runcount; + /* Check for object which constructors we do not run here. */ + if (l->l_name[0] == '\0' && l->l_type == lt_executable) + continue; - if (l->l_runcount == 1) + /* See whether any dependent objects are not yet initialized. + XXX Is this necessary? I'm not sure anymore... */ + if (l->l_searchlist.r_nlist > 1) + _dl_init_rec (l, argc, argv, env); + + /* Now run the local constructors. There are several of them: + - the one named by DT_INIT + - the others in the DT_INIT_ARRAY. + */ + message_written = 0; + if (l->l_info[DT_INIT]) { - /* Try running the DT_INIT constructor. */ - if (l->l_info[DT_INIT]) + /* Print a debug message if wanted. */ + if (_dl_debug_impcalls) { - /* Print a debug message if wanted. */ - if (_dl_debug_impcalls) - _dl_debug_message (1, "\ncalling init: ", - l->l_name[0] ? l->l_name : _dl_argv[0], - "\n\n", NULL); - - return l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr; + _dl_debug_message (1, "\ncalling init: ", + l->l_name[0] ? l->l_name : _dl_argv[0], + "\n\n", NULL); + message_written = 1; } - /* No DT_INIT, so go on with the array. */ - ++l->l_runcount; + init = (init_t) (l->l_addr + l->l_info[DT_INIT]->d_un.d_ptr); + + /* Call the function. */ + init (argc, argv, env); } - if (l->l_runcount > l->l_initcount) + /* Next see whether there is an array with initialiazation functions. */ + if (l->l_info[DT_INIT_ARRAY]) { - /* That were all of the constructors. */ - l->l_runcount = 0; - l->l_init_called = 1; - continue; - } + unsigned int j; + unsigned int jm; + ElfW(Addr) *addrs; - /* Print a debug message if wanted. */ - if (_dl_debug_impcalls && l->l_info[DT_INIT] == NULL - && l->l_runcount == 2) - _dl_debug_message (1, "\ncalling init: ", - l->l_name[0] ? l->l_name : _dl_argv[0], - "\n\n", NULL); + jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr)); - array = (ElfW(Addr) *) D_PTR (l, l_info[DT_INIT_ARRAY]); - return l->l_addr + array[l->l_runcount - 2]; - /* NOTREACHED */ + if (jm > 0 && _dl_debug_impcalls && ! message_written) + _dl_debug_message (1, "\ncalling init: ", + l->l_name[0] ? l->l_name : _dl_argv[0], + "\n\n", NULL); + + addrs = (ElfW(Addr) *) (l->l_info[DT_INIT_ARRAY]->d_un.d_ptr + + l->l_addr); + for (j = 0; j < jm; ++j) + ((init_t) addrs[j]) (argc, argv, env); + } } +} - /* Notify the debugger all new objects are now ready to go. */ - _r_debug.r_state = RT_CONSISTENT; +void +internal_function +_dl_init (struct link_map *main_map, int argc, char **argv, char **env) +{ + struct r_debug *r; + + /* Notify the debugger we have added some objects. We need to call + _dl_debug_initialize in a static program in case dynamic linking has + not been used before. */ + r = _dl_debug_initialize (0); + r->r_state = RT_ADD; _dl_debug_state (); - return 0; + /* Recursively call the constructors. */ + _dl_init_rec (main_map, argc, argv, env); + + /* Notify the debugger all new objects are now ready to go. */ + r->r_state = RT_CONSISTENT; + _dl_debug_state (); } diff --git a/elf/dl-load.c b/elf/dl-load.c index 0ec2152..3892289 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -858,6 +858,7 @@ _dl_map_object_from_fd (const char *name, int fd, char *realname, verbatim, and later correct for the run-time load address. */ case PT_DYNAMIC: l->l_ld = (void *) ph->p_vaddr; + l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn)); break; case PT_PHDR: l->l_phdr = (void *) ph->p_vaddr; diff --git a/elf/dl-open.c b/elf/dl-open.c index c497d2e..b419219 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -85,8 +85,6 @@ dl_open_worker (void *a) const char *file = args->file; int mode = args->mode; struct link_map *new, *l; - ElfW(Addr) init; - struct r_debug *r; const char *dst; int lazy; @@ -194,17 +192,8 @@ dl_open_worker (void *a) l = l->l_prev; } - /* Notify the debugger we have added some objects. We need to call - _dl_debug_initialize in a static program in case dynamic linking has - not been used before. */ - r = _dl_debug_initialize (0); - r->r_state = RT_ADD; - _dl_debug_state (); - /* Run the initializer functions of new objects. */ - while ((init = _dl_init_next (&new->l_searchlist))) - (*(void (*) (int, char **, char **)) init) (__libc_argc, __libc_argv, - __environ); + _dl_init (new, __libc_argc, __libc_argv, __environ); /* Now we can make the new map available in the global scope. */ if (mode & RTLD_GLOBAL) diff --git a/elf/dl-preinit.c b/elf/dl-preinit.c index 8ef4afc..fa8ce7e 100644 --- a/elf/dl-preinit.c +++ b/elf/dl-preinit.c @@ -21,29 +21,35 @@ #include +/* Type of the initializer. */ +typedef void (*init_t) (int, char **, char **); + + /* Run initializers for MAP and its dependencies, in inverse dependency order (that is, leaf nodes first). */ -ElfW(Addr) +void internal_function -_dl_preinit_next (struct r_scope_elem *searchlist) +_dl_preinit (struct link_map *main_map, int argc, char **argv, char **env) { - struct link_map *l = searchlist->r_list[0]; - ElfW(Addr) *array; + /* Don't do anything if there is no preinit array. */ + ElfW(Dyn) *preinit_array = main_map->l_info[DT_PREINIT_ARRAYSZ]; + unsigned int max; - if (l->l_runcount >= l->l_preinitcount) + if (preinit_array != NULL + && (max = preinit_array->d_un.d_val / sizeof (ElfW(Addr))) > 0) { - /* That were all of the constructors. */ - l->l_runcount = 0; - return 0; + ElfW(Addr) *addrs; + unsigned int cnt; + + if (_dl_debug_impcalls) + _dl_debug_message (1, "\ncalling preinit: ", + main_map->l_name[0] + ? main_map->l_name : _dl_argv[0], "\n\n", NULL); + + addrs = (ElfW(Addr) *) (main_map->l_info[DT_PREINIT_ARRAY]->d_un.d_ptr + + main_map->l_addr); + for (cnt = 0; cnt < max; ++cnt) + ((init_t) addrs[cnt]) (argc, argv, env); } - - /* Print a debug message if wanted. */ - if (_dl_debug_impcalls && l->l_runcount == 0) - _dl_debug_message (1, "\ncalling preinit: ", - l->l_name[0] ? l->l_name : _dl_argv[0], - "\n\n", NULL); - - array = (ElfW(Addr) *) l->l_info[DT_PREINIT_ARRAY]->d_un.d_ptr; - return l->l_addr + array[l->l_runcount++]; } diff --git a/elf/dynamic-link.h b/elf/dynamic-link.h index cd30656..5987707 100644 --- a/elf/dynamic-link.h +++ b/elf/dynamic-link.h @@ -114,19 +114,6 @@ elf_get_dynamic_info (struct link_map *l) if (flags & DF_BIND_NOW) info[DT_BIND_NOW] = info[DT_FLAGS]; } -#ifndef DL_RO_DYN_SECTION - /* Determine how many constructors there are. */ - if (info[DT_INIT_ARRAY] != NULL) - info[DT_INIT_ARRAY]->d_un.d_ptr += l_addr; -#endif - l->l_initcount = 1 + (info[DT_INIT_ARRAY] - ? (info[DT_INIT_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))) - : 0); - l->l_preinitcount = (info[DT_PREINIT_ARRAY] - ? (info[DT_PREINIT_ARRAYSZ]->d_un.d_val - / sizeof (ElfW(Addr))) - : 0); if (info[DT_RUNPATH] != NULL) /* If both RUNPATH and RPATH are given, the latter is ignored. */ info[DT_RPATH] = NULL; diff --git a/elf/link.h b/elf/link.h index ac53a20..e4c2fea 100644 --- a/elf/link.h +++ b/elf/link.h @@ -1,6 +1,6 @@ /* Data structure for communication from the run-time dynamic linker for loaded ELF shared objects. - Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1995-1999, 2000 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 @@ -137,6 +137,7 @@ struct link_map const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */ ElfW(Addr) l_entry; /* Entry point location. */ ElfW(Half) l_phnum; /* Number of program header entries. */ + ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */ /* Array of DT_NEEDED dependencies and their dependencies, in dependency order for symbol lookup (with and without @@ -166,6 +167,8 @@ struct link_map unsigned int l_init_called:1; /* Nonzero if DT_INIT function called. */ unsigned int l_global:1; /* Nonzero if object in _dl_global_scope. */ unsigned int l_reserved:2; /* Reserved for internal use. */ + unsigned int l_phdr_allocated:1; /* Nonzero if the data structure pointed + to by `l_phdr' is allocated. */ /* Array with version names. */ unsigned int l_nversions; @@ -200,22 +203,11 @@ struct link_map dev_t l_dev; ino_t l_ino; - /* Nonzero if the data structure pointed to by `l_phdr' is allocated. */ - int l_phdr_allocated; - - /* Counter for running constructors and destructors. */ - unsigned int l_runcount; - - /* Number of constructors. We compute this during loading to avoid - duplication of this during the possibly many calls to _dl_init_next. */ - unsigned int l_initcount; - /* Collected information about own RUNPATH directories. */ struct r_search_path_elem **l_runpath_dirs; - /* Number of pre-constructors. We compute this during loading to avoid - duplication of this during the possibly many calls to _dl_init_next. */ - unsigned int l_preinitcount; + /* List of object in order of the init and fini calls. */ + struct link_map **l_initfini; }; #endif /* link.h */ -- cgit v1.1