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.
This commit is contained in:
Ulrich Drepper 2000-03-30 16:30:49 +00:00
parent 38e986ecd8
commit dacc8ffa42
17 changed files with 415 additions and 273 deletions

View File

@ -1,3 +1,48 @@
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.
2000-03-29 Ulrich Drepper <drepper@redhat.com>
* iconvdata/testdata/CSA_Z243.4-1985-1..UCS-2BE: Renamed from

View File

@ -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;
}
}

View File

@ -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 <sys/mman.h>
/* 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);

View File

@ -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;
}
}
}
}

View File

@ -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;
for (l = _dl_loaded; l; l = l->l_next)
if (l->l_init_called)
{
int first = 1;
/* First count how many objects are there. */
for (l = _dl_loaded; l != NULL; l = l->l_next)
++nloaded;
/* Make sure nothing happens if we are called twice. */
l->l_init_called = 0;
/* XXX Could it be (in static binaries) that there is no object loaded? */
assert (nloaded > 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;
/* 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;
/* 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;
/* 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;
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;
/* Find the place in the `maps' array. */
for (j = 1; maps[j] != l; ++j)
;
(*(void (*) (void)) (l->l_addr + array[cnt])) ();
}
}
/* 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;
/* 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);
runp = maps[k]->l_initfini;
if (runp != NULL)
{
while (*runp != NULL)
if (*runp == l)
{
struct link_map *here = maps[k];
(*(void (*) (void)) (l->l_addr + l->l_info[DT_FINI]->d_un.d_ptr)) ();
}
}
/* 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])) ();
}
/* 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)) ();
}
}
}

View File

@ -21,82 +21,112 @@
#include <ldsodefs.h>
/* 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.
i = searchlist->r_nlist;
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 = 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? */
/* Avoid handling this constructor again in case we have a circular
dependency. */
l->l_init_called = 1;
/* Check for object which constructors we do not run here. */
if (l->l_name[0] == '\0' && l->l_type == lt_executable)
{
l->l_init_called = 1;
continue;
}
continue;
/* Account for running next constructor. */
++l->l_runcount;
/* 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);
if (l->l_runcount == 1)
/* 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;
jm = l->l_info[DT_INIT_ARRAYSZ]->d_un.d_val / sizeof (ElfW(Addr));
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);
}
/* 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);
array = (ElfW(Addr) *) D_PTR (l, l_info[DT_INIT_ARRAY]);
return l->l_addr + array[l->l_runcount - 2];
/* NOTREACHED */
}
}
/* 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 ();
}

View File

@ -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;

View File

@ -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)

View File

@ -21,29 +21,35 @@
#include <ldsodefs.h>
/* 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++];
}

View File

@ -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;

View File

@ -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 */

View File

@ -354,11 +354,10 @@ extern int _dl_check_all_versions (struct link_map *map, int verbose)
extern int _dl_check_map_versions (struct link_map *map, int verbose)
internal_function;
/* Return the address of the next initializer function for SCOPE or one of
its dependencies that has not yet been run. When there are no more
initializers to be run, this returns zero. The functions are returned
in the order they should be called. */
extern ElfW(Addr) _dl_init_next (struct r_scope_elem *scope) internal_function;
/* Initialize the object in SCOPE by calling the constructors with
ARGC, ARGV, and ENV as the parameters. */
extern void _dl_init (struct link_map *main_map, int argc, char **argv,
char **env) internal_function;
/* Call the finalizer functions of all shared objects whose
initializer functions have completed. */

View File

@ -63,12 +63,12 @@ __libc_start_main (int (*main) (int, char **, char **), int argc,
if (rtld_fini != NULL)
atexit (rtld_fini);
/* Call the initializer of the libc. */
#ifdef PIC
if (_dl_debug_impcalls)
_dl_debug_message (1, "\ninitialize libc\n\n", NULL);
#endif
/* Call the initializer of the libc. This is only needed here if we
are compiling for the static library in which case we haven't
run the constructors in `_dl_start_user'. */
#ifndef PIC
__libc_init_first (argc, argv, __environ);
#endif
/* Register the destructor of the program, if any. */
if (fini)

View File

@ -1,5 +1,5 @@
/* Machine-dependent ELF dynamic relocation inline functions. i386 version.
Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Copyright (C) 1995, 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
@ -217,47 +217,33 @@ _dl_start_user:\n\
movl _dl_skip_args@GOT(%ebx), %eax\n\
movl (%eax), %eax\n\
# Pop the original argument count.\n\
popl %ecx\n\
popl %esi\n\
# Subtract _dl_skip_args from it.\n\
subl %eax, %ecx\n\
subl %eax, %esi\n\
# Adjust the stack pointer to skip _dl_skip_args words.\n\
leal (%esp,%eax,4), %esp\n\
# Push back the modified argument count.\n\
pushl %ecx\n\
# Push the searchlist of the main object as argument in\n\
# _dl_init_next call below.\n\
movl _dl_main_searchlist@GOT(%ebx), %eax\n\
movl (%eax), %esi\n\
# First run the pre-initializers.\n\
0: movl %esi,%eax\n\
# Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\
call _dl_preinit_next@PLT\n\
# Check for zero return, when out of initializers.\n\
testl %eax, %eax\n\
jz 0f\n\
# Call the pre-initilizer.\n\
call *%eax\n\
# Loop to call _dl_preinit_next for the next initializer.\n\
jmp 0b\n\
0: movl %esi,%eax\n\
# Call _dl_init_next to return the address of an initializer\n\
# function to run.\n\
call _dl_init_next@PLT\n\
# Check for zero return, when out of initializers.\n\
testl %eax, %eax\n\
jz 1f\n\
# Call the shared object initializer function.\n\
# NOTE: We depend only on the registers (%ebx, %esi and %edi)\n\
# and the return address pushed by this call;\n\
# the initializer is called with the stack just\n\
# as it appears on entry, and it is free to move\n\
# the stack around, as long as it winds up jumping to\n\
# the return address on the top of the stack.\n\
call *%eax\n\
# Loop to call _dl_init_next for the next initializer.\n\
jmp 0b\n\
1: # Clear the startup flag.\n\
# Move the argv pointer in a register.\n\
leal 4(%esp,%esi,4), %edx\n\
movl %esp, %ecx\n\
pushl %edx\n\
movl %esi, %edx\n\
# Get the searchlist of the main object as argument for\n\
# _dl_preinit and _dl_init calls below.\n\
movl _dl_loaded@GOT(%ebx), %ebp\n\
movl (%ebp), %eax\n\
# Call the function to run the pre-initializers.\n\
call _dl_preinit@PLT\n\
# Load the parameters again.\n\
leal 4(%esp,%esi,4), %edx\n\
movl %esp, %ecx\n\
pushl %edx\n\
movl %esi, %edx\n\
movl (%ebp), %eax\n\
# Call the function to run the initializers.\n\
call _dl_init@PLT\n\
# Push argc back on the stack.\n\
push %esi\n\
# Clear the startup flag.\n\
movl _dl_starting_up@GOT(%ebx), %eax\n\
movl $0, (%eax)\n\
# Pass our finalizer function to the user in %edx, as per ELF ABI.\n\

View File

@ -3,7 +3,6 @@ cmsg_nxthdr.c
errlist.h
getdirentries.c
getdirentries64.c
init-first.h
ipc_priv.h
kernel-features.h
kernel_sigaction.h

View File

@ -1,5 +1,5 @@
/* Initialization code run first thing by the ELF startup code. Linux version.
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
@ -22,7 +22,6 @@
#include <unistd.h>
#include <sysdep.h>
#include <fpu_control.h>
#include <init-first.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/types.h>
@ -156,7 +155,7 @@ init (int argc, char **argv, char **envp)
#ifdef PIC
SYSDEP_CALL_INIT(_init, init);
strong_alias (init, _init);
void
__libc_init_first (void)

View File

@ -1,50 +0,0 @@
/* Prepare arguments for library initialization function.
Copyright (C) 1997, 1999 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
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* The job of this fragment it to find argc and friends for INIT.
This is done in one of two ways: either in the stack context
of program start, or having dlopen pass them in. */
#define SYSDEP_CALL_INIT(NAME, INIT) \
void NAME (void *arg) \
{ \
int argc; \
char **argv, **envp; \
/* The next variable is only here to work around a bug in gcc <= 2.7.2.2. \
If the address would be taken inside the expression the optimizer \
would try to be too smart and throws it away. Grrr. */ \
int *dummy_addr = &_dl_starting_up; \
\
__libc_multiple_libcs = dummy_addr && !_dl_starting_up; \
\
if (!__libc_multiple_libcs) \
{ \
argc = (int) (long int) arg; \
argv = (char **) &arg + 1; \
envp = &argv[argc+1]; \
} \
else \
{ \
argc = (int) (long int) arg; \
argv = ((char ***) &arg)[1]; \
envp = ((char ***) &arg)[2]; \
} \
\
INIT (argc, argv, envp); \
}