diff options
| -rw-r--r-- | ldso/ldso/ldso.c | 58 | ||||
| -rw-r--r-- | ldso/libdl/libdl.c | 22 | ||||
| -rw-r--r-- | libc/misc/internals/__uClibc_main.c | 55 | ||||
| -rw-r--r-- | libc/stdlib/_atexit.c | 14 | 
4 files changed, 133 insertions, 16 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); diff --git a/libc/misc/internals/__uClibc_main.c b/libc/misc/internals/__uClibc_main.c index 8d834595c..0531892c6 100644 --- a/libc/misc/internals/__uClibc_main.c +++ b/libc/misc/internals/__uClibc_main.c @@ -84,6 +84,20 @@ extern void weak_function _locale_init(void) attribute_hidden;  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) @@ -228,6 +242,26 @@ void attribute_hidden (*__app_fini)(void) = NULL;  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. @@ -313,10 +347,31 @@ void __uClibc_main(int (*main)(int, char **, char **), int argc,      /* 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 diff --git a/libc/stdlib/_atexit.c b/libc/stdlib/_atexit.c index 959d08edb..bf35ab2d6 100644 --- a/libc/stdlib/_atexit.c +++ b/libc/stdlib/_atexit.c @@ -318,11 +318,8 @@ pthread_mutex_t mylock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;  libc_hidden_data_def(mylock)  #endif -#ifdef __UCLIBC_CTOR_DTOR__ -extern void (*__app_fini)(void); -#endif - -extern void (*__rtld_fini)(void); +extern void __uClibc_fini(void); +libc_hidden_proto(__uClibc_fini)  /*   * Normal program termination @@ -336,12 +333,7 @@ void exit(int rv)  	}  	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 | 
