about summary refs log tree commit diff
path: root/elf/dl-init.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2000-03-30 16:30:49 +0000
committerUlrich Drepper <drepper@redhat.com>2000-03-30 16:30:49 +0000
commitdacc8ffa420575038f04c543c31065fea81d5732 (patch)
treee48ee55d563a39779776f3c7e02d76bc05a4cbb4 /elf/dl-init.c
parent38e986ecd8aba6953cfa4e7f104c671100f00999 (diff)
downloadglibc-dacc8ffa420575038f04c543c31065fea81d5732.tar.gz
glibc-dacc8ffa420575038f04c543c31065fea81d5732.tar.xz
glibc-dacc8ffa420575038f04c543c31065fea81d5732.zip
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-init.c')
-rw-r--r--elf/dl-init.c128
1 files changed, 79 insertions, 49 deletions
diff --git a/elf/dl-init.c b/elf/dl-init.c
index c1e927180c..c50c16a8d4 100644
--- a/elf/dl-init.c
+++ b/elf/dl-init.c
@@ -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.
+
+     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 ();
 }