Browse Source

First attempt to fix the INIT/FINI ordering. Fingers crossed :)

Joakim Tjernlund 20 years ago
parent
commit
b54df7ec54
4 changed files with 83 additions and 70 deletions
  1. 2 0
      ldso/include/dl-hash.h
  2. 7 0
      ldso/include/ldso.h
  3. 33 51
      ldso/ldso/ldso.c
  4. 41 19
      ldso/libdl/libdl.c

+ 2 - 0
ldso/include/dl-hash.h

@@ -8,6 +8,7 @@
 struct dyn_elf{
   struct elf_resolve * dyn;
   struct dyn_elf * next_handle;  /* Used by dlopen et al. */
+  struct init_fini_list *init_fini;
   struct dyn_elf * next;
   struct dyn_elf * prev;
 };
@@ -57,6 +58,7 @@ struct elf_resolve{
 #define RELOCS_DONE         2
 #define JMP_RELOCS_DONE     4
 #define INIT_FUNCS_CALLED   8
+#define FINI_FUNCS_CALLED   16
 
 extern struct dyn_elf     * _dl_symbol_tables;
 extern struct elf_resolve * _dl_loaded_modules;

+ 7 - 0
ldso/include/ldso.h

@@ -31,6 +31,13 @@
 #include <dl-elf.h>
 #include <dl-hash.h>
 
+/* For INIT/FINI handling */
+struct init_fini_list {
+	struct init_fini_list *next;
+	struct init_fini_list *prev;
+	struct elf_resolve *tpnt;
+};
+
 /* Global variables used within the shared library loader */
 extern char *_dl_library_path;         /* Where we look for libraries */
 extern char *_dl_preload;              /* Things to be loaded before the libs */

+ 33 - 51
ldso/ldso/ldso.c

@@ -104,6 +104,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
 #if defined (__SUPPORT_LD_DEBUG__)
 	int (*_dl_on_exit) (void (*FUNCTION)(int STATUS, void *ARG),void*);
 #endif
+	struct init_fini_list *init_list;
 
 #ifdef __SUPPORT_LD_DEBUG_EARLY__
 	/* Wahoo!!! */
@@ -566,56 +567,55 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
 		}
 	}
 #endif
-
-	for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
-	{
+	init_list = NULL;
+	for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) {
 		Elf32_Dyn *dpnt;
-		for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
-		{
-			if (dpnt->d_tag == DT_NEEDED)
-			{
+		for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
+			if (dpnt->d_tag == DT_NEEDED) {
 				char *name;
+				struct init_fini_list *tmp;
+
 				lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + dpnt->d_un.d_val);
 				name = _dl_get_last_path_component(lpntstr);
 
-				if ((tpnt1 = _dl_check_if_named_library_is_loaded(name, trace_loaded_objects)))
-				{
+				if ((tpnt1 = _dl_check_if_named_library_is_loaded(name, trace_loaded_objects)))	{
 					tpnt1->usage_count++;
-					continue;
 				}
 #if defined (__SUPPORT_LD_DEBUG__)
-				if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfile='%s';  needed by '%s'\n",
-						lpntstr, _dl_progname);
+				if(_dl_debug) _dl_dprintf(_dl_debug_file, "\tfile='%s';  needed by '%s'\n", lpntstr, _dl_progname);
 #endif
-				if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, trace_loaded_objects)))
-				{
+				if (!tpnt1) {
+					if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, trace_loaded_objects)))	{
 #ifdef __LDSO_LDD_SUPPORT__
-					if (trace_loaded_objects) {
-						_dl_dprintf(1, "\t%s => not found\n", lpntstr);
-						continue;
-					} else
+						if (trace_loaded_objects) {
+							_dl_dprintf(1, "\t%s => not found\n", lpntstr);
+							continue;
+						} else
 #endif
-					{
-						_dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, lpntstr);
-						_dl_exit(16);
+						{
+							_dl_dprintf(2, "%s: can't load library '%s'\n", _dl_progname, lpntstr);
+							_dl_exit(16);
+						}
 					}
-				} else {
-					tpnt1->rtld_flags = unlazy | RTLD_GLOBAL;
+				}
+				tmp = alloca(sizeof(struct init_fini_list)); /* Allocates on stack, no need to free this memory */
+				/* Don't set the tmp->next ptr, it is not used */
+				tmp->tpnt = tpnt1;
+				tmp->prev = init_list;
+				init_list = tmp;
+				tpnt1->rtld_flags = unlazy | RTLD_GLOBAL;
 #ifdef __SUPPORT_LD_DEBUG_EARLY__
-					_dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
+				_dl_dprintf(_dl_debug_file, "Loading:\t(%x) %s\n", tpnt1->loadaddr, tpnt1->libname);
 #endif
 #ifdef __LDSO_LDD_SUPPORT__
-					if (trace_loaded_objects && tpnt1->usage_count==1) {
-						_dl_dprintf(1, "\t%s => %s (%x)\n", lpntstr, tpnt1->libname,
-								(unsigned) tpnt1->loadaddr);
-					}
-#endif
+				if (trace_loaded_objects && tpnt1->usage_count==1) {
+					_dl_dprintf(1, "\t%s => %s (%x)\n", lpntstr, tpnt1->libname, (unsigned) tpnt1->loadaddr);
 				}
+#endif
 			}
 		}
 	}
 
-
 	_dl_unmap_cache();
 
 	/*
@@ -722,23 +722,8 @@ 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();
-
-	for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
-		;
-
-	for (;rpnt!=NULL; rpnt=rpnt->prev)
-	{
-		tpnt = rpnt->dyn;
-
-		if (tpnt->libtype == program_interpreter)
-			continue;
-
-		/* Apparently crt0/1 for the application is responsible for handling this.
-		 * We only need to run the init/fini for shared libraries
-		 */
-		if (tpnt->libtype == elf_executable)
-			break;      /* at this point all shared libs are initialized !! */
-
+	for (; init_list; init_list = init_list->prev) {
+		tpnt = init_list->tpnt;
 		if (tpnt->init_flag & INIT_FUNCS_CALLED)
 			continue;
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
@@ -751,6 +736,7 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
 #endif
 			(*dl_elf_func) ();
 		}
+		tpnt->init_flag |= FINI_FUNCS_CALLED;
 		if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) {
 			void (*dl_elf_func) (void);
 			dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
@@ -766,10 +752,6 @@ void _dl_get_ready_to_run(struct elf_resolve *tpnt, unsigned long load_addr,
 		else {
 			if (!_dl_atexit)
 				_dl_dprintf(_dl_debug_file, "%s: The address of atexit () is 0x0.\n", tpnt->libname);
-#if 0
-			if (!tpnt->dynamic_info[DT_FINI])
-				_dl_dprintf(_dl_debug_file, "%s: Invalid .fini section.\n", tpnt->libname);
-#endif
 		}
 #endif
 	}

+ 41 - 19
ldso/libdl/libdl.c

@@ -134,6 +134,8 @@ void *dlopen(const char *libname, int flag)
 	struct elf_resolve *tpnt1;
 	void (*dl_brk) (void);
 	int now_flag;
+	struct init_fini_list *init_list;
+	struct init_fini_list *tmp;
 
 	/* A bit of sanity checking... */
 	if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
@@ -192,15 +194,23 @@ void *dlopen(const char *libname, int flag)
 	if(_dl_debug)
 		fprintf(stderr, "Looking for needed libraries\n");
 #endif
+	init_list = NULL;
 
+	tmp =  malloc(sizeof(struct init_fini_list));
+	tmp->tpnt = tpnt;
+	tmp->next = NULL;
+	tmp->prev = init_list;
+	init_list = tmp;
+
+	dyn_chain->init_fini = init_list;
 	for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
 	{
 		Elf32_Dyn *dpnt;
 		char *lpntstr;
 		for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
 			if (dpnt->d_tag == DT_NEEDED) {
-
 				char *name;
+
 				lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
 						dpnt->d_un.d_val);
 				name = _dl_get_last_path_component(lpntstr);
@@ -224,6 +234,12 @@ void *dlopen(const char *libname, int flag)
 					tpnt1->rtld_flags |= RTLD_GLOBAL;
 					tpnt1->usage_count++;
 				}
+				tmp =  malloc(sizeof(struct init_fini_list));
+				tmp->tpnt = tpnt1;
+				tmp->next = NULL;
+				tmp->prev = init_list;
+				init_list->next = tmp;
+				init_list = init_list->next;;
 			}
 		}
 	}
@@ -273,20 +289,11 @@ void *dlopen(const char *libname, int flag)
 	}
 
 #if defined (__LIBDL_SHARED__)
-	/* Find the last library so we can run things in the right order */
-	for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
-		;
-
-	/* Run the ctors and set up the dtors */
-	for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
-	{
+	/* Run the ctors and setup the dtors */
+	for (; init_list; init_list = init_list->prev) {
 		/* Apparently crt1 for the application is responsible for handling this.
-		 * We only need to run the init/fini for shared libraries
-		 */
-		if (tpnt->libtype == program_interpreter)
-			continue;
-		if (tpnt->libtype == elf_executable)
-			continue;
+		 * We only need to run the init/fini for shared libraries. */
+		tpnt = init_list->tpnt;
 		if (tpnt->init_flag & INIT_FUNCS_CALLED)
 			continue;
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
@@ -377,6 +384,7 @@ static int do_dlclose(void *vhandle, int need_fini)
 	struct dyn_elf *handle;
 	unsigned int end;
 	int i = 0;
+	struct init_fini_list *fini_list, *tmp;
 
 	handle = (struct dyn_elf *) vhandle;
 	rpnt1 = NULL;
@@ -394,15 +402,29 @@ static int do_dlclose(void *vhandle, int need_fini)
 		rpnt1->next_handle = rpnt->next_handle;
 	else
 		_dl_handles = rpnt->next_handle;
+	if (need_fini) {
+		for (fini_list = handle->init_fini; fini_list; ) {
+			tpnt = fini_list->tpnt;
+			tmp = NULL;
+			if (tpnt->dynamic_info[DT_FINI] && tpnt->usage_count == 1 &&
+			    !(tpnt->init_flag & FINI_FUNCS_CALLED)) {
+				tpnt->init_flag |= FINI_FUNCS_CALLED;
+				dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+#ifdef __SUPPORT_LD_DEBUG__
+				if(_dl_debug)
+					fprintf(stderr, "running dtors for library %s at '%x'\n", tpnt->libname, dl_elf_fini);
+#endif
+				(*dl_elf_fini) ();
+				tmp = fini_list;
+			}
+			fini_list = fini_list->next;
+			free(tmp);
+		}
+	}
 	/* OK, this is a valid handle - now close out the file */
 	for (rpnt = handle; rpnt; rpnt = rpnt->next) {
 		tpnt = rpnt->dyn;
 		if (--tpnt->usage_count == 0) {
-			if (need_fini && tpnt->dynamic_info[DT_FINI]) {
-				dl_elf_fini = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
-				(*dl_elf_fini) ();
-			}
-
 			end = 0;
 			for (i = 0, ppnt = tpnt->ppnt;
 					i < tpnt->n_phent; ppnt++, i++) {