Explorar el Código

Add RTLD_LOCAL support for dlopened libs. Reported by
Andrew de Quincey, who has been most helpful getting this sorted
out, thanks. Thanks also to Peter Mazinger who did alot of testing.

Removed all traces of dl_parse_copy_information() since it is no longer used.

Joakim Tjernlund hace 19 años
padre
commit
0038f6a229

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

@@ -35,7 +35,7 @@ struct elf_resolve{
   unsigned int nbucket;
   unsigned long * elf_buckets;
   struct init_fini_list *init_fini;
-
+  struct init_fini_list *rtld_local; /* keep tack of RTLD_LOCAL libs in same group */
   /*
    * These are only used with ELF style shared libraries
    */
@@ -71,7 +71,7 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
 	unsigned long dynamic_addr, unsigned long dynamic_size);
 
 extern char * _dl_find_hash(const char * name, struct dyn_elf * rpnt1, 
-			    int type_class);
+			    struct elf_resolve *mytpnt, int type_class);
 
 extern int _dl_linux_dynamic_link(void);
 

+ 3 - 56
ldso/ldso/arm/elfinterp.c

@@ -149,8 +149,8 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 	got_addr = (char **) instr_addr;
 
 	/* Get the address of the GOT entry */
-	new_addr = _dl_find_hash(symname,
-		tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+	new_addr = _dl_find_hash(symname, tpnt->symbol_scope,
+				 tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
 			_dl_progname, symname);
@@ -278,7 +278,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 	if (symtab_index) {
 
 		symbol_addr = (unsigned long) _dl_find_hash(strtab + symtab[symtab_index].st_name,
-				scope, elf_machine_type_class(reloc_type));
+				scope, tpnt, elf_machine_type_class(reloc_type));
 
 		/*
 		 * We want to allow undefined references to weak symbols - this might
@@ -391,53 +391,6 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
 
 }
 
-/* This is done as a separate step, because there are cases where
-   information is first copied and later initialized.  This results in
-   the wrong information being copied.  Someone at Sun was complaining about
-   a bug in the handling of _COPY by SVr4, and this may in fact be what he
-   was talking about.  Sigh. */
-
-/* No, there are cases where the SVr4 linker fails to emit COPY relocs
-   at all */
-static int
-_dl_do_copy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
-	     ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
-{
-        int reloc_type;
-	int symtab_index;
-	unsigned long *reloc_addr;
-	unsigned long symbol_addr;
-	int goof = 0;
-	return 0; /* disable now, remove later */
-	reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
-	reloc_type = ELF32_R_TYPE(rpnt->r_info);
-	if (reloc_type != R_ARM_COPY)
-		return 0;
-	symtab_index = ELF32_R_SYM(rpnt->r_info);
-	symbol_addr = 0;
-
-	if (symtab_index) {
-
-		symbol_addr = (unsigned long) _dl_find_hash(strtab +
-			symtab[symtab_index].st_name, scope,
-			ELF_RTYPE_CLASS_COPY);
-		if (!symbol_addr) goof++;
-	}
-	if (!goof) {
-#if defined (__SUPPORT_LD_DEBUG__)
-	        if(_dl_debug_move)
-		  _dl_dprintf(_dl_debug_file,"\n%s move %x bytes from %x to %x",
-			     strtab + symtab[symtab_index].st_name,
-			     symtab[symtab_index].st_size,
-			     symbol_addr, symtab[symtab_index].st_value);
-#endif
-		_dl_memcpy((char *) symtab[symtab_index].st_value,
-			(char *) symbol_addr, symtab[symtab_index].st_size);
-	}
-
-	return goof;
-}
-
 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 	unsigned long rel_addr, unsigned long rel_size)
 {
@@ -450,9 +403,3 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
 	return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
 }
 
-int _dl_parse_copy_information(struct dyn_elf *rpnt,
-	unsigned long rel_addr, unsigned long rel_size)
-{
-	return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);
-}
-

+ 2 - 2
ldso/ldso/cris/elfinterp.c

@@ -144,7 +144,7 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 	got_addr = (char **)instr_addr;
 
 	/* Get the address of the GOT entry. */
-	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname);
 		_dl_exit(1);
@@ -253,7 +253,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 		    ELF32_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL) {
 			symbol_addr = (unsigned long)tpnt->loadaddr;
 		} else {
-			symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
+		  symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
 								   elf_machine_type_class(reloc_type));
 		}
 

+ 15 - 8
ldso/ldso/dl-hash.c

@@ -137,7 +137,7 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
  * This function resolves externals, and this is either called when we process
  * relocations or when we call an entry in the PLT table for the first time.
  */
-char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, int type_class)
+char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt, int type_class)
 {
 	struct elf_resolve *tpnt;
 	int si;
@@ -148,17 +148,24 @@ char *_dl_find_hash(const char *name, struct dyn_elf *rpnt, int type_class)
 	char *weak_result = NULL;
 
 	elf_hash_number = _dl_elf_hash(name);
-
-	/* 
-	   NOTE! RTLD_LOCAL handling for dlopen not implemented yet.
-	   Everything is treated as RTLD_GLOBAL.
-	*/
 	   
 	for (; rpnt; rpnt = rpnt->next) {
 		tpnt = rpnt->dyn;
 
-		if (!(tpnt->rtld_flags & RTLD_GLOBAL))
-			continue;
+		if (!(tpnt->rtld_flags & RTLD_GLOBAL) && mytpnt) {
+			if (mytpnt == tpnt)
+				;
+			else {
+				struct init_fini_list *tmp;
+
+				for (tmp = mytpnt->rtld_local; tmp; tmp = tmp->next) {
+					if (tmp->tpnt == tpnt)
+						break;
+				}
+				if (!tmp)
+					continue;
+			}
+		}
 		/* Don't search the executable when resolving a copy reloc. */
 		if ((type_class &  ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
 			continue;

+ 2 - 62
ldso/ldso/i386/elfinterp.c

@@ -147,7 +147,7 @@ _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 	got_addr = (char **)instr_addr;
 
 	/* Get the address of the GOT entry. */
-	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: Can't resolve symbol '%s'\n", _dl_progname, symname);
 		_dl_exit(1);
@@ -253,7 +253,7 @@ _dl_do_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 	symname = strtab + symtab[symtab_index].st_name;
 
 	if (symtab_index) {
-		symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
+		symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
 							   elf_machine_type_class(reloc_type));
 
 		/*
@@ -355,56 +355,6 @@ _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 	return 0;
 }
 
-/* This is done as a separate step, because there are cases where
-   information is first copied and later initialized.  This results in
-   the wrong information being copied.  Someone at Sun was complaining about
-   a bug in the handling of _COPY by SVr4, and this may in fact be what he
-   was talking about.  Sigh. */
-
-/* No, there are cases where the SVr4 linker fails to emit COPY relocs
-   at all */
-static int
-_dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
-		  ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
-{
-	int reloc_type;
-	int symtab_index;
-	unsigned long *reloc_addr;
-	unsigned long symbol_addr;
-	int goof = 0;
-	char *symname;
-
-	reloc_addr = (unsigned long *)(intptr_t)(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
-	reloc_type = ELF32_R_TYPE(rpnt->r_info);
-	if (reloc_type != R_386_COPY)
-		return 0;
-
-	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(symname, scope, ELF_RTYPE_CLASS_COPY);
-		if (!symbol_addr)
-			goof++;
-	}
-
-	if (!goof) {
-#if defined (__SUPPORT_LD_DEBUG__)
-		if (_dl_debug_move)
-			_dl_dprintf(_dl_debug_file,
-				    "\n%s move %x bytes from %x to %x",
-				    symname, symtab[symtab_index].st_size,
-				    symbol_addr, symtab[symtab_index].st_value);
-#endif
-
-		_dl_memcpy((char *)symtab[symtab_index].st_value,
-			   (char *)symbol_addr, symtab[symtab_index].st_size);
-	}
-
-	return goof;
-}
-
 void
 _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 				      unsigned long rel_addr,
@@ -420,13 +370,3 @@ _dl_parse_relocation_information(struct dyn_elf *rpnt,
 {
 	return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
 }
-
-int
-_dl_parse_copy_information(struct dyn_elf *rpnt,
-			   unsigned long rel_addr,
-			   unsigned long rel_size)
-{
-	return 0;
-	/* just disable for now, remove when we know that it works */
-	/* return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc); */
-}

+ 4 - 4
ldso/ldso/ldso.c

@@ -774,7 +774,7 @@ next_lib2:
 	 * ld.so.1, so we have to look up each symbol individually.
 	 */
 
-	_dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", _dl_symbol_tables, 0);
+	_dl_envp = (unsigned long *) (intptr_t) _dl_find_hash("__environ", _dl_symbol_tables, NULL, 0);
 	if (_dl_envp)
 		*_dl_envp = (unsigned long) envp;
 
@@ -798,10 +798,10 @@ next_lib2:
 	}
 #endif
 
-	_dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", _dl_symbol_tables, ELF_RTYPE_CLASS_PLT);
+	_dl_atexit = (int (*)(void *)) (intptr_t) _dl_find_hash("atexit", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
 #if defined (__SUPPORT_LD_DEBUG__)
 	_dl_on_exit = (int (*)(void (*)(int, void *),void*))
-		(intptr_t) _dl_find_hash("on_exit", _dl_symbol_tables, ELF_RTYPE_CLASS_PLT);
+		(intptr_t) _dl_find_hash("on_exit", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
 #endif
 
 	/* Notify the debugger we have added some objects. */
@@ -853,7 +853,7 @@ next_lib2:
 	_dl_debug_state();
 
 	/* Find the real malloc function and make ldso functions use that from now on */
-	 _dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash("malloc", _dl_symbol_tables, ELF_RTYPE_CLASS_PLT);
+	 _dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash("malloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT);
 }
 
 char *_dl_getenv(const char *symbol, char **envp)

+ 2 - 62
ldso/ldso/m68k/elfinterp.c

@@ -98,7 +98,7 @@ unsigned int _dl_linux_resolver (int dummy1, int dummy2,
 
   /* Get the address of the GOT entry.  */
   new_addr = _dl_find_hash (strtab + symtab[symtab_index].st_name,
-			    tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+			    tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
   if (unlikely(!new_addr))
     {
       _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
@@ -204,7 +204,7 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
 	{
 	  symbol_addr = (unsigned int)
 	    _dl_find_hash (strtab + symtab[symtab_index].st_name,
-			   tpnt->symbol_scope,
+			   tpnt->symbol_scope, tpnt,
 			   elf_machine_type_class(reloc_type));
 
 	  /* We want to allow undefined references to weak symbols -
@@ -272,63 +272,3 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
     }
   return goof;
 }
-
-/* This is done as a separate step, because there are cases where
-   information is first copied and later initialized.  This results in
-   the wrong information being copied.  Someone at Sun was complaining about
-   a bug in the handling of _COPY by SVr4, and this may in fact be what he
-   was talking about.  Sigh.  */
-
-/* No, there are cases where the SVr4 linker fails to emit COPY relocs
-   at all.  */
-
-int _dl_parse_copy_information(struct dyn_elf *xpnt,
-	unsigned long rel_addr, unsigned long rel_size)
-{
-  int i;
-  char *strtab;
-  int reloc_type;
-  int goof = 0;
-  Elf32_Sym *symtab;
-  Elf32_Rela *rpnt;
-  unsigned int *reloc_addr;
-  unsigned int symbol_addr;
-  struct elf_resolve *tpnt;
-  int symtab_index;
-  /* Now parse the relocation information */
-  return 0; /* disable now, remove later */
-  tpnt = xpnt->dyn;
-
-  rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
-  rel_size = rel_size / sizeof (Elf32_Rela);
-
-  symtab = (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB]
-				 + tpnt->loadaddr);
-  strtab = (char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
-
-  for (i = 0; i < rel_size; i++, rpnt++)
-    {
-      reloc_addr = (int *) (tpnt->loadaddr + (int) rpnt->r_offset);
-      reloc_type = ELF32_R_TYPE (rpnt->r_info);
-      if (reloc_type != R_68K_COPY)
-	continue;
-      symtab_index = ELF32_R_SYM (rpnt->r_info);
-      symbol_addr = 0;
-      if (symtab_index)
-	{
-	  symbol_addr = (unsigned int)
-	    _dl_find_hash (strtab + symtab[symtab_index].st_name,
-			   xpnt->next, ELF_RTYPE_CLASS_COPY);
-	  if (!symbol_addr)
-	    {
-	      _dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
-			    _dl_progname, strtab + symtab[symtab_index].st_name);
-	      goof++;
-	    }
-	}
-      if (!goof)
-      _dl_memcpy ((void *) symtab[symtab_index].st_value, (void *) symbol_addr,
-		  symtab[symtab_index].st_size);
-    }
-  return goof;
-}

+ 4 - 12
ldso/ldso/mips/elfinterp.c

@@ -129,7 +129,7 @@ unsigned long _dl_linux_resolver(unsigned long sym_index,
 	symname = strtab + sym->st_name;
 
 	new_addr = (unsigned long) _dl_find_hash(symname,
-			tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+			tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf (2, "%s: can't resolve symbol '%s'\n",
 				_dl_progname, symname);
@@ -164,14 +164,6 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 	return;
 }
 
-int _dl_parse_copy_information(struct dyn_elf *rpnt,
-	unsigned long rel_addr, unsigned long rel_size)
-{
-	/* Nothing to do */
-	return 0;
-}
-
-
 int _dl_parse_relocation_information(struct dyn_elf *xpnt,
 	unsigned long rel_addr, unsigned long rel_size)
 {
@@ -290,12 +282,12 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
 				}
 				else {
 					*got_entry = (unsigned long) _dl_find_hash(strtab +
-						sym->st_name, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+						sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 				}
 			}
 			else if (sym->st_shndx == SHN_COMMON) {
 				*got_entry = (unsigned long) _dl_find_hash(strtab +
-					sym->st_name, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+					sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 			}
 			else if (ELF32_ST_TYPE(sym->st_info) == STT_FUNC &&
 				*got_entry != sym->st_value) {
@@ -307,7 +299,7 @@ void _dl_perform_mips_global_got_relocations(struct elf_resolve *tpnt)
 			}
 			else {
 				*got_entry = (unsigned long) _dl_find_hash(strtab +
-					sym->st_name, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+					sym->st_name, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 			}
 
 			got_entry++;

+ 2 - 2
ldso/ldso/powerpc/elfinterp.c

@@ -210,7 +210,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 
 	/* Get the address of the GOT entry */
 	finaladdr = (Elf32_Addr) _dl_find_hash(symname,
-			tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+			tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!finaladdr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
 		_dl_exit(1);
@@ -269,7 +269,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 	symtab_index = ELF32_R_SYM(rpnt->r_info);
 	symname      = strtab + symtab[symtab_index].st_name;
 	if (symtab_index) {
-		symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
+		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
 							    elf_machine_type_class(reloc_type));
 		/* We want to allow undefined references to weak symbols - this might
 		 * have been intentional.  We should not be linking local symbols

+ 2 - 10
ldso/ldso/sh/elfinterp.c

@@ -149,7 +149,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 
 
 	/* Get the address of the GOT entry */
-	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
 		_dl_exit(1);
@@ -253,9 +253,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 	symname      = strtab + symtab[symtab_index].st_name;
 
 	if (symtab_index) {
-
-
-		symbol_addr = (unsigned long) _dl_find_hash(symname, scope,
+		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
 							    elf_machine_type_class(reloc_type));
 
 		/*
@@ -360,9 +358,3 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
 	return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
 }
 
-int _dl_parse_copy_information(struct dyn_elf __attribute__((unused))*rpnt,
-	unsigned long __attribute__((unused))rel_addr, unsigned long __attribute__((unused))rel_size)
-{
-	return 0;
-}
-

+ 2 - 62
ldso/ldso/sh64/elfinterp.c

@@ -190,7 +190,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 
 
 	/* Get the address of the GOT entry */
-	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+	new_addr = _dl_find_hash(symname, tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
 			    _dl_progname, symname);
@@ -305,7 +305,7 @@ static int _dl_do_reloc(struct elf_resolve *tpnt,struct dyn_elf *scope,
 	if (symtab_index) {
 		int stb;
 
-		symbol_addr = (unsigned long)_dl_find_hash(symname, scope,
+		symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
 							   elf_machine_type_class(reloc_type));
 
 		/*
@@ -445,59 +445,6 @@ static int _dl_do_lazy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
 	return 0;
 }
 
-/* This is done as a separate step, because there are cases where
-   information is first copied and later initialized.  This results in
-   the wrong information being copied.  Someone at Sun was complaining about
-   a bug in the handling of _COPY by SVr4, and this may in fact be what he
-   was talking about.  Sigh. */
-
-/* No, there are cases where the SVr4 linker fails to emit COPY relocs
-   at all */
-static int _dl_do_copy_reloc(struct elf_resolve *tpnt, struct dyn_elf *scope,
-		       ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
-{
-        int reloc_type;
-	int symtab_index;
-	unsigned long *reloc_addr;
-	unsigned long symbol_addr;
-	char *symname;
-	int goof = 0;
-	return 0; /* disable now, remove later */
-	reloc_addr = (unsigned long *)(intptr_t)
-		(tpnt->loadaddr + (unsigned long)rpnt->r_offset);
-	reloc_type = ELF32_R_TYPE(rpnt->r_info);
-
-	if (reloc_type != R_SH_COPY)
-		return 0;
-
-	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(symname, scope, ELF_RTYPE_CLASS_COPY);
-
-		if (!symbol_addr)
-			goof++;
-	}
-
-	if (!goof) {
-#ifdef __SUPPORT_LD_DEBUG__
-	        if (_dl_debug_move)
-			_dl_dprintf(_dl_debug_file,
-				    "\n%s move %x bytes from %x to %x",
-				    symname, symtab[symtab_index].st_size,
-				    symbol_addr, symtab[symtab_index].st_value);
-#endif
-
-		_dl_memcpy((char *)symtab[symtab_index].st_value,
-			   (char *)symbol_addr, symtab[symtab_index].st_size);
-	}
-
-	return goof;
-}
-
 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 	unsigned long rel_addr, unsigned long rel_size)
 {
@@ -509,10 +456,3 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
 {
 	return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
 }
-
-int _dl_parse_copy_information(struct dyn_elf *rpnt,
-	unsigned long rel_addr, unsigned long rel_size)
-{
-	return _dl_parse(rpnt->dyn, rpnt->next, rel_addr, rel_size, _dl_do_copy_reloc);
-}
-

+ 2 - 60
ldso/ldso/sparc/elfinterp.c

@@ -113,7 +113,7 @@ unsigned int _dl_linux_resolver(unsigned int reloc_entry, unsigned int * plt)
 
   /* Get the address of the GOT entry */
   new_addr = _dl_find_hash(strtab + symtab[symtab_index].st_name,
-  			tpnt->symbol_scope, ELF_RTYPE_CLASS_PLT);
+  			tpnt->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT);
   if(unlikely(!new_addr)) {
     _dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
 	       _dl_progname, strtab + symtab[symtab_index].st_name);
@@ -216,7 +216,7 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
 
       symbol_addr = (unsigned int)
 	_dl_find_hash(strtab + symtab[symtab_index].st_name,
-		      tpnt->symbol_scope, elf_machine_type_class(reloc_type));
+		      tpnt->symbol_scope, tpnt, elf_machine_type_class(reloc_type));
 
       if(!symbol_addr &&
 	 ELF32_ST_BIND(symtab [symtab_index].st_info) != STB_WEAK) {
@@ -278,61 +278,3 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
   };
   return goof;
 }
-
-
-/* This is done as a separate step, because there are cases where
-   information is first copied and later initialized.  This results in
-   the wrong information being copied.  Someone at Sun was complaining about
-   a bug in the handling of _COPY by SVr4, and this may in fact be what he
-   was talking about.  Sigh. */
-
-/* No, there are cases where the SVr4 linker fails to emit COPY relocs
-   at all */
-
-int _dl_parse_copy_information(struct dyn_elf *xpnt,
-	unsigned long rel_addr, unsigned long rel_size)
-{
-  int i;
-  char * strtab;
-  int reloc_type;
-  int goof = 0;
-  Elf32_Sym * symtab;
-  Elf32_Rela * rpnt;
-  unsigned int * reloc_addr;
-  unsigned int symbol_addr;
-  struct elf_resolve *tpnt;
-  int symtab_index;
-  /* Now parse the relocation information */
-  return 0; /* disable for now, remove later */
-  tpnt = xpnt->dyn;
-
-  rpnt = (Elf32_Rela *) (rel_addr + tpnt->loadaddr);
-
-  symtab =  (Elf32_Sym *) (tpnt->dynamic_info[DT_SYMTAB] + tpnt->loadaddr);
-  strtab = ( char *) (tpnt->dynamic_info[DT_STRTAB] + tpnt->loadaddr);
-
-  for(i=0; i< rel_size; i+= sizeof(Elf32_Rela), rpnt++){
-    reloc_addr = (int *) (tpnt->loadaddr + (int)rpnt->r_offset);
-    reloc_type = ELF32_R_TYPE(rpnt->r_info);
-    if(reloc_type != R_SPARC_COPY) continue;
-    symtab_index = ELF32_R_SYM(rpnt->r_info);
-    symbol_addr = 0;
-    if(symtab_index) {
-      symbol_addr = (unsigned int)
-	_dl_find_hash(strtab + symtab[symtab_index].st_name,
-		      xpnt->next,  ELF_RTYPE_CLASS_COPY);
-      if(!symbol_addr) {
-	_dl_dprintf(2, "%s: can't resolve symbol '%s'\n",
-		   _dl_progname, strtab + symtab[symtab_index].st_name);
-	goof++;
-      };
-    };
-    if (!goof)
-      _dl_memcpy((char *) symtab[symtab_index].st_value,
-		  (char *) symbol_addr,
-		  symtab[symtab_index].st_size);
-  };
-  return goof;
-}
-
-

+ 25 - 11
ldso/libdl/libdl.c

@@ -39,7 +39,7 @@
 /* When libdl is loaded as a shared library, we need to load in
  * and use a pile of symbols from ldso... */
 
-extern char *_dl_find_hash(const char *, struct dyn_elf *, int)
+extern char *_dl_find_hash(const char *, struct dyn_elf *, struct elf_resolve *, int)
 	__attribute__ ((__weak__));
 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
 	struct elf_resolve *, char *, int) __attribute__ ((__weak__));
@@ -136,7 +136,7 @@ void *dlopen(const char *libname, int flag)
 	struct elf_resolve *tpnt1;
 	void (*dl_brk) (void);
 	int now_flag;
-	struct init_fini_list *tmp;
+	struct init_fini_list *tmp, *runp;
 	int nlist, i;
 	struct elf_resolve **init_fini_list;
 
@@ -190,7 +190,7 @@ void *dlopen(const char *libname, int flag)
 	dyn_chain = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
 	_dl_memset(dyn_chain, 0, sizeof(struct dyn_elf));
 	dyn_chain->dyn = tpnt;
-	tpnt->rtld_flags |= RTLD_GLOBAL;
+	tpnt->rtld_flags |= (flag & RTLD_GLOBAL);
 
 	dyn_chain->next_handle = _dl_handles;
 	_dl_handles = dyn_ptr = dyn_chain;
@@ -227,7 +227,7 @@ void *dlopen(const char *libname, int flag)
 					if (!tpnt1)
 						goto oops;
 				}
-				tpnt1->rtld_flags |= RTLD_GLOBAL;
+				tpnt1->rtld_flags |= (flag & RTLD_GLOBAL);
 				dyn_ptr->next = (struct dyn_elf *) malloc(sizeof(struct dyn_elf));
 				_dl_memset (dyn_ptr->next, 0, sizeof (struct dyn_elf));
 				dyn_ptr = dyn_ptr->next;
@@ -246,6 +246,15 @@ void *dlopen(const char *libname, int flag)
 	i = 0;
 	for (tcurr = tpnt; tcurr; tcurr = tcurr->next) {
 		init_fini_list[i++] = tcurr;
+		for(runp = tcurr->init_fini; runp; runp = runp->next){
+			if (!(runp->tpnt->rtld_flags & RTLD_GLOBAL)) {
+				tmp = malloc(sizeof(struct init_fini_list));
+				tmp->tpnt = runp->tpnt;
+				tmp->next = tcurr->rtld_local;
+				tcurr->rtld_local = tmp;
+			}
+		}
+
 	}
 	/* Sort the INIT/FINI list in dependency order. */
 	for (tcurr = tpnt; tcurr; tcurr = tcurr->next) {
@@ -275,12 +284,10 @@ void *dlopen(const char *libname, int flag)
 	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);
+			runp = init_fini_list[i]->init_fini;
+			for ( ;runp; runp = runp->next)
+				printf(" %s ", runp->tpnt->libname);
 			printf("\n");
 		}
 	}
@@ -409,7 +416,7 @@ void *dlsym(void *vhandle, const char *name)
 		}
 	}
 
-	ret = _dl_find_hash((char*)name, handle, 0);
+	ret = _dl_find_hash((char*)name, handle, NULL, 0);
 
 	/*
 	 * Nothing found.
@@ -422,6 +429,7 @@ void *dlsym(void *vhandle, const char *name)
 static int do_dlclose(void *vhandle, int need_fini)
 {
 	struct dyn_elf *rpnt, *rpnt1;
+	struct init_fini_list *runp, *tmp;
 	ElfW(Phdr) *ppnt;
 	struct elf_resolve *tpnt;
 	int (*dl_elf_fini) (void);
@@ -461,7 +469,8 @@ static int do_dlclose(void *vhandle, int need_fini)
 			}
 		}
 	}
-	free(handle->init_fini.init_fini);
+	if (handle->dyn->usage_count == 1)
+		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;
@@ -475,6 +484,11 @@ static int do_dlclose(void *vhandle, int need_fini)
 					end = ppnt->p_vaddr + ppnt->p_memsz;
 			}
 			_dl_munmap((void*)tpnt->loadaddr, end);
+			/* Free elements in RTLD_LOCAL scope list */ 
+			for (runp = tpnt->rtld_local; runp; runp = tmp) {
+				tmp = runp->next;
+				free(runp);
+			}
 			/* Next, remove tpnt from the loaded_module list */
 			if (_dl_loaded_modules == tpnt) {
 				_dl_loaded_modules = tpnt->next;