Browse Source

Cool. Found most of the problem. Turns out we were inadvertanly loading some
libraries multiple times, wasting memory and causing different libraries to use
different symbol sets, some of which were not properly resolved.

Continue scrubbing ld.so and converting it to use proper types.

Eric Andersen 21 years ago
parent
commit
2711bc5895
10 changed files with 501 additions and 281 deletions
  1. 8 23
      ldso/include/dl-hash.h
  2. 8 23
      ldso/include/ld_hash.h
  3. 23 2
      ldso/ldso/dl-elf.c
  4. 5 6
      ldso/ldso/dl-hash.c
  5. 5 6
      ldso/ldso/hash.c
  6. 24 24
      ldso/ldso/i386/elfinterp.c
  7. 11 11
      ldso/ldso/ldso.c
  8. 23 2
      ldso/ldso/readelflib1.c
  9. 197 92
      ldso/libdl/dlib.c
  10. 197 92
      ldso/libdl/libdl.c

+ 8 - 23
ldso/include/dl-hash.h

@@ -12,13 +12,13 @@ struct dyn_elf{
   struct dyn_elf * next;
   struct dyn_elf * prev;
 };
- 
+
 struct elf_resolve{
   /* These entries must be in this order to be compatible with the interface used
      by gdb to obtain the list of symbols. */
-  char * loadaddr;
-  char * libname;
-  unsigned long dynamic_addr;
+  ElfW(Addr) loadaddr;		/* Base address shared object is loaded at.  */
+  char *libname;		/* Absolute file name object was found in.  */
+  ElfW(Dyn) *dynamic_addr;	/* Dynamic section of the shared object.  */
   struct elf_resolve * next;
   struct elf_resolve * prev;
   /* Nothing after this address is used by gdb. */
@@ -53,25 +53,10 @@ struct elf_resolve{
 #endif
 };
 
-#if 0
-/*
- * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
- * gdb can pick this up to obtain the correct list of loaded modules.
- */
-
-struct r_debug{
-  int r_version;
-  struct elf_resolve * link_map;
-  unsigned long brk_fun;
-  enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
-  unsigned long ldbase;
-};
-#endif
-
-#define COPY_RELOCS_DONE 1
-#define RELOCS_DONE 2
-#define JMP_RELOCS_DONE 4
-#define INIT_FUNCS_CALLED 8
+#define COPY_RELOCS_DONE    1
+#define RELOCS_DONE         2
+#define JMP_RELOCS_DONE     4
+#define INIT_FUNCS_CALLED   8
 
 extern struct dyn_elf     * _dl_symbol_tables;
 extern struct elf_resolve * _dl_loaded_modules;

+ 8 - 23
ldso/include/ld_hash.h

@@ -12,13 +12,13 @@ struct dyn_elf{
   struct dyn_elf * next;
   struct dyn_elf * prev;
 };
- 
+
 struct elf_resolve{
   /* These entries must be in this order to be compatible with the interface used
      by gdb to obtain the list of symbols. */
-  char * loadaddr;
-  char * libname;
-  unsigned long dynamic_addr;
+  ElfW(Addr) loadaddr;		/* Base address shared object is loaded at.  */
+  char *libname;		/* Absolute file name object was found in.  */
+  ElfW(Dyn) *dynamic_addr;	/* Dynamic section of the shared object.  */
   struct elf_resolve * next;
   struct elf_resolve * prev;
   /* Nothing after this address is used by gdb. */
@@ -53,25 +53,10 @@ struct elf_resolve{
 #endif
 };
 
-#if 0
-/*
- * The DT_DEBUG entry in the .dynamic section is given the address of this structure.
- * gdb can pick this up to obtain the correct list of loaded modules.
- */
-
-struct r_debug{
-  int r_version;
-  struct elf_resolve * link_map;
-  unsigned long brk_fun;
-  enum {RT_CONSISTENT, RT_ADD, RT_DELETE};
-  unsigned long ldbase;
-};
-#endif
-
-#define COPY_RELOCS_DONE 1
-#define RELOCS_DONE 2
-#define JMP_RELOCS_DONE 4
-#define INIT_FUNCS_CALLED 8
+#define COPY_RELOCS_DONE    1
+#define RELOCS_DONE         2
+#define JMP_RELOCS_DONE     4
+#define INIT_FUNCS_CALLED   8
 
 extern struct dyn_elf     * _dl_symbol_tables;
 extern struct elf_resolve * _dl_loaded_modules;

+ 23 - 2
ldso/ldso/dl-elf.c

@@ -180,7 +180,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
 {
 	char *pnt, *pnt1;
 	struct elf_resolve *tpnt1;
-	char *libname;
+	char *libname, *libname2;
 
 	_dl_internal_error_number = 0;
 	pnt = libname = full_libname;
@@ -190,12 +190,33 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
 	if (_dl_strlen(full_libname) > 1024)
 		goto goof;
 
-	/* Skip over any initial initial './' path to get the libname */ 
+	/* Skip over any initial initial './' and '/' stuff to 
+	 * get the short form libname with no path garbage */ 
 	pnt1 = _dl_strrchr(pnt, '/');
 	if (pnt1) {
 		libname = pnt1 + 1;
 	}
 
+	/* Critical step!  Weed out duplicates early to avoid
+	 * function aliasing, which wastes memory, and causes
+	 * really bad things to happen with weaks and globals. */
+	for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+
+		/* Skip over any initial initial './' and '/' stuff to 
+		 * get the short form libname with no path garbage */ 
+		libname2 = tpnt1->libname;
+		pnt1 = _dl_strrchr(libname2, '/');
+		if (pnt1) {
+			libname2 = pnt1 + 1;
+		}
+
+		if (_dl_strcmp(libname2, libname) == 0) {
+			/* Well, that was certainly easy */
+			return tpnt1;
+		}
+	}
+	
+
 #if defined (__SUPPORT_LD_DEBUG__)
 	if(_dl_debug) _dl_dprintf(_dl_debug_file, "searching for library: '%s'\n", libname);
 #endif

+ 5 - 6
ldso/ldso/dl-hash.c

@@ -123,7 +123,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 	tpnt->next = NULL;
 	tpnt->init_flag = 0;
 	tpnt->libname = _dl_strdup(libname);
-	tpnt->dynamic_addr = dynamic_addr;
+	tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
 	tpnt->dynamic_size = dynamic_size;
 	tpnt->libtype = loaded_file;
 
@@ -135,7 +135,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 		hash_addr += tpnt->nbucket;
 		tpnt->chains = hash_addr;
 	}
-	tpnt->loadaddr = loadaddr;
+	tpnt->loadaddr = (ElfW(Addr))loadaddr;
 	for (i = 0; i < 24; i++)
 		tpnt->dynamic_info[i] = dynamic_info[i];
 #ifdef __mips__
@@ -285,15 +285,14 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
 							ELF32_ST_TYPE(symtab[si].st_info) 
 							== STT_NOTYPE) 
 						{	/* nakao */
-							data_result = tpnt->loadaddr + 
+							data_result = (char *)tpnt->loadaddr + 
 							    symtab[si].st_value;	/* nakao */
 							break;	/* nakao */
 						} else	/* nakao */
-							return tpnt->loadaddr + symtab[si].st_value;
+							return (char*)tpnt->loadaddr + symtab[si].st_value;
 					case STB_WEAK:
 						if (!weak_result)
-							weak_result =
-								tpnt->loadaddr + symtab[si].st_value;
+							weak_result = (char *)tpnt->loadaddr + symtab[si].st_value;
 						break;
 					default:	/* Do local symbols need to be examined? */
 						break;

+ 5 - 6
ldso/ldso/hash.c

@@ -123,7 +123,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 	tpnt->next = NULL;
 	tpnt->init_flag = 0;
 	tpnt->libname = _dl_strdup(libname);
-	tpnt->dynamic_addr = dynamic_addr;
+	tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
 	tpnt->dynamic_size = dynamic_size;
 	tpnt->libtype = loaded_file;
 
@@ -135,7 +135,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 		hash_addr += tpnt->nbucket;
 		tpnt->chains = hash_addr;
 	}
-	tpnt->loadaddr = loadaddr;
+	tpnt->loadaddr = (ElfW(Addr))loadaddr;
 	for (i = 0; i < 24; i++)
 		tpnt->dynamic_info[i] = dynamic_info[i];
 #ifdef __mips__
@@ -285,15 +285,14 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt1,
 							ELF32_ST_TYPE(symtab[si].st_info) 
 							== STT_NOTYPE) 
 						{	/* nakao */
-							data_result = tpnt->loadaddr + 
+							data_result = (char *)tpnt->loadaddr + 
 							    symtab[si].st_value;	/* nakao */
 							break;	/* nakao */
 						} else	/* nakao */
-							return tpnt->loadaddr + symtab[si].st_value;
+							return (char*)tpnt->loadaddr + symtab[si].st_value;
 					case STB_WEAK:
 						if (!weak_result)
-							weak_result =
-								tpnt->loadaddr + symtab[si].st_value;
+							weak_result = (char *)tpnt->loadaddr + symtab[si].st_value;
 						break;
 					default:	/* Do local symbols need to be examined? */
 						break;

+ 24 - 24
ldso/ldso/i386/elfinterp.c

@@ -87,7 +87,7 @@ static void debug_reloc(Elf32_Sym *symtab,char *strtab, ELF_RELOC *rpnt)
 		rpnt->r_offset,
 		rpnt->r_addend);
 #else
-    _dl_dprintf(_dl_debug_file, "%s\toffset=%x",
+    _dl_dprintf(_dl_debug_file, "%s\toffset=%x\n",
 		_dl_reltypes(ELF32_R_TYPE(rpnt->r_info)),
 		rpnt->r_offset);
 #endif
@@ -157,7 +157,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 			_dl_dprintf(_dl_debug_file, "\nresolve function: %s",
 					strtab + symtab[symtab_index].st_name);
 			if(_dl_debug_detail) _dl_dprintf(_dl_debug_file, 
-					"\n\tpatch %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
+					"\n\tpatched %x ==> %x @ %x\n", *got_addr, new_addr, got_addr);
 		}
 	}
 	if (!_dl_debug_nofixups) {
@@ -178,7 +178,6 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 {
 	unsigned int i;
 	char *strtab;
-	int goof = 0;
 	Elf32_Sym *symtab;
 	ELF_RELOC *rpnt;
 	int symtab_index;
@@ -230,10 +229,10 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 		else if (res >0)
 		{
 			_dl_dprintf(2, "can't resolve symbol\n");
-			goof += res;
+			return res;
 		}
 	  }
-	  return goof;
+	  return 0;
 }
 
 
@@ -243,19 +242,23 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 {
 	int reloc_type;
 	int symtab_index;
+	char *symname;
 	unsigned long *reloc_addr;
 	unsigned long symbol_addr;
-	int goof = 0;
+#if defined (__SUPPORT_LD_DEBUG__)
+	unsigned long old_val;
+#endif
 
 	reloc_addr   = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
 	reloc_type   = ELF32_R_TYPE(rpnt->r_info);
 	symtab_index = ELF32_R_SYM(rpnt->r_info);
 	symbol_addr  = 0;
+	symname      = strtab + symtab[symtab_index].st_name;
 
 	if (symtab_index) {
 
-		symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name, 
-				scope, (reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
+		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, 
+				(reloc_type == R_386_JMP_SLOT ? tpnt : NULL), symbolrel);
 
 		/*
 		 * We want to allow undefined references to weak symbols - this might
@@ -265,16 +268,15 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 
 		if (!symbol_addr && ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_GLOBAL) {
 #if defined (__SUPPORT_LD_DEBUG__)
-			_dl_dprintf(2, "library '%s': NOT resolving global symbol '%s'\n",
-					tpnt->libname, strtab + symtab[symtab_index].st_name);
+			_dl_dprintf(2, "\tglobal symbol '%s' already defined in '%s'\n",
+					symname, tpnt->libname);
 #endif
-			goof++;
+			return 0;
 		}
 	}
 
 #if defined (__SUPPORT_LD_DEBUG__)
-	{
-		unsigned long old_val = *reloc_addr;
+	old_val = *reloc_addr;
 #endif
 		switch (reloc_type) {
 			case R_386_NONE:
@@ -299,13 +301,11 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 				return -1; /*call _dl_exit(1) */
 		}
 #if defined (__SUPPORT_LD_DEBUG__)
-		if(_dl_debug_reloc && _dl_debug_detail)
-			_dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
-	}
-
+	if(_dl_debug_reloc && _dl_debug_detail)
+		_dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
 #endif
 
-	return goof;
+	return 0;
 }
 
 static int
@@ -314,6 +314,9 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
 {
 	int reloc_type;
 	unsigned long *reloc_addr;
+#if defined (__SUPPORT_LD_DEBUG__)
+	unsigned long old_val;
+#endif
 	(void)scope;
 	(void)symtab;
 	(void)strtab;
@@ -322,8 +325,7 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
 	reloc_type = ELF32_R_TYPE(rpnt->r_info);
 
 #if defined (__SUPPORT_LD_DEBUG__)
-	{
-		unsigned long old_val = *reloc_addr;
+	old_val = *reloc_addr;
 #endif
 		switch (reloc_type) {
 			case R_386_NONE:
@@ -335,10 +337,8 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
 				return -1; /*call _dl_exit(1) */
 		}
 #if defined (__SUPPORT_LD_DEBUG__)
-		if(_dl_debug_reloc && _dl_debug_detail)
-			_dl_dprintf(_dl_debug_file, "\tpatch: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
-	}
-
+	if(_dl_debug_reloc && _dl_debug_detail)
+		_dl_dprintf(_dl_debug_file, "\tpatched: %x ==> %x @ %x", old_val, *reloc_addr, reloc_addr);
 #endif
 	return 0;
 

+ 11 - 11
ldso/ldso/ldso.c

@@ -142,7 +142,6 @@ static char *_dl_malloc_addr, *_dl_mmap_zero;
 
 static char *_dl_trace_loaded_objects = 0;
 static int (*_dl_elf_main) (int, char **, char **);
-static int (*_dl_elf_init) (void);
 struct r_debug *_dl_debug_addr = NULL;
 unsigned long *_dl_brkp;
 unsigned long *_dl_envp;
@@ -665,7 +664,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 	tpnt->next = 0;
 	tpnt->libname = 0;
 	tpnt->libtype = program_interpreter;
-	tpnt->loadaddr = (char *) load_addr;
+	tpnt->loadaddr = (ElfW(Addr)) load_addr;
 
 #ifdef ALLOW_ZERO_PLTGOT
 	if (tpnt->dynamic_info[DT_PLTGOT])
@@ -690,17 +689,17 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 		tpnt->ppnt = myppnt = (ElfW(Phdr) *) (load_addr + epnt->e_phoff);
 		for (j = 0; j < epnt->e_phnum; j++, myppnt++) {
 			if (myppnt->p_type == PT_DYNAMIC) {
-				tpnt->dynamic_addr = myppnt->p_vaddr + load_addr;
+				tpnt->dynamic_addr = (ElfW(Dyn) *)myppnt->p_vaddr + load_addr;
 #if defined(__mips__)
 				{
 					int k = 1;
-					Elf32_Dyn *dpnt = (Elf32_Dyn *) tpnt->dynamic_addr;
+					ElfW(Dyn) *dpnt = (ElfW(Dyn) *) tpnt->dynamic_addr;
 
 					while(dpnt->d_tag) {
 						dpnt++;
 						k++;
 					}
-					tpnt->dynamic_size = k * sizeof(Elf32_Dyn);
+					tpnt->dynamic_size = k * sizeof(ElfW(Dyn));
 				}
 #else
 				tpnt->dynamic_size = myppnt->p_filesz;
@@ -1038,8 +1037,7 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 		for (dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag;
 				dpnt++) {
 			if (dpnt->d_tag == DT_NEEDED) {
-				lpntstr = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
-					dpnt->d_un.d_val;
+				lpntstr = (char*) (tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + dpnt->d_un.d_val);
 				if (_dl_strcmp(lpntstr, "libc.so.6") == 0) {
 					char *name, *msg;
 					name = tcurr->libname;
@@ -1261,15 +1259,17 @@ static void _dl_get_ready_to_run(struct elf_resolve *tpnt, struct elf_resolve *a
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
 
 		if (tpnt->dynamic_info[DT_INIT]) {
-			_dl_elf_init = (int (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
-			  
+			void (*dl_elf_func) (void);
+			dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
 #if defined (__SUPPORT_LD_DEBUG__)
 			if(_dl_debug) _dl_dprintf(_dl_debug_file,"\ncalling init: %s\n\n", tpnt->libname);	
 #endif    
-			(*_dl_elf_init) ();
+			(*dl_elf_func) ();
 		}
 		if (_dl_atexit && tpnt->dynamic_info[DT_FINI]) {
-			(*_dl_atexit) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+			void (*dl_elf_func) (void);
+			dl_elf_func = (void (*)(void)) (intptr_t) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+			(*_dl_atexit) (dl_elf_func);
 #if defined (__SUPPORT_LD_DEBUG__)
 			if(_dl_debug && _dl_on_exit)
 			{

+ 23 - 2
ldso/ldso/readelflib1.c

@@ -180,7 +180,7 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
 {
 	char *pnt, *pnt1;
 	struct elf_resolve *tpnt1;
-	char *libname;
+	char *libname, *libname2;
 
 	_dl_internal_error_number = 0;
 	pnt = libname = full_libname;
@@ -190,12 +190,33 @@ struct elf_resolve *_dl_load_shared_library(int secure, struct dyn_elf **rpnt,
 	if (_dl_strlen(full_libname) > 1024)
 		goto goof;
 
-	/* Skip over any initial initial './' path to get the libname */ 
+	/* Skip over any initial initial './' and '/' stuff to 
+	 * get the short form libname with no path garbage */ 
 	pnt1 = _dl_strrchr(pnt, '/');
 	if (pnt1) {
 		libname = pnt1 + 1;
 	}
 
+	/* Critical step!  Weed out duplicates early to avoid
+	 * function aliasing, which wastes memory, and causes
+	 * really bad things to happen with weaks and globals. */
+	for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+
+		/* Skip over any initial initial './' and '/' stuff to 
+		 * get the short form libname with no path garbage */ 
+		libname2 = tpnt1->libname;
+		pnt1 = _dl_strrchr(libname2, '/');
+		if (pnt1) {
+			libname2 = pnt1 + 1;
+		}
+
+		if (_dl_strcmp(libname2, libname) == 0) {
+			/* Well, that was certainly easy */
+			return tpnt1;
+		}
+	}
+	
+
 #if defined (__SUPPORT_LD_DEBUG__)
 	if(_dl_debug) _dl_dprintf(_dl_debug_file, "searching for library: '%s'\n", libname);
 #endif

+ 197 - 92
ldso/libdl/dlib.c

@@ -13,6 +13,7 @@ int dlclose(void *) __attribute__ ((__weak__, __alias__ ("_dlclose")));
 void *dlsym(void *, const char *) __attribute__ ((__weak__, __alias__ ("_dlsym")));
 const char *dlerror(void) __attribute__ ((__weak__, __alias__ ("_dlerror")));
 int dladdr(void *, Dl_info *) __attribute__ ((__weak__, __alias__ ("_dladdr")));
+void _dlinfo(void);
 
 
 #ifdef __PIC__
@@ -121,16 +122,14 @@ static void __attribute__ ((destructor)) dl_cleanup(void)
 
 void *_dlopen(const char *libname, int flag)
 {
-	struct elf_resolve *tpnt, *tfrom;
-	struct dyn_elf *rpnt = NULL;
-	struct dyn_elf *dyn_chain;
+	struct elf_resolve *tpnt, *tfrom, *tcurr;
+	struct dyn_elf *dyn_chain, *rpnt = NULL;
 	struct dyn_elf *dpnt;
 	static int dl_init = 0;
-	char *from;
+	ElfW(Addr) from;
+	const char *libname1, *libname2, *ptr;
+	struct elf_resolve *tpnt1;
 	void (*dl_brk) (void);
-#ifdef __PIC__
-	int (*dl_elf_init) (void);
-#endif
 
 	/* A bit of sanity checking... */
 	if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
@@ -138,7 +137,7 @@ void *_dlopen(const char *libname, int flag)
 		return NULL;
 	}
 
-	from = __builtin_return_address(0);
+	from = (ElfW(Addr)) __builtin_return_address(0);
 
 	/* Have the dynamic linker use the regular malloc function now */
 	if (!dl_init) {
@@ -150,9 +149,7 @@ void *_dlopen(const char *libname, int flag)
 	if (!libname)
 		return _dl_symbol_tables;
 
-#ifdef USE_CACHE
 	_dl_map_cache();
-#endif
 
 	/*
 	 * Try and locate the module we were called from - we
@@ -166,101 +163,204 @@ void *_dlopen(const char *libname, int flag)
 	for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
 		tpnt = dpnt->dyn;
 		if (tpnt->loadaddr < from
-			&& (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
+				&& (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
 			tfrom = tpnt;
 	}
 
+	/* Skip over any initial initial './' and '/' stuff to 
+	 * get the short form libname with no path garbage */
+	libname1 = libname;
+	ptr = _dl_strrchr(libname1, '/');
+	if (ptr) {
+	    libname1 = ptr + 1;
+	}
+
+
+	/* Weed out duplicates early to avoid function aliasing */
+	for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+	    /* Skip over any initial initial './' and '/' stuff to 
+	     * get the short form libname with no path garbage */ 
+	    libname2 = tpnt1->libname;
+	    ptr = _dl_strrchr(libname2, '/');
+	    if (ptr) {
+		libname2 = ptr + 1;
+	    }
+
+	    if (_dl_strcmp(libname1, libname2) == 0) {
+		/* Well, that was certainly easy */
+		return tpnt1;
+	    }
+	}
+
+
+
+	/* Try to load the specified library */
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
+#endif
 	if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
-#ifdef USE_CACHE
 		_dl_unmap_cache();
-#endif
 		return NULL;
 	}
 	//tpnt->libtype = loaded_file;
 
-	dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
-	_dl_memset(rpnt, 0, sizeof(struct dyn_elf));
-	rpnt->dyn = tpnt;
-	rpnt->flags = flag;
+
+	dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+	_dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
+	dyn_chain->dyn = tpnt;
+	dyn_chain->flags = flag;
 	if (!tpnt->symbol_scope)
 		tpnt->symbol_scope = dyn_chain;
 
-	rpnt->next_handle = _dl_handles;
-	_dl_handles = rpnt;
+	dyn_chain->next_handle = _dl_handles;
+	_dl_handles = rpnt = dyn_chain;
 
-	/*
-	 * OK, we have the requested file in memory.  Now check for
-	 * any other requested files that may also be required.
-	 */
-	  {
-	    struct elf_resolve *tcurr;
-	    struct elf_resolve * tpnt1;
-	    Elf32_Dyn * dpnt;
-	    char * lpnt;
-
-	    tcurr = tpnt;
-	    do{
-	      for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
-		{
-	  
-		  if(dpnt->d_tag == DT_NEEDED)
-		    {
-		      lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
-			dpnt->d_un.d_val;
-		      if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt)))
-			goto oops;
 
-		      rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
-		      _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
-		      rpnt = rpnt->next;
-		      if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
-		      rpnt->dyn = tpnt1;
-		    };
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
+#endif
+	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) {
+				lpntstr = (char*)tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+					dpnt->d_un.d_val;
+
+				/* Skip over any initial initial './' and '/' stuff to 
+				 * get the short form libname with no path garbage */
+				libname1 = lpntstr;
+				ptr = _dl_strrchr(libname1, '/');
+				if (ptr) {
+				    libname1 = ptr + 1;
+				}
+
+				/* Linked with glibc? */
+				if (_dl_strcmp(libname1, "libc.so.6") == 0) {
+					_dl_dprintf(2, "\tERROR: %s is linked with GNU libc!\n", 
+						tcurr->libname);
+					goto oops;
+				}
+
+#if 0
+				{
+				    struct elf_resolve *tpnt2;
+				    /* Weed out duplicates early to avoid function aliasing */
+				    for (tpnt2 = _dl_loaded_modules; tpnt2; tpnt2 = tpnt2->next) {
+					/* Skip over any initial initial './' and '/' stuff to 
+					 * get the short form libname with no path garbage */ 
+					libname2 = tpnt2->libname;
+					ptr = _dl_strrchr(libname2, '/');
+					if (ptr) {
+					    libname2 = ptr + 1;
+					}
+
+					if (_dl_strcmp(libname1, libname2) == 0) {
+					    /* Well, that was certainly easy */
+#ifdef __SUPPORT_LD_DEBUG__
+					    _dl_dprintf(_dl_debug_file, "\tLibrary '%s' needed by '%s' "
+						    "already loaded\n", lpntstr, tcurr->libname);
+#endif
+					    continue;
+					}
+				    }
+				}
+#endif
+
+#ifdef __SUPPORT_LD_DEBUG__
+				_dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n", 
+						lpntstr, tcurr->libname);
+#endif
+
+#if 1
+
+				if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) {
+					goto oops;
+				}
+#else
+				if (!(tpnt1 = _dlopen(lpntstr, flag))) {
+					goto oops;
+				}
+#endif
+
+				rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+				_dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
+				rpnt = rpnt->next;
+				if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
+				rpnt->dyn = tpnt1;
+
+			}
 		}
-	      
-	      tcurr = tcurr->next;
-	    } while(tcurr);
-	  }
-	 
+	}
+
 	/*
 	 * OK, now attach the entire chain at the end
 	 */
-
 	rpnt->next = _dl_symbol_tables;
 
+#ifdef __mips__
 	/*
-	 * MIPS is special *sigh*
+	 * Relocation of the GOT entries for MIPS have to be done
+	 * after all the libraries have been loaded.
 	 */
-#ifdef __mips__
 	_dl_perform_mips_global_got_relocations(tpnt);
 #endif
 
-	if (_dl_fixup(tpnt, (flag & RTLD_LAZY))) {
-		_dl_error_number = LD_NO_SYMBOL;
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
+#endif
+	/*
+	 * OK, now all of the kids are tucked into bed in their proper addresses.
+	 * Now we go through and look for REL and RELA records that indicate fixups
+	 * to the GOT tables.  We need to do this in reverse order so that COPY
+	 * directives work correctly */
+	if (_dl_fixup(dyn_chain->dyn, (flag & RTLD_LAZY)))
 		goto oops;
+
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Beginning dlopen copy fixups\n");
+#endif
+	if (_dl_symbol_tables) {
+		if (_dl_copy_fixups(dyn_chain))
+			goto oops;
 	}
 
+
+	/* TODO:  Should we set the protections of all pages back to R/O now ? */
+	
+
+	/* Notify the debugger we have added some objects. */
+	_dl_debug_addr->r_state = RT_ADD;
 	if (_dl_debug_addr) {
-	    dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
-	    if (dl_brk != NULL) {
-		_dl_debug_addr->r_state = RT_ADD;
-		(*dl_brk) ();
+		dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
+		if (dl_brk != NULL) {
+			_dl_debug_addr->r_state = RT_ADD;
+			(*dl_brk) ();
 
-		_dl_debug_addr->r_state = RT_CONSISTENT;
-		(*dl_brk) ();
-	    }
+			_dl_debug_addr->r_state = RT_CONSISTENT;
+			(*dl_brk) ();
+		}
 	}
 
+#if 1
+#ifdef __SUPPORT_LD_DEBUG__
+	_dlinfo();
+#endif
+#endif
+
 #ifdef __PIC__
-	/* Find the last library */
-	for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
-		;
+	/* Find the last library so we can run things in the right order */
+	for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
+	    ;
+
 	/* Run the ctors and set up the dtors */
-	for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
+	for (;rpnt!=NULL; rpnt=rpnt->prev)
 	{
 		/* Apparently crt1 for the application is responsible for handling this.
 		 * We only need to run the init/fini for shared libraries
 		 */
+		tpnt = rpnt->dyn;
 		if (tpnt->libtype == program_interpreter)
 			continue;
 		if (tpnt->libtype == elf_executable)
@@ -270,26 +370,32 @@ void *_dlopen(const char *libname, int flag)
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
 
 		if (tpnt->dynamic_info[DT_INIT]) {
-			dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
-			(*dl_elf_init) ();
+		    void (*dl_elf_func) (void);
+		    dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
+		    if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+			_dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+			(*dl_elf_func) ();
+		    }
 		}
 		if (tpnt->dynamic_info[DT_FINI]) {
-			atexit((void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]));
+		    void (*dl_elf_func) (void);
+		    dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+		    if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+			_dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+			atexit(dl_elf_func);
+		    }
 		}
-
 	}
 #endif
-
-#ifdef USE_CACHE
-	_dl_unmap_cache();
-#endif
 	return (void *) dyn_chain;
 
-  oops:
+oops:
 	/* Something went wrong.  Clean up and return NULL. */
-#ifdef USE_CACHE
 	_dl_unmap_cache();
-#endif
 	do_dlclose(dyn_chain, 0);
 	return NULL;
 }
@@ -298,7 +404,7 @@ void *_dlsym(void *vhandle, const char *name)
 {
 	struct elf_resolve *tpnt, *tfrom;
 	struct dyn_elf *handle;
-	char *from;
+	ElfW(Addr) from;
 	struct dyn_elf *rpnt;
 	void *ret;
 
@@ -325,7 +431,7 @@ void *_dlsym(void *vhandle, const char *name)
 		 * dynamic loader itself, as it doesn't know
 		 * how to properly treat it.
 		 */
-		from = __builtin_return_address(0);
+		from = (ElfW(Addr)) __builtin_return_address(0);
 
 		tfrom = NULL;
 		for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
@@ -442,7 +548,7 @@ static int do_dlclose(void *vhandle, int need_fini)
 				if (end < ppnt->p_vaddr + ppnt->p_memsz)
 					end = ppnt->p_vaddr + ppnt->p_memsz;
 			}
-			_dl_munmap(rpnt->dyn->loadaddr, end);
+			_dl_munmap((void*)rpnt->dyn->loadaddr, end);
 			/* Next, remove rpnt->dyn from the loaded_module list */
 			if (_dl_loaded_modules == rpnt->dyn) {
 				_dl_loaded_modules = rpnt->dyn->next;
@@ -527,9 +633,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
 	struct elf_resolve *pelf;
 	struct elf_resolve *rpnt;
 
-#ifdef USE_CACHE
 	_dl_map_cache();
-#endif
 
 	/*
 	 * Try and locate the module address is in
@@ -537,7 +641,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
 	pelf = NULL;
 
 #if 0
-	_dl_dprintf(2, "dladdr( 0x%p, 0x%p )\n", __address, __dlip);
+	_dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
 #endif
 
 	for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
@@ -545,10 +649,10 @@ int _dladdr(void *__address, Dl_info * __dlip)
 
 		tpnt = rpnt;
 #if 0
-		_dl_dprintf(2, "Module \"%s\" at 0x%p\n", 
+		_dl_dprintf(2, "Module \"%s\" at %x\n", 
 			tpnt->libname, tpnt->loadaddr);
 #endif
-		if (tpnt->loadaddr < (char *) __address
+		if (tpnt->loadaddr < (ElfW(Addr)) __address
 			&& (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
 		    pelf = tpnt;
 		}
@@ -568,24 +672,25 @@ int _dladdr(void *__address, Dl_info * __dlip)
 		int hn, si;
 		int sf;
 		int sn = 0;
-		void *sa = 0;
+		ElfW(Addr) sa;
 
+		sa = 0;
 		symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
 		strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
 
 		sf = 0;
 		for (hn = 0; hn < pelf->nbucket; hn++) {
 			for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
-				void *symbol_addr;
+				ElfW(Addr) symbol_addr;
 
 				symbol_addr = pelf->loadaddr + symtab[si].st_value;
-				if (symbol_addr <= __address && (!sf || sa < symbol_addr)) {
+				if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
 					sa = symbol_addr;
 					sn = si;
 					sf = 1;
 				}
 #if 0
-				_dl_dprintf(2, "Symbol \"%s\" at 0x%p\n", 
+				_dl_dprintf(2, "Symbol \"%s\" at %x\n", 
 					strtab + symtab[si].st_name, symbol_addr);
 #endif
 			}
@@ -593,9 +698,9 @@ int _dladdr(void *__address, Dl_info * __dlip)
 
 		if (sf) {
 			__dlip->dli_fname = pelf->libname;
-			__dlip->dli_fbase = pelf->loadaddr;
+			__dlip->dli_fbase = (void *)pelf->loadaddr;
 			__dlip->dli_sname = strtab + symtab[sn].st_name;
-			__dlip->dli_saddr = sa;
+			__dlip->dli_saddr = (void *)sa;
 		}
 		return 1;
 	}

+ 197 - 92
ldso/libdl/libdl.c

@@ -13,6 +13,7 @@ int dlclose(void *) __attribute__ ((__weak__, __alias__ ("_dlclose")));
 void *dlsym(void *, const char *) __attribute__ ((__weak__, __alias__ ("_dlsym")));
 const char *dlerror(void) __attribute__ ((__weak__, __alias__ ("_dlerror")));
 int dladdr(void *, Dl_info *) __attribute__ ((__weak__, __alias__ ("_dladdr")));
+void _dlinfo(void);
 
 
 #ifdef __PIC__
@@ -121,16 +122,14 @@ static void __attribute__ ((destructor)) dl_cleanup(void)
 
 void *_dlopen(const char *libname, int flag)
 {
-	struct elf_resolve *tpnt, *tfrom;
-	struct dyn_elf *rpnt = NULL;
-	struct dyn_elf *dyn_chain;
+	struct elf_resolve *tpnt, *tfrom, *tcurr;
+	struct dyn_elf *dyn_chain, *rpnt = NULL;
 	struct dyn_elf *dpnt;
 	static int dl_init = 0;
-	char *from;
+	ElfW(Addr) from;
+	const char *libname1, *libname2, *ptr;
+	struct elf_resolve *tpnt1;
 	void (*dl_brk) (void);
-#ifdef __PIC__
-	int (*dl_elf_init) (void);
-#endif
 
 	/* A bit of sanity checking... */
 	if (!(flag & (RTLD_LAZY|RTLD_NOW))) {
@@ -138,7 +137,7 @@ void *_dlopen(const char *libname, int flag)
 		return NULL;
 	}
 
-	from = __builtin_return_address(0);
+	from = (ElfW(Addr)) __builtin_return_address(0);
 
 	/* Have the dynamic linker use the regular malloc function now */
 	if (!dl_init) {
@@ -150,9 +149,7 @@ void *_dlopen(const char *libname, int flag)
 	if (!libname)
 		return _dl_symbol_tables;
 
-#ifdef USE_CACHE
 	_dl_map_cache();
-#endif
 
 	/*
 	 * Try and locate the module we were called from - we
@@ -166,101 +163,204 @@ void *_dlopen(const char *libname, int flag)
 	for (dpnt = _dl_symbol_tables; dpnt; dpnt = dpnt->next) {
 		tpnt = dpnt->dyn;
 		if (tpnt->loadaddr < from
-			&& (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
+				&& (tfrom == NULL || tfrom->loadaddr < tpnt->loadaddr))
 			tfrom = tpnt;
 	}
 
+	/* Skip over any initial initial './' and '/' stuff to 
+	 * get the short form libname with no path garbage */
+	libname1 = libname;
+	ptr = _dl_strrchr(libname1, '/');
+	if (ptr) {
+	    libname1 = ptr + 1;
+	}
+
+
+	/* Weed out duplicates early to avoid function aliasing */
+	for (tpnt1 = _dl_loaded_modules; tpnt1; tpnt1 = tpnt1->next) {
+	    /* Skip over any initial initial './' and '/' stuff to 
+	     * get the short form libname with no path garbage */ 
+	    libname2 = tpnt1->libname;
+	    ptr = _dl_strrchr(libname2, '/');
+	    if (ptr) {
+		libname2 = ptr + 1;
+	    }
+
+	    if (_dl_strcmp(libname1, libname2) == 0) {
+		/* Well, that was certainly easy */
+		return tpnt1;
+	    }
+	}
+
+
+
+	/* Try to load the specified library */
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Trying to dlopen '%s'\n", (char*)libname);
+#endif
 	if (!(tpnt = _dl_load_shared_library(0, &rpnt, tfrom, (char*)libname))) {
-#ifdef USE_CACHE
 		_dl_unmap_cache();
-#endif
 		return NULL;
 	}
 	//tpnt->libtype = loaded_file;
 
-	dyn_chain = rpnt = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
-	_dl_memset(rpnt, 0, sizeof(struct dyn_elf));
-	rpnt->dyn = tpnt;
-	rpnt->flags = flag;
+
+	dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+	_dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
+	dyn_chain->dyn = tpnt;
+	dyn_chain->flags = flag;
 	if (!tpnt->symbol_scope)
 		tpnt->symbol_scope = dyn_chain;
 
-	rpnt->next_handle = _dl_handles;
-	_dl_handles = rpnt;
+	dyn_chain->next_handle = _dl_handles;
+	_dl_handles = rpnt = dyn_chain;
 
-	/*
-	 * OK, we have the requested file in memory.  Now check for
-	 * any other requested files that may also be required.
-	 */
-	  {
-	    struct elf_resolve *tcurr;
-	    struct elf_resolve * tpnt1;
-	    Elf32_Dyn * dpnt;
-	    char * lpnt;
-
-	    tcurr = tpnt;
-	    do{
-	      for(dpnt = (Elf32_Dyn *) tcurr->dynamic_addr; dpnt->d_tag; dpnt++)
-		{
-	  
-		  if(dpnt->d_tag == DT_NEEDED)
-		    {
-		      lpnt = tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] + 
-			dpnt->d_un.d_val;
-		      if(!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpnt)))
-			goto oops;
 
-		      rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
-		      _dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
-		      rpnt = rpnt->next;
-		      if (!tpnt1->symbol_scope) tpnt1->symbol_scope = dyn_chain;
-		      rpnt->dyn = tpnt1;
-		    };
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Looking for needed libraries\n");
+#endif
+	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) {
+				lpntstr = (char*)tcurr->loadaddr + tcurr->dynamic_info[DT_STRTAB] +
+					dpnt->d_un.d_val;
+
+				/* Skip over any initial initial './' and '/' stuff to 
+				 * get the short form libname with no path garbage */
+				libname1 = lpntstr;
+				ptr = _dl_strrchr(libname1, '/');
+				if (ptr) {
+				    libname1 = ptr + 1;
+				}
+
+				/* Linked with glibc? */
+				if (_dl_strcmp(libname1, "libc.so.6") == 0) {
+					_dl_dprintf(2, "\tERROR: %s is linked with GNU libc!\n", 
+						tcurr->libname);
+					goto oops;
+				}
+
+#if 0
+				{
+				    struct elf_resolve *tpnt2;
+				    /* Weed out duplicates early to avoid function aliasing */
+				    for (tpnt2 = _dl_loaded_modules; tpnt2; tpnt2 = tpnt2->next) {
+					/* Skip over any initial initial './' and '/' stuff to 
+					 * get the short form libname with no path garbage */ 
+					libname2 = tpnt2->libname;
+					ptr = _dl_strrchr(libname2, '/');
+					if (ptr) {
+					    libname2 = ptr + 1;
+					}
+
+					if (_dl_strcmp(libname1, libname2) == 0) {
+					    /* Well, that was certainly easy */
+#ifdef __SUPPORT_LD_DEBUG__
+					    _dl_dprintf(_dl_debug_file, "\tLibrary '%s' needed by '%s' "
+						    "already loaded\n", lpntstr, tcurr->libname);
+#endif
+					    continue;
+					}
+				    }
+				}
+#endif
+
+#ifdef __SUPPORT_LD_DEBUG__
+				_dl_dprintf(_dl_debug_file, "Trying to load '%s', needed by '%s'\n", 
+						lpntstr, tcurr->libname);
+#endif
+
+#if 1
+
+				if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr))) {
+					goto oops;
+				}
+#else
+				if (!(tpnt1 = _dlopen(lpntstr, flag))) {
+					goto oops;
+				}
+#endif
+
+				rpnt->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
+				_dl_memset (rpnt->next, 0, sizeof (struct dyn_elf));
+				rpnt = rpnt->next;
+				if (!tpnt1->symbol_scope) tpnt1->symbol_scope = rpnt;
+				rpnt->dyn = tpnt1;
+
+			}
 		}
-	      
-	      tcurr = tcurr->next;
-	    } while(tcurr);
-	  }
-	 
+	}
+
 	/*
 	 * OK, now attach the entire chain at the end
 	 */
-
 	rpnt->next = _dl_symbol_tables;
 
+#ifdef __mips__
 	/*
-	 * MIPS is special *sigh*
+	 * Relocation of the GOT entries for MIPS have to be done
+	 * after all the libraries have been loaded.
 	 */
-#ifdef __mips__
 	_dl_perform_mips_global_got_relocations(tpnt);
 #endif
 
-	if (_dl_fixup(tpnt, (flag & RTLD_LAZY))) {
-		_dl_error_number = LD_NO_SYMBOL;
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Beginning dlopen relocation fixups\n");
+#endif
+	/*
+	 * OK, now all of the kids are tucked into bed in their proper addresses.
+	 * Now we go through and look for REL and RELA records that indicate fixups
+	 * to the GOT tables.  We need to do this in reverse order so that COPY
+	 * directives work correctly */
+	if (_dl_fixup(dyn_chain->dyn, (flag & RTLD_LAZY)))
 		goto oops;
+
+#ifdef __SUPPORT_LD_DEBUG__
+	_dl_dprintf(_dl_debug_file, "Beginning dlopen copy fixups\n");
+#endif
+	if (_dl_symbol_tables) {
+		if (_dl_copy_fixups(dyn_chain))
+			goto oops;
 	}
 
+
+	/* TODO:  Should we set the protections of all pages back to R/O now ? */
+	
+
+	/* Notify the debugger we have added some objects. */
+	_dl_debug_addr->r_state = RT_ADD;
 	if (_dl_debug_addr) {
-	    dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
-	    if (dl_brk != NULL) {
-		_dl_debug_addr->r_state = RT_ADD;
-		(*dl_brk) ();
+		dl_brk = (void (*)(void)) _dl_debug_addr->r_brk;
+		if (dl_brk != NULL) {
+			_dl_debug_addr->r_state = RT_ADD;
+			(*dl_brk) ();
 
-		_dl_debug_addr->r_state = RT_CONSISTENT;
-		(*dl_brk) ();
-	    }
+			_dl_debug_addr->r_state = RT_CONSISTENT;
+			(*dl_brk) ();
+		}
 	}
 
+#if 1
+#ifdef __SUPPORT_LD_DEBUG__
+	_dlinfo();
+#endif
+#endif
+
 #ifdef __PIC__
-	/* Find the last library */
-	for (tpnt = dyn_chain->dyn; tpnt->next!=NULL; tpnt = tpnt->next)
-		;
+	/* Find the last library so we can run things in the right order */
+	for (rpnt = _dl_symbol_tables; rpnt!=NULL&& rpnt->next!=NULL; rpnt=rpnt->next)
+	    ;
+
 	/* Run the ctors and set up the dtors */
-	for (; tpnt != dyn_chain->dyn->prev; tpnt=tpnt->prev)
+	for (;rpnt!=NULL; rpnt=rpnt->prev)
 	{
 		/* Apparently crt1 for the application is responsible for handling this.
 		 * We only need to run the init/fini for shared libraries
 		 */
+		tpnt = rpnt->dyn;
 		if (tpnt->libtype == program_interpreter)
 			continue;
 		if (tpnt->libtype == elf_executable)
@@ -270,26 +370,32 @@ void *_dlopen(const char *libname, int flag)
 		tpnt->init_flag |= INIT_FUNCS_CALLED;
 
 		if (tpnt->dynamic_info[DT_INIT]) {
-			dl_elf_init = (int (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
-			(*dl_elf_init) ();
+		    void (*dl_elf_func) (void);
+		    dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_INIT]);
+		    if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+			_dl_dprintf(2, "running ctors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+			(*dl_elf_func) ();
+		    }
 		}
 		if (tpnt->dynamic_info[DT_FINI]) {
-			atexit((void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]));
+		    void (*dl_elf_func) (void);
+		    dl_elf_func = (void (*)(void)) (tpnt->loadaddr + tpnt->dynamic_info[DT_FINI]);
+		    if (dl_elf_func && *dl_elf_func != NULL) {
+#ifdef __SUPPORT_LD_DEBUG__
+			_dl_dprintf(2, "setting up dtors for library %s at '%x'\n", tpnt->libname, dl_elf_func);
+#endif
+			atexit(dl_elf_func);
+		    }
 		}
-
 	}
 #endif
-
-#ifdef USE_CACHE
-	_dl_unmap_cache();
-#endif
 	return (void *) dyn_chain;
 
-  oops:
+oops:
 	/* Something went wrong.  Clean up and return NULL. */
-#ifdef USE_CACHE
 	_dl_unmap_cache();
-#endif
 	do_dlclose(dyn_chain, 0);
 	return NULL;
 }
@@ -298,7 +404,7 @@ void *_dlsym(void *vhandle, const char *name)
 {
 	struct elf_resolve *tpnt, *tfrom;
 	struct dyn_elf *handle;
-	char *from;
+	ElfW(Addr) from;
 	struct dyn_elf *rpnt;
 	void *ret;
 
@@ -325,7 +431,7 @@ void *_dlsym(void *vhandle, const char *name)
 		 * dynamic loader itself, as it doesn't know
 		 * how to properly treat it.
 		 */
-		from = __builtin_return_address(0);
+		from = (ElfW(Addr)) __builtin_return_address(0);
 
 		tfrom = NULL;
 		for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
@@ -442,7 +548,7 @@ static int do_dlclose(void *vhandle, int need_fini)
 				if (end < ppnt->p_vaddr + ppnt->p_memsz)
 					end = ppnt->p_vaddr + ppnt->p_memsz;
 			}
-			_dl_munmap(rpnt->dyn->loadaddr, end);
+			_dl_munmap((void*)rpnt->dyn->loadaddr, end);
 			/* Next, remove rpnt->dyn from the loaded_module list */
 			if (_dl_loaded_modules == rpnt->dyn) {
 				_dl_loaded_modules = rpnt->dyn->next;
@@ -527,9 +633,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
 	struct elf_resolve *pelf;
 	struct elf_resolve *rpnt;
 
-#ifdef USE_CACHE
 	_dl_map_cache();
-#endif
 
 	/*
 	 * Try and locate the module address is in
@@ -537,7 +641,7 @@ int _dladdr(void *__address, Dl_info * __dlip)
 	pelf = NULL;
 
 #if 0
-	_dl_dprintf(2, "dladdr( 0x%p, 0x%p )\n", __address, __dlip);
+	_dl_dprintf(2, "dladdr( %x, %x )\n", __address, __dlip);
 #endif
 
 	for (rpnt = _dl_loaded_modules; rpnt; rpnt = rpnt->next) {
@@ -545,10 +649,10 @@ int _dladdr(void *__address, Dl_info * __dlip)
 
 		tpnt = rpnt;
 #if 0
-		_dl_dprintf(2, "Module \"%s\" at 0x%p\n", 
+		_dl_dprintf(2, "Module \"%s\" at %x\n", 
 			tpnt->libname, tpnt->loadaddr);
 #endif
-		if (tpnt->loadaddr < (char *) __address
+		if (tpnt->loadaddr < (ElfW(Addr)) __address
 			&& (pelf == NULL || pelf->loadaddr < tpnt->loadaddr)) {
 		    pelf = tpnt;
 		}
@@ -568,24 +672,25 @@ int _dladdr(void *__address, Dl_info * __dlip)
 		int hn, si;
 		int sf;
 		int sn = 0;
-		void *sa = 0;
+		ElfW(Addr) sa;
 
+		sa = 0;
 		symtab = (Elf32_Sym *) (pelf->dynamic_info[DT_SYMTAB] + pelf->loadaddr);
 		strtab = (char *) (pelf->dynamic_info[DT_STRTAB] + pelf->loadaddr);
 
 		sf = 0;
 		for (hn = 0; hn < pelf->nbucket; hn++) {
 			for (si = pelf->elf_buckets[hn]; si; si = pelf->chains[si]) {
-				void *symbol_addr;
+				ElfW(Addr) symbol_addr;
 
 				symbol_addr = pelf->loadaddr + symtab[si].st_value;
-				if (symbol_addr <= __address && (!sf || sa < symbol_addr)) {
+				if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
 					sa = symbol_addr;
 					sn = si;
 					sf = 1;
 				}
 #if 0
-				_dl_dprintf(2, "Symbol \"%s\" at 0x%p\n", 
+				_dl_dprintf(2, "Symbol \"%s\" at %x\n", 
 					strtab + symtab[si].st_name, symbol_addr);
 #endif
 			}
@@ -593,9 +698,9 @@ int _dladdr(void *__address, Dl_info * __dlip)
 
 		if (sf) {
 			__dlip->dli_fname = pelf->libname;
-			__dlip->dli_fbase = pelf->loadaddr;
+			__dlip->dli_fbase = (void *)pelf->loadaddr;
 			__dlip->dli_sname = strtab + symtab[sn].st_name;
-			__dlip->dli_saddr = sa;
+			__dlip->dli_saddr = (void *)sa;
 		}
 		return 1;
 	}