[patch] init_array/fini_array support
Joseph S. Myers
joseph at codesourcery.com
Wed Feb 8 17:35:09 UTC 2006
Here is yet another version of the init_array/fini_array support. This
one uses _dl_app_init_array and _dl_app_fini_array functions in ld.so to
call the constructors/destructors from init_array/fini_array for the
executable in the dynamically linked case (_init and _fini still being
called as before rather), with __uClibc_main and a new function
__uClibc_fini going through the arrays (with the magic symbols provided by
the linker) in the static case. This should avoid enlarging dynamic
executables.
Index: ldso/ldso/ldso.c
===================================================================
--- ldso/ldso/ldso.c (revision 13876)
+++ ldso/ldso/ldso.c (working copy)
@@ -107,6 +107,15 @@
if (tpnt->init_flag & FINI_FUNCS_CALLED)
continue;
tpnt->init_flag |= FINI_FUNCS_CALLED;
+ if (tpnt->dynamic_info[DT_FINI_ARRAY]) {
+ ElfW(Addr) *array = (ElfW(Addr) *) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI_ARRAY]);
+ unsigned int i = (tpnt->dynamic_info[DT_FINI_ARRAYSZ] / sizeof(ElfW(Addr)));
+ while (i-- > 0) {
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) array[i];
+ (*dl_elf_func) ();
+ }
+ }
if (tpnt->dynamic_info[DT_FINI]) {
void (*dl_elf_func) (void);
@@ -136,6 +145,8 @@
unsigned long *_dl_envp; /* The environment address */
ElfW(Addr) relro_addr = 0;
size_t relro_size = 0;
+ unsigned long preinit_array;
+ unsigned long preinit_array_size;
/* Wahoo!!! We managed to make a function call! Get malloc
* setup so we can use _dl_dprintf() to print debug noise
@@ -769,7 +780,26 @@
/* Notify the debugger we have added some objects. */
_dl_debug_addr->r_state = RT_ADD;
_dl_debug_state();
+
+ /* Run pre-initialization functions for the executable. */
+ preinit_array = _dl_loaded_modules->dynamic_info[DT_PREINIT_ARRAY];
+ preinit_array_size = _dl_loaded_modules->dynamic_info[DT_PREINIT_ARRAYSZ];
+ if (preinit_array != 0
+ && (i = preinit_array_size / sizeof (ElfW(Addr))) > 0) {
+ ElfW(Addr) *addrs;
+ int cnt;
+ addrs = (ElfW(Addr) *) (preinit_array + _dl_loaded_modules->loadaddr);
+ for (cnt = 0; cnt < i; ++cnt) {
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) (addrs[cnt]);
+ (*dl_elf_func) ();
+ }
+ }
+
+ /* Run initialization functions for loaded objects. For the
+ main executable, they will be run by __libc_csu_init. */
for (i = nlist; i; --i) {
+ unsigned long init_array;
tpnt = init_fini_list[i-1];
tpnt->init_fini = NULL; /* Clear, since alloca was used */
if (tpnt->init_flag & INIT_FUNCS_CALLED)
@@ -785,6 +815,20 @@
(*dl_elf_func) ();
}
+
+ init_array = tpnt->dynamic_info[DT_INIT_ARRAY];
+ if (init_array != 0) {
+ unsigned int j;
+ unsigned int jm;
+ ElfW(Addr) *addrs;
+ jm = tpnt->dynamic_info[DT_INIT_ARRAYSZ] / sizeof (ElfW(Addr));
+ addrs = (ElfW(Addr) *) (init_array + tpnt->loadaddr);
+ for (j = 0; j < jm; ++j) {
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) addrs[j];
+ (*dl_elf_func) ();
+ }
+ }
}
/* Find the real malloc function and make ldso functions use that from now on */
@@ -876,5 +920,36 @@
return retval;
}
+void _dl_app_init_array(void)
+{
+ unsigned long init_array;
+ init_array = _dl_loaded_modules->dynamic_info[DT_INIT_ARRAY];
+ if (init_array != 0) {
+ unsigned int j;
+ unsigned int jm;
+ ElfW(Addr) *addrs;
+ jm = _dl_loaded_modules->dynamic_info[DT_INIT_ARRAYSZ] / sizeof (ElfW(Addr));
+ addrs = (ElfW(Addr) *) (init_array + _dl_loaded_modules->loadaddr);
+ for (j = 0; j < jm; ++j) {
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) addrs[j];
+ (*dl_elf_func) ();
+ }
+ }
+}
+
+void _dl_app_fini_array(void)
+{
+ if (_dl_loaded_modules->dynamic_info[DT_FINI_ARRAY]) {
+ ElfW(Addr) *array = (ElfW(Addr) *) (_dl_loaded_modules->loadaddr + _dl_loaded_modules->dynamic_info[DT_FINI_ARRAY]);
+ unsigned int i = (_dl_loaded_modules->dynamic_info[DT_FINI_ARRAYSZ] / sizeof(ElfW(Addr)));
+ while (i-- > 0) {
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) array[i];
+ (*dl_elf_func) ();
+ }
+ }
+}
+
#include "dl-hash.c"
#include "dl-elf.c"
Index: ldso/libdl/libdl.c
===================================================================
--- ldso/libdl/libdl.c (revision 13876)
+++ ldso/libdl/libdl.c (working copy)
@@ -369,6 +369,7 @@
#ifdef SHARED
/* Run the ctors and setup the dtors */
for (i = nlist; i; --i) {
+ unsigned long init_array;
tpnt = init_fini_list[i-1];
if (tpnt->init_flag & INIT_FUNCS_CALLED)
continue;
@@ -383,6 +384,20 @@
(*dl_elf_func) ();
}
}
+
+ init_array = tpnt->dynamic_info[DT_INIT_ARRAY];
+ if (init_array != 0) {
+ unsigned int j;
+ unsigned int jm;
+ ElfW(Addr) *addrs;
+ jm = tpnt->dynamic_info[DT_INIT_ARRAYSZ] / sizeof (ElfW(Addr));
+ addrs = (ElfW(Addr) *) (init_array + tpnt->loadaddr);
+ for (j = 0; j < jm; ++j) {
+ void (*dl_elf_func) (void);
+ dl_elf_func = (void (*)(void)) (intptr_t) addrs[j];
+ (*dl_elf_func) ();
+ }
+ }
}
#endif /* SHARED */
@@ -498,13 +513,26 @@
for (j = 0; j < handle->init_fini.nlist; ++j) {
tpnt = handle->init_fini.init_fini[j];
if (--tpnt->usage_count == 0) {
- if (tpnt->dynamic_info[DT_FINI] && need_fini &&
+ if ((tpnt->dynamic_info[DT_FINI]
+ || tpnt->dynamic_info[DT_FINI_ARRAY])
+ && need_fini &&
!(tpnt->init_flag & FINI_FUNCS_CALLED)) {
tpnt->init_flag |= FINI_FUNCS_CALLED;
- dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
- _dl_if_debug_print("running dtors for library %s at '%p'\n",
- tpnt->libname, dl_elf_fini);
- (*dl_elf_fini) ();
+ if (tpnt->dynamic_info[DT_FINI_ARRAY]) {
+ ElfW(Addr) *array = (ElfW(Addr) *) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI_ARRAY]);
+ unsigned int i = (tpnt->dynamic_info[DT_FINI_ARRAYSZ] / sizeof(ElfW(Addr)));
+ while (i-- > 0) {
+ dl_elf_fini = (int (*)(void)) (intptr_t) array[i];
+ (*dl_elf_fini) ();
+ }
+ }
+
+ if (tpnt->dynamic_info[DT_FINI]) {
+ dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+ _dl_if_debug_print("running dtors for library %s at '%p'\n",
+ tpnt->libname, dl_elf_fini);
+ (*dl_elf_fini) ();
+ }
}
_dl_if_debug_print("unmapping: %s\n", tpnt->libname);
Index: libc/stdlib/atexit.c
===================================================================
--- libc/stdlib/atexit.c (revision 13876)
+++ libc/stdlib/atexit.c (working copy)
@@ -318,12 +318,9 @@
libc_hidden_data_def(mylock)
#endif
-#ifdef __UCLIBC_CTOR_DTOR__
-extern void (*__app_fini)(void);
-#endif
+extern void __uClibc_fini(void);
+libc_hidden_proto(__uClibc_fini)
-extern void (*__rtld_fini)(void);
-
/*
* Normal program termination
*/
@@ -336,12 +333,7 @@
}
UNLOCK;
-#ifdef __UCLIBC_CTOR_DTOR__
- if (__app_fini != NULL)
- (__app_fini)();
-#endif
- if (__rtld_fini != NULL)
- (__rtld_fini)();
+ __uClibc_fini();
/* If we are using stdio, try to shut it down. At the very least,
* this will attempt to commit all buffered writes. It may also
Index: libc/misc/internals/__uClibc_main.c
===================================================================
--- libc/misc/internals/__uClibc_main.c (revision 13876)
+++ libc/misc/internals/__uClibc_main.c (working copy)
@@ -84,6 +84,20 @@
extern void weak_function __pthread_initialize_minimal(void);
#endif
+#ifdef __UCLIBC_CTOR_DTOR__
+extern void _dl_app_init_array(void);
+extern void _dl_app_fini_array(void);
+#ifndef SHARED
+/* These magic symbols are provided by the linker. */
+extern void (*__preinit_array_start []) (void) attribute_hidden;
+extern void (*__preinit_array_end []) (void) attribute_hidden;
+extern void (*__init_array_start []) (void) attribute_hidden;
+extern void (*__init_array_end []) (void) attribute_hidden;
+extern void (*__fini_array_start []) (void) attribute_hidden;
+extern void (*__fini_array_end []) (void) attribute_hidden;
+#endif
+#endif
+
attribute_hidden const char *__uclibc_progname = NULL;
#ifdef __UCLIBC_HAS___PROGNAME__
strong_alias (__uclibc_progname, __progname)
@@ -226,6 +240,26 @@
void attribute_hidden (*__rtld_fini)(void) = NULL;
+extern void __uClibc_fini(void);
+libc_hidden_proto(__uClibc_fini)
+void __uClibc_fini(void)
+{
+#ifdef __UCLIBC_CTOR_DTOR__
+#ifdef SHARED
+ _dl_app_fini_array();
+#else
+ size_t i = __fini_array_end - __fini_array_start;
+ while (i-- > 0)
+ (*__fini_array_start [i]) ();
+#endif
+ if (__app_fini != NULL)
+ (__app_fini)();
+#endif
+ if (__rtld_fini != NULL)
+ (__rtld_fini)();
+}
+libc_hidden_def(__uClibc_fini)
+
/* __uClibc_main is the new main stub for uClibc. This function is
* called from crt1 (version 0.9.28 or newer), after ALL shared libraries
* are initialized, just before we call the application's main function.
@@ -311,11 +345,32 @@
/* Arrange for the application's dtors to run before we exit. */
__app_fini = app_fini;
+#ifndef SHARED
+ /* For dynamically linked executables the preinit array is executed by
+ the dynamic linker (before initializing any shared object).
+ For static executables, preinit happens rights before init. */
+ {
+ const size_t size = __preinit_array_end - __preinit_array_start;
+ size_t i;
+ for (i = 0; i < size; i++)
+ (*__preinit_array_start [i]) ();
+ }
+#endif
/* Run all the application's ctors now. */
if (app_init!=NULL) {
app_init();
}
+#ifdef SHARED
+ _dl_app_init_array();
+#else
+ {
+ const size_t size = __init_array_end - __init_array_start;
+ size_t i;
+ for (i = 0; i < size; i++)
+ (*__init_array_start [i]) ();
+ }
#endif
+#endif
/* Note: It is possible that any initialization done above could
* have resulted in errno being set nonzero, so set it to 0 before
--
Joseph S. Myers
joseph at codesourcery.com
More information about the uClibc
mailing list