diff options
author | Mike Frysinger <vapier@gentoo.org> | 2006-02-14 01:02:26 +0000 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2006-02-14 01:02:26 +0000 |
commit | 2525195d77d4ab4be720a077d1e30c6a3d8d7a84 (patch) | |
tree | 2b0a36008e182161474cf6ee35b4992181e23ef2 /ldso | |
parent | 7f7444e68d69f90fd36bfc8488de7b183d998236 (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.c | 58 | ||||
-rw-r--r-- | ldso/libdl/libdl.c | 22 |
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); |