[uClibc-cvs] CVS update of uClibc/ldso (include/dl-hash.h include/ldso.h ldso/ldso.c libdl/libdl.c)

Joakim Tjernlund jocke at codepoet.org
Wed Sep 8 09:43:25 UTC 2004


    Date: Wednesday, September 8, 2004 @ 03:43:25
  Author: jocke
    Path: /var/cvs/uClibc/ldso

Modified: include/dl-hash.h (1.6 -> 1.7) include/ldso.h (1.19 -> 1.20)
          ldso/ldso.c (1.120 -> 1.121) libdl/libdl.c (1.55 -> 1.56)

Second attempt to fix the INIT/FINI order. This time I think I got it right :)
This needs testing with apps that have complex dependencies.


Index: uClibc/ldso/include/dl-hash.h
diff -u uClibc/ldso/include/dl-hash.h:1.6 uClibc/ldso/include/dl-hash.h:1.7
--- uClibc/ldso/include/dl-hash.h:1.6	Fri Sep  3 15:17:09 2004
+++ uClibc/ldso/include/dl-hash.h	Wed Sep  8 03:43:24 2004
@@ -5,10 +5,15 @@
 #define RTLD_NEXT	((void*)-1)
 #endif
 
+struct init_fini {
+	struct elf_resolve **init_fini;
+	unsigned long nlist; /* Number of entries in init_fini */
+};
+
 struct dyn_elf{
   struct elf_resolve * dyn;
   struct dyn_elf * next_handle;  /* Used by dlopen et al. */
-  struct init_fini_list *init_fini;
+  struct init_fini init_fini;
   struct dyn_elf * next;
   struct dyn_elf * prev;
 };
@@ -29,6 +34,8 @@
   unsigned long rtld_flags; /* RTLD_GLOBAL, RTLD_NOW etc. */
   unsigned int nbucket;
   unsigned long * elf_buckets;
+  struct init_fini_list *init_fini;
+
   /*
    * These are only used with ELF style shared libraries
    */
Index: uClibc/ldso/include/ldso.h
diff -u uClibc/ldso/include/ldso.h:1.19 uClibc/ldso/include/ldso.h:1.20
--- uClibc/ldso/include/ldso.h:1.19	Fri Sep  3 15:17:09 2004
+++ uClibc/ldso/include/ldso.h	Wed Sep  8 03:43:24 2004
@@ -31,10 +31,9 @@
 #include <dl-elf.h>
 #include <dl-hash.h>
 
-/* For INIT/FINI handling */
+/* For INIT/FINI dependency sorting. */
 struct init_fini_list {
 	struct init_fini_list *next;
-	struct init_fini_list *prev;
 	struct elf_resolve *tpnt;
 };
 
Index: uClibc/ldso/ldso/ldso.c
diff -u uClibc/ldso/ldso/ldso.c:1.120 uClibc/ldso/ldso/ldso.c:1.121
--- uClibc/ldso/ldso/ldso.c:1.120	Fri Sep  3 15:17:09 2004
+++ uClibc/ldso/ldso/ldso.c	Wed Sep  8 03:43:24 2004
@@ -91,7 +91,8 @@
 	ElfW(Phdr) *ppnt;
 	Elf32_Dyn *dpnt;
 	char *lpntstr;
-	int i, goof = 0, unlazy = 0, trace_loaded_objects = 0;
+	int i, nlist, goof = 0, unlazy = 0, trace_loaded_objects = 0;
+	struct elf_resolve **init_fini_list;
 	struct dyn_elf *rpnt;
 	struct elf_resolve *tcurr;
 	struct elf_resolve *tpnt1;
@@ -104,7 +105,6 @@
 #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!!! */
@@ -567,9 +567,11 @@
 		}
 	}
 #endif
-	init_list = NULL;
+	nlist = 0;
 	for (tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next) {
 		Elf32_Dyn *dpnt;
+
+		nlist++;
 		for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
 			if (dpnt->d_tag == DT_NEEDED) {
 				char *name;
@@ -599,10 +601,10 @@
 					}
 				}
 				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;
+				tmp->next = tcurr->init_fini;
+				tcurr->init_fini = 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);
@@ -615,9 +617,58 @@
 			}
 		}
 	}
-
 	_dl_unmap_cache();
 
+	--nlist; /* Exclude the application. */
+
+	/* As long as atexit() is used to run the FINI functions, we can
+	 use alloca here. The use of atexit() should go away at some time as that
+	 will make Valgring happy. */
+	init_fini_list = alloca(nlist * sizeof(struct elf_resolve *));
+	i = 0;
+	for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
+		init_fini_list[i++] = tcurr;
+	}
+	/* Sort the INIT/FINI list in dependency order. */
+	for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
+		int j, k;
+
+		for (j = 0; init_fini_list[j] != tcurr; ++j)
+			/* Empty */;
+		for (k = j + 1; k < nlist; ++k) {
+			struct init_fini_list *runp = init_fini_list[k]->init_fini;
+
+			for (; runp; runp = runp->next) {
+				if (runp->tpnt == tcurr) {
+					struct elf_resolve *here = init_fini_list[k];
+#ifdef __SUPPORT_LD_DEBUG__
+					if(_dl_debug)
+						_dl_dprintf(2, "Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
+#endif
+					for (i = (k - j); i; --i)
+						init_fini_list[i+j] = init_fini_list[i+j-1];
+					init_fini_list[j] = here;
+					++j;
+					break;
+				}
+			}
+		}
+	}
+#ifdef __SUPPORT_LD_DEBUG__
+	if(_dl_debug) {
+		_dl_dprintf(2, "\nINIT/FINI order and dependencies:\n");
+		for (i=0;i < nlist;i++) {
+			struct init_fini_list *tmp;
+
+			_dl_dprintf(2, "lib: %s has deps:\n", init_fini_list[i]->libname);
+			tmp = init_fini_list[i]->init_fini;
+			for ( ;tmp; tmp = tmp->next)
+				_dl_dprintf(2, " %s ", tmp->tpnt->libname);
+			_dl_dprintf(2, "\n");
+		}
+	}
+#endif
+
 	/*
 	 * If the program interpreter is not in the module chain, add it.  This will
 	 * be required for dlopen to be able to access the internal functions in the
@@ -722,8 +773,9 @@
 	/* Notify the debugger we have added some objects. */
 	_dl_debug_addr->r_state = RT_ADD;
 	_dl_debug_state();
-	for (; init_list; init_list = init_list->prev) {
-		tpnt = init_list->tpnt;
+	for (i = nlist; i; --i) {
+		tpnt = init_fini_list[i-1];
+		tpnt->init_fini = NULL; /* Clear, since alloca was used */
 		if (tpnt->init_flag & INIT_FUNCS_CALLED)
 			continue;
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
Index: uClibc/ldso/libdl/libdl.c
diff -u uClibc/ldso/libdl/libdl.c:1.55 uClibc/ldso/libdl/libdl.c:1.56
--- uClibc/ldso/libdl/libdl.c:1.55	Tue Sep  7 02:36:25 2004
+++ uClibc/ldso/libdl/libdl.c	Wed Sep  8 03:43:25 2004
@@ -134,8 +134,9 @@
 	struct elf_resolve *tpnt1;
 	void (*dl_brk) (void);
 	int now_flag;
-	struct init_fini_list *init_list;
 	struct init_fini_list *tmp;
+	int nlist, i;
+	struct elf_resolve **init_fini_list;
 
 	/* A bit of sanity checking... */
 	if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
@@ -194,19 +195,14 @@
 	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;
+	nlist = 0;
 	for (tcurr = tpnt; tcurr; tcurr = tcurr->next)
 	{
 		Elf32_Dyn *dpnt;
 		char *lpntstr;
+
+		nlist++;
+		tcurr->init_fini = NULL; /* clear any previous dependcies */
 		for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++) {
 			if (dpnt->d_tag == DT_NEEDED) {
 				char *name;
@@ -234,15 +230,58 @@
 					tpnt1->rtld_flags |= RTLD_GLOBAL;
 					tpnt1->usage_count++;
 				}
-				tmp =  malloc(sizeof(struct init_fini_list));
+				tmp = alloca(sizeof(struct init_fini_list)); /* Allocates on stack, no need to free this memory */
 				tmp->tpnt = tpnt1;
-				tmp->next = NULL;
-				tmp->prev = init_list;
-				init_list->next = tmp;
-				init_list = init_list->next;;
+				tmp->next = tcurr->init_fini;
+				tcurr->init_fini = tmp;
 			}
 		}
 	}
+	init_fini_list = malloc(nlist * sizeof(struct elf_resolve *));
+	dyn_chain->init_fini.init_fini = init_fini_list;
+	dyn_chain->init_fini.nlist = nlist;
+	i = 0;
+	for (tcurr = tpnt; tcurr; tcurr = tcurr->next) {
+		init_fini_list[i++] = tcurr;
+	}
+	/* Sort the INIT/FINI list in dependency order. */
+	for (tcurr = tpnt; tcurr; tcurr = tcurr->next) {
+		int j, k;
+		for (j = 0; init_fini_list[j] != tcurr; ++j)
+			/* Empty */;
+		for (k = j + 1; k < nlist; ++k) {
+			struct init_fini_list *runp = init_fini_list[k]->init_fini;
+
+			for (; runp; runp = runp->next) {
+				if (runp->tpnt == tcurr) {
+					struct elf_resolve *here = init_fini_list[k];
+#ifdef __SUPPORT_LD_DEBUG__
+					if(_dl_debug)
+						fprintf(stderr, "Move %s from pos %d to %d in INIT/FINI list.\n", here->libname, k, j);
+#endif
+					for (i = (k - j); i; --i)
+						init_fini_list[i+j] = init_fini_list[i+j-1];
+					init_fini_list[j] = here;
+					++j;
+					break;
+				}
+			}
+		}
+	}
+#ifdef __SUPPORT_LD_DEBUG__
+	if(_dl_debug) {
+		fprintf(stderr, "\nINIT/FINI order and dependencies:\n");
+		for (i=0;i < nlist;i++) {
+			struct init_fini_list *tmp;
+
+			fprintf(stderr, "lib: %s has deps:\n", init_fini_list[i]->libname);
+			tmp = init_fini_list[i]->init_fini;
+			for ( ;tmp; tmp = tmp->next)
+				printf(" %s ", tmp->tpnt->libname);
+			printf("\n");
+		}
+	}
+#endif
 
 	if (dyn_chain->dyn->init_flag & INIT_FUNCS_CALLED) {
 		/* If the init and fini stuff has already been run, that means
@@ -290,10 +329,8 @@
 
 #if defined (__LIBDL_SHARED__)
 	/* 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. */
-		tpnt = init_list->tpnt;
+	for (i = nlist; i; --i) {
+		tpnt = init_fini_list[i-1];
 		if (tpnt->init_flag & INIT_FUNCS_CALLED)
 			continue;
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
@@ -384,7 +421,6 @@
 	struct dyn_elf *handle;
 	unsigned int end;
 	int i = 0;
-	struct init_fini_list *fini_list, *tmp;
 
 	handle = (struct dyn_elf *) vhandle;
 	rpnt1 = NULL;
@@ -403,9 +439,8 @@
 	else
 		_dl_handles = rpnt->next_handle;
 	if (need_fini) {
-		for (fini_list = handle->init_fini; fini_list; ) {
-			tpnt = fini_list->tpnt;
-			tmp = NULL;
+		for (i = 0; i < handle->init_fini.nlist; ++i) {
+			tpnt = handle->init_fini.init_fini[i];
 			if (tpnt->dynamic_info[DT_FINI] && tpnt->usage_count == 1 &&
 			    !(tpnt->init_flag & FINI_FUNCS_CALLED)) {
 				tpnt->init_flag |= FINI_FUNCS_CALLED;
@@ -415,12 +450,10 @@
 					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);
 		}
 	}
+	free(handle->init_fini.init_fini);
 	/* OK, this is a valid handle - now close out the file */
 	for (rpnt = handle; rpnt; rpnt = rpnt->next) {
 		tpnt = rpnt->dyn;



More information about the uClibc-cvs mailing list