summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorMike Frysinger <vapier@gentoo.org>2006-02-14 01:02:26 +0000
committerMike Frysinger <vapier@gentoo.org>2006-02-14 01:02:26 +0000
commit2525195d77d4ab4be720a077d1e30c6a3d8d7a84 (patch)
tree2b0a36008e182161474cf6ee35b4992181e23ef2 /ldso
parent7f7444e68d69f90fd36bfc8488de7b183d998236 (diff)
after much deliberation, may i present Joseph S. Myers patch to add support for .init and .fini array processing
for the gory details, see the mailing list: http://www.uclibc.org/lists/uclibc/2006-January/014079.html http://www.uclibc.org/lists/uclibc/2006-February/014285.html
Diffstat (limited to 'ldso')
-rw-r--r--ldso/ldso/ldso.c58
-rw-r--r--ldso/libdl/libdl.c22
2 files changed, 75 insertions, 5 deletions
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index 1b9cd791b..ff8ab7d11 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -97,6 +97,53 @@ strong_alias(__stack_chk_guard,__guard)
#endif
#endif
+static void _dl_run_array_forward(unsigned long array, unsigned long size,
+ ElfW(Addr) loadaddr)
+{
+ if (array != 0) {
+ unsigned int j;
+ unsigned int jm;
+ ElfW(Addr) *addrs;
+ jm = size / sizeof (ElfW(Addr));
+ addrs = (ElfW(Addr) *) (array + 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_run_init_array(struct elf_resolve *tpnt)
+{
+ _dl_run_array_forward(tpnt->dynamic_info[DT_INIT_ARRAY],
+ tpnt->dynamic_info[DT_INIT_ARRAYSZ],
+ tpnt->loadaddr);
+}
+
+void _dl_app_init_array(void)
+{
+ _dl_run_init_array(_dl_loaded_modules);
+}
+
+void _dl_run_fini_array(struct elf_resolve *tpnt)
+{
+ 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) ();
+ }
+ }
+}
+
+void _dl_app_fini_array(void)
+{
+ _dl_run_fini_array(_dl_loaded_modules);
+}
+
static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
{
int i;
@@ -107,6 +154,7 @@ static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
if (tpnt->init_flag & FINI_FUNCS_CALLED)
continue;
tpnt->init_flag |= FINI_FUNCS_CALLED;
+ _dl_run_fini_array(tpnt);
if (tpnt->dynamic_info[DT_FINI]) {
void (*dl_elf_func) (void);
@@ -769,6 +817,14 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
/* 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. */
+ _dl_run_array_forward(_dl_loaded_modules->dynamic_info[DT_PREINIT_ARRAY],
+ _dl_loaded_modules->dynamic_info[DT_PREINIT_ARRAYSZ],
+ _dl_loaded_modules->loadaddr);
+
+ /* Run initialization functions for loaded objects. For the
+ main executable, they will be run from __uClibc_main. */
for (i = nlist; i; --i) {
tpnt = init_fini_list[i-1];
tpnt->init_fini = NULL; /* Clear, since alloca was used */
@@ -785,6 +841,8 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
(*dl_elf_func) ();
}
+
+ _dl_run_init_array(tpnt);
}
/* Find the real malloc function and make ldso functions use that from now on */
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 14af827a6..c1a8c247e 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -51,6 +51,8 @@ extern struct elf_resolve *_dl_loaded_modules;
extern struct r_debug *_dl_debug_addr;
extern unsigned long _dl_error_number;
extern void *(*_dl_malloc_function)(size_t);
+extern void _dl_run_init_array(struct elf_resolve *);
+extern void _dl_run_fini_array(struct elf_resolve *);
#ifdef __LDSO_CACHE_SUPPORT__
int _dl_map_cache(void);
int _dl_unmap_cache(void);
@@ -383,6 +385,8 @@ void *dlopen(const char *libname, int flag)
(*dl_elf_func) ();
}
}
+
+ _dl_run_init_array(tpnt);
}
#endif /* SHARED */
@@ -498,13 +502,21 @@ static int do_dlclose(void *vhandle, int need_fini)
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) ();
+#ifdef SHARED
+ _dl_run_fini_array(tpnt);
+#endif
+
+ 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);