[git commit] ldso: Rework global scope handling and symbol lookup mechanism

Filippo Arcidiacono filippo.arcidiacono at st.com
Fri Jul 1 07:49:47 UTC 2011


commit: http://git.uclibc.org/uClibc/commit/?id=94cc6edb78a12655c0602a246fa1cbdc8c6d0ad9
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master

Global symbol scope is implemented as a linked list of
local scope, that dynamically grows and shrinks when dlopen/
dlclose are called. Each local scope is implemented as an array
of pointer to struct elf_resolve.
This will help to detect conflict when LD_TRACE_PRELINKING option
will be implemented.

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono at st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso at st.com>
---
 ldso/include/dl-defs.h   |    2 +-
 ldso/include/dl-elf.h    |    5 ++-
 ldso/include/dl-hash.h   |   19 ++++++++--
 ldso/include/ldso.h      |    1 +
 ldso/ldso/dl-elf.c       |    9 ++---
 ldso/ldso/dl-hash.c      |   83 ++++++++++++++++++++++++---------------------
 ldso/ldso/dl-startup.c   |    2 +-
 ldso/ldso/ldso.c         |   78 ++++++++++++++++++++++++++++++++++++-------
 ldso/ldso/sh/elfinterp.c |   14 ++++----
 ldso/libdl/libdl.c       |   59 ++++++++++++++++++++++++++++++--
 10 files changed, 197 insertions(+), 75 deletions(-)

diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index 2d6303c..cbbaa3c 100644
--- a/ldso/include/dl-defs.h
+++ b/ldso/include/dl-defs.h
@@ -225,7 +225,7 @@ typedef struct {
 /* Similar to DL_LOADADDR_UNMAP, but used for libraries that have been
    dlopen()ed successfully, when they're dlclose()d.  */
 #ifndef DL_LIB_UNMAP
-# define DL_LIB_UNMAP(LIB, LEN) (DL_LOADADDR_UNMAP ((LIB)->loadaddr, (LEN)))
+# define DL_LIB_UNMAP(LIB, LEN) (DL_LOADADDR_UNMAP ((LIB)->mapaddr, (LEN)))
 #endif
 
 /* Define this to verify that a library named LIBNAME, whose ELF
diff --git a/ldso/include/dl-elf.h b/ldso/include/dl-elf.h
index dc4af7b..3e85864 100644
--- a/ldso/include/dl-elf.h
+++ b/ldso/include/dl-elf.h
@@ -15,6 +15,7 @@
 /* Forward declarations for stuff defined in ld_hash.h */
 struct dyn_elf;
 struct elf_resolve;
+struct r_scope_elem;
 
 #include <dl-defs.h>
 #ifdef __LDSO_CACHE_SUPPORT__
@@ -30,7 +31,7 @@ static __inline__ void _dl_unmap_cache(void) { }
 extern void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 	unsigned long rel_addr, unsigned long rel_size);
 extern int _dl_parse_relocation_information(struct dyn_elf *rpnt,
-	unsigned long rel_addr, unsigned long rel_size);
+	struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size);
 extern struct elf_resolve * _dl_load_shared_library(int secure,
 	struct dyn_elf **rpnt, struct elf_resolve *tpnt, char *full_libname,
 	int trace_loaded_objects);
@@ -39,7 +40,7 @@ extern struct elf_resolve * _dl_load_elf_shared_library(int secure,
 extern struct elf_resolve *_dl_check_if_named_library_is_loaded(const char *full_libname,
 	int trace_loaded_objects);
 extern int _dl_linux_resolve(void);
-extern int _dl_fixup(struct dyn_elf *rpnt, int flag);
+extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int flag);
 extern void _dl_protect_relro (struct elf_resolve *l);
 
 /*
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index edef9d8..f47384c 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -25,6 +25,15 @@ struct dyn_elf {
   struct dyn_elf * prev;
 };
 
+
+/* Structure to describe a single list of scope elements.  The lookup
+   functions get passed an array of pointers to such structures.  */
+struct r_scope_elem {
+  struct elf_resolve **r_list; /* Array of maps for the scope.  */
+  unsigned int r_nlist;        /* Number of entries in the scope.  */
+  struct r_scope_elem *next;
+};
+
 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. */
@@ -65,7 +74,8 @@ struct elf_resolve {
   ElfW(Addr) l_entry;
 #endif
   enum {elf_lib, elf_executable,program_interpreter, loaded_file} libtype;
-  struct dyn_elf * symbol_scope;
+  /* This is the local scope of the shared object */
+  struct r_scope_elem symbol_scope;
   unsigned short usage_count;
   unsigned short int init_flag;
   unsigned long rtld_flags; /* RTLD_GLOBAL, RTLD_NOW etc. */
@@ -132,6 +142,7 @@ struct elf_resolve {
 #define INIT_FUNCS_CALLED   0x000004
 #define FINI_FUNCS_CALLED   0x000008
 #define DL_OPENED	    0x000010
+#define DL_RESERVED	    0x000020
 
 extern struct dyn_elf     * _dl_symbol_tables;
 extern struct elf_resolve * _dl_loaded_modules;
@@ -145,15 +156,15 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
 #if !((defined(USE_TLS) && USE_TLS) || defined __FDPIC__)
 # define _dl_lookup_hash(n, r, m, c, t) _dl_lookup_hash(n, r, m, c)
 #endif
-extern char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt,
+extern char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope,
 	struct elf_resolve *mytpnt, int type_class,
 	struct elf_resolve **tpntp);
 
-static __always_inline char *_dl_find_hash(const char *name, struct dyn_elf *rpnt,
+static __always_inline char *_dl_find_hash(const char *name, struct r_scope_elem *scope,
 					struct elf_resolve *mytpnt, int type_class,
 					struct elf_resolve **tpntp)
 {
-	return _dl_lookup_hash(name, rpnt, mytpnt, type_class, tpntp);
+	return _dl_lookup_hash(name, scope, mytpnt, type_class, tpntp);
 }
 
 extern int _dl_linux_dynamic_link(void);
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 1208892..536f7d2 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -27,6 +27,7 @@
 /* Pull in compiler and arch stuff */
 #include <stdlib.h>
 #include <stdarg.h>
+#include <stddef.h> /* for ptrdiff_t */
 #define _FCNTL_H
 #include <bits/fcntl.h>
 #include <bits/wordsize.h>
diff --git a/ldso/ldso/dl-elf.c b/ldso/ldso/dl-elf.c
index 2a77587..a8ccc5e 100644
--- a/ldso/ldso/dl-elf.c
+++ b/ldso/ldso/dl-elf.c
@@ -814,7 +814,6 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 	}
 #endif
 	(*rpnt)->dyn = tpnt;
-	tpnt->symbol_scope = _dl_symbol_tables;
 	tpnt->usage_count++;
 #ifdef __LDSO_STANDALONE_SUPPORT__
 	tpnt->libtype = (epnt->e_type == ET_DYN) ? elf_lib : elf_executable;
@@ -846,7 +845,7 @@ struct elf_resolve *_dl_load_elf_shared_library(int secure,
 }
 
 /* now_flag must be RTLD_NOW or zero */
-int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
+int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int now_flag)
 {
 	int goof = 0;
 	struct elf_resolve *tpnt;
@@ -854,7 +853,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
 	ElfW(Addr) reloc_addr;
 
 	if (rpnt->next)
-		goof = _dl_fixup(rpnt->next, now_flag);
+		goof = _dl_fixup(rpnt->next, scope, now_flag);
 	if (goof)
 		return goof;
 	tpnt = rpnt->dyn;
@@ -884,7 +883,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
 			elf_machine_relative(tpnt->loadaddr, reloc_addr, relative_count);
 			reloc_addr += relative_count * sizeof(ELF_RELOC);
 		}
-		goof += _dl_parse_relocation_information(rpnt,
+		goof += _dl_parse_relocation_information(rpnt, scope,
 				reloc_addr,
 				reloc_size);
 		tpnt->init_flag |= RELOCS_DONE;
@@ -900,7 +899,7 @@ int _dl_fixup(struct dyn_elf *rpnt, int now_flag)
 					tpnt->dynamic_info[DT_JMPREL],
 					tpnt->dynamic_info [DT_PLTRELSZ]);
 		} else {
-			goof += _dl_parse_relocation_information(rpnt,
+			goof += _dl_parse_relocation_information(rpnt, scope,
 					tpnt->dynamic_info[DT_JMPREL],
 					tpnt->dynamic_info[DT_PLTRELSZ]);
 		}
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index 0048734..2c4571f 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -268,70 +268,75 @@ _dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long
  * 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_lookup_hash(const char *name, struct dyn_elf *rpnt, struct elf_resolve *mytpnt,
+char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
 	int type_class, struct elf_resolve **tpntp)
 {
 	struct elf_resolve *tpnt = NULL;
 	ElfW(Sym) *symtab;
+	int i = 0;
 
 	unsigned long elf_hash_number = 0xffffffff;
 	const ElfW(Sym) *sym = NULL;
 
 	char *weak_result = NULL;
+	struct r_scope_elem *loop_scope;
 
 #ifdef __LDSO_GNU_HASH_SUPPORT__
 	unsigned long gnu_hash_number = _dl_gnu_hash((const unsigned char *)name);
 #endif
 
-	for (; rpnt; rpnt = rpnt->next) {
-		tpnt = rpnt->dyn;
-
-		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;
+	for (loop_scope = scope; loop_scope && !sym; loop_scope = loop_scope->next) {
+		for (i = 0; i < loop_scope->r_nlist; i++) {
+			tpnt = loop_scope->r_list[i];
+
+			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;
 				}
-				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;
+			/* Don't search the executable when resolving a copy reloc. */
+			if ((type_class &  ELF_RTYPE_CLASS_COPY) && tpnt->libtype == elf_executable)
+				continue;
 
-		/* If the hash table is empty there is nothing to do here.  */
-		if (tpnt->nbucket == 0)
-			continue;
+			/* If the hash table is empty there is nothing to do here.  */
+			if (tpnt->nbucket == 0)
+				continue;
 
-		symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
+			symtab = (ElfW(Sym) *) (intptr_t) (tpnt->dynamic_info[DT_SYMTAB]);
 
 #ifdef __LDSO_GNU_HASH_SUPPORT__
-		/* Prefer GNU hash style, if any */
-		if (tpnt->l_gnu_bitmask) {
-			sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class);
-			if (sym != NULL)
-				/* If sym has been found, do not search further */
-				break;
-		} else {
+			/* Prefer GNU hash style, if any */
+			if (tpnt->l_gnu_bitmask) {
+				sym = _dl_lookup_gnu_hash(tpnt, symtab, gnu_hash_number, name, type_class);
+				if (sym != NULL)
+					/* If sym has been found, do not search further */
+					break;
+			} else {
 #endif
-		/* Use the old SysV-style hash table */
+				/* Use the old SysV-style hash table */
 
-		/* Calculate the old sysv hash number only once */
-		if (elf_hash_number == 0xffffffff)
-			elf_hash_number = _dl_elf_hash((const unsigned char *)name);
+				/* Calculate the old sysv hash number only once */
+				if (elf_hash_number == 0xffffffff)
+					elf_hash_number = _dl_elf_hash((const unsigned char *)name);
 
-		sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class);
-		if (sym != NULL)
-			break;
+				sym = _dl_lookup_sysv_hash(tpnt, symtab, elf_hash_number, name, type_class);
+				if (sym != NULL)
+					/* If sym has been found, do not search further */
+					break;
 #ifdef __LDSO_GNU_HASH_SUPPORT__
-		}
+			}
 #endif
-	} /* end of for (; rpnt; rpnt = rpnt->next) { */
+		} /* End of inner for */
+	}
 
 	if (sym) {
 		/* At this point we have found the requested symbol, do binding */
diff --git a/ldso/ldso/dl-startup.c b/ldso/ldso/dl-startup.c
index 2aefa6d..feffa78 100644
--- a/ldso/ldso/dl-startup.c
+++ b/ldso/ldso/dl-startup.c
@@ -192,7 +192,7 @@ DL_START(unsigned long args)
 	DL_BOOT_COMPUTE_GOT(got);
 
 	/* Now, finally, fix up the location of the dynamic stuff */
-	DL_BOOT_COMPUTE_DYN(dpnt, got, load_addr);
+	DL_BOOT_COMPUTE_DYN(dpnt, got, (DL_LOADADDR_TYPE)header);
 
 	SEND_EARLY_STDERR_DEBUG("First Dynamic section entry=");
 	SEND_ADDRESS_STDERR_DEBUG(dpnt, 1);
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index bb39471..ff3519f 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -107,6 +107,7 @@ static unsigned char *_dl_malloc_addr = NULL;	/* Lets _dl_malloc use the already
 static unsigned char *_dl_mmap_zero   = NULL;	/* Also used by _dl_malloc */
 
 static struct elf_resolve **init_fini_list;
+static struct elf_resolve **scope_elem_list;
 static unsigned int nlist; /* # items in init_fini_list */
 extern void _start(void);
 
@@ -284,6 +285,21 @@ static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
 	}
 }
 
+static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
+										struct elf_resolve *map)
+{
+	struct elf_resolve **p = list;
+	struct init_fini_list *q;
+
+	*p++ = map;
+	map->init_flag |= DL_RESERVED;
+	if (map->init_fini)
+		for (q = map->init_fini; q; q = q->next)
+			if (! (q->tpnt->init_flag & DL_RESERVED))
+				p += _dl_build_local_scope (p, q->tpnt);
+	return p - list;
+}
+
 void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 			  ElfW(auxv_t) auxvt[AT_EGID + 1], char **envp, char **argv
 			  DL_GET_READY_TO_RUN_EXTRA_PARMS)
@@ -292,7 +308,7 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 	ElfW(Phdr) *ppnt;
 	ElfW(Dyn) *dpnt;
 	char *lpntstr;
-	unsigned int i;
+	unsigned int i, cnt, k, nscope_elem;
 	int unlazy = 0, trace_loaded_objects = 0;
 	struct dyn_elf *rpnt;
 	struct elf_resolve *tcurr;
@@ -304,6 +320,9 @@ void *_dl_get_ready_to_run(struct elf_resolve *tpnt, DL_LOADADDR_TYPE load_addr,
 	unsigned long *_dl_envp;		/* The environment address */
 	ElfW(Addr) relro_addr = 0;
 	size_t relro_size = 0;
+	struct r_scope_elem *global_scope;
+	struct elf_resolve **local_scope;
+
 	struct stat st;
 #if defined(USE_TLS) && USE_TLS
 	void *tcbp = NULL;
@@ -576,7 +595,6 @@ of this helper program; chances are you did not intend to run this program.\n\
 			app_tpnt->mapaddr = app_mapaddr;
 			app_tpnt->rtld_flags = unlazy | RTLD_GLOBAL;
 			app_tpnt->usage_count++;
-			app_tpnt->symbol_scope = _dl_symbol_tables;
 			lpnt = (unsigned long *) (app_tpnt->dynamic_info[DT_PLTGOT]);
 #ifdef ALLOW_ZERO_PLTGOT
 			if (lpnt)
@@ -637,11 +655,11 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 * case the executable is actually an ET_DYN object.
 	 */
 	if (app_tpnt->l_tls_initimage != NULL) {
+		unsigned int tmp = (unsigned int) app_tpnt->l_tls_initimage;
 		app_tpnt->l_tls_initimage =
 			(char *) app_tpnt->l_tls_initimage + app_tpnt->loadaddr;
 		_dl_debug_early("Relocated TLS initial image from %x to %x (size = %x)\n",
-			(unsigned int)app_tpnt->l_tls_initimage,
-			app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size);
+			tmp, app_tpnt->l_tls_initimage, app_tpnt->l_tls_initimage_size);
 	}
 #endif
 
@@ -926,6 +944,9 @@ of this helper program; chances are you did not intend to run this program.\n\
 	}
 	_dl_unmap_cache();
 
+	/* Keep track of the number of elements in the global scope */
+	nscope_elem = nlist;
+
 	--nlist; /* Exclude the application. */
 	init_fini_list = _dl_malloc(nlist * sizeof(struct elf_resolve *));
 	i = 0;
@@ -1002,7 +1023,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 		}
 		tpnt->libtype = program_interpreter;
 		tpnt->usage_count++;
-		tpnt->symbol_scope = _dl_symbol_tables;
+		nscope_elem++;
 		if (rpnt) {
 			rpnt->next = _dl_zalloc(sizeof(struct dyn_elf));
 			rpnt->next->prev = rpnt;
@@ -1012,6 +1033,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 		}
 		rpnt->dyn = tpnt;
 		tpnt->rtld_flags = RTLD_NOW | RTLD_GLOBAL; /* Must not be LAZY */
+
 #ifdef RERELOCATE_LDSO
 		/* Only rerelocate functions for now. */
 		tpnt->init_flag = RELOCS_DONE;
@@ -1026,6 +1048,38 @@ of this helper program; chances are you did not intend to run this program.\n\
 		tpnt = NULL;
 	}
 
+	/*
+	 * Allocate the global scope array.
+	 */
+	scope_elem_list = (struct elf_resolve **) _dl_malloc(nscope_elem * sizeof(struct elf_resolve *));
+
+	for (i = 0, tcurr = _dl_loaded_modules; tcurr; tcurr = tcurr->next)
+		scope_elem_list[i++] = tcurr;
+
+	_dl_loaded_modules->symbol_scope.r_list = scope_elem_list;
+	_dl_loaded_modules->symbol_scope.r_nlist = nscope_elem;
+	/*
+	 * The symbol scope of the application, that is the first entry of the
+	 * _dl_loaded_modules list, is just the global scope to be used for the
+	 * symbol lookup.
+	 */
+	global_scope = &_dl_loaded_modules->symbol_scope;
+
+	/* Build the local scope for the each loaded modules. */
+	local_scope = _dl_malloc(nscope_elem * sizeof(struct elf_resolve *));
+	i = 1;
+	for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
+		cnt = _dl_build_local_scope(local_scope, scope_elem_list[i++]);
+		tcurr->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
+		tcurr->symbol_scope.r_nlist = cnt;
+		_dl_memcpy (tcurr->symbol_scope.r_list, local_scope, cnt * sizeof (struct elf_resolve *));
+		/* Restoring the init_flag.*/
+		for (k = 1; k < nscope_elem; k++)
+			scope_elem_list[k]->init_flag &= ~DL_RESERVED;
+	}
+
+	_dl_free(local_scope);
+
 #ifdef __LDSO_LDD_SUPPORT__
 	/* End of the line for ldd.... */
 	if (trace_loaded_objects) {
@@ -1081,7 +1135,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 * order so that COPY directives work correctly.
 	 */
 	if (_dl_symbol_tables)
-		if (_dl_fixup(_dl_symbol_tables, unlazy))
+		if (_dl_fixup(_dl_symbol_tables, global_scope, unlazy))
 			_dl_exit(-1);
 
 	for (tpnt = _dl_loaded_modules; tpnt; tpnt = tpnt->next) {
@@ -1118,7 +1172,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 * ld.so.1, so we have to look up each symbol individually.
 	 */
 
-	_dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", _dl_symbol_tables, NULL, 0, NULL);
+	_dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", global_scope, NULL, 0, NULL);
 	if (_dl_envp)
 		*_dl_envp = (unsigned long) envp;
 
@@ -1174,21 +1228,21 @@ of this helper program; chances are you did not intend to run this program.\n\
 
 	/* 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(__C_SYMBOL_PREFIX__ "malloc",
-			_dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+			global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 #if defined(USE_TLS) && USE_TLS
 	/* Find the real functions and make ldso functions use them from now on */
 	_dl_calloc_function = (void* (*)(size_t, size_t)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	_dl_realloc_function = (void* (*)(void *, size_t)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	_dl_free_function = (void (*)(void *)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "free", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "free", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	_dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", _dl_symbol_tables, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 #endif
 
diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c
index 715eadc..d3465bc 100644
--- a/ldso/ldso/sh/elfinterp.c
+++ b/ldso/ldso/sh/elfinterp.c
@@ -69,7 +69,7 @@ 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, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
+	new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
 
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
@@ -95,9 +95,9 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 
 
 static int
-_dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_parse(struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	  unsigned long rel_addr, unsigned long rel_size,
-	  int (*reloc_fnc) (struct elf_resolve *tpnt, struct dyn_elf *scope,
+	  int (*reloc_fnc) (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 			    ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab))
 {
 	unsigned int i;
@@ -148,7 +148,7 @@ _dl_parse(struct elf_resolve *tpnt, struct dyn_elf *scope,
 
 
 static int
-_dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
+_dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	      ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
 {
 	int reloc_type;
@@ -251,7 +251,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct dyn_elf *scope,
 
 
 static int
-_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct dyn_elf *scope,
+_dl_do_lazy_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 		   ELF_RELOC *rpnt, Elf32_Sym *symtab, char *strtab)
 {
 	int reloc_type;
@@ -293,7 +293,7 @@ void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
 }
 
 int _dl_parse_relocation_information(struct dyn_elf *rpnt,
-	unsigned long rel_addr, unsigned long rel_size)
+	struct r_scope_elem *scope, unsigned long rel_addr, unsigned long rel_size)
 {
-	return _dl_parse(rpnt->dyn, rpnt->dyn->symbol_scope, rel_addr, rel_size, _dl_do_reloc);
+	return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
 }
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 3957e84..b641fe3 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -55,7 +55,7 @@ extern struct link_map *_dl_update_slotinfo(unsigned long int req_modid);
 
 extern struct elf_resolve * _dl_load_shared_library(int, struct dyn_elf **,
 	struct elf_resolve *, char *, int);
-extern int _dl_fixup(struct dyn_elf *rpnt, int lazy);
+extern int _dl_fixup(struct dyn_elf *rpnt, struct r_scope_elem *scope, int lazy);
 extern void _dl_protect_relro(struct elf_resolve * tpnt);
 extern int _dl_errno;
 extern struct dyn_elf *_dl_symbol_tables;
@@ -271,6 +271,21 @@ void dl_cleanup(void)
 	}
 }
 
+static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
+	struct elf_resolve *map)
+{
+	struct elf_resolve **p = list;
+	struct init_fini_list *q;
+
+	*p++ = map;
+	map->init_flag |= DL_RESERVED;
+	if (map->init_fini)
+		for (q = map->init_fini; q; q = q->next)
+			if (! (q->tpnt->init_flag & DL_RESERVED))
+				p += _dl_build_local_scope (p, q->tpnt);
+	return p - list;
+}
+
 void *dlopen(const char *libname, int flag)
 {
 	struct elf_resolve *tpnt, *tfrom;
@@ -283,6 +298,8 @@ void *dlopen(const char *libname, int flag)
 	unsigned int nlist, i;
 	struct elf_resolve **init_fini_list;
 	static bool _dl_init;
+	struct elf_resolve **local_scope;
+	struct r_scope_elem *ls;
 #if defined(USE_TLS) && USE_TLS
 	bool any_tls = false;
 #endif
@@ -458,6 +475,23 @@ void *dlopen(const char *libname, int flag)
 		}
 
 	}
+	/* Build the local scope for the dynamically loaded modules. */
+	local_scope = _dl_malloc(nlist * sizeof(struct elf_resolve *)); /* Could it allocated on stack? */
+	for (i = 0; i < nlist; i++)
+		if (init_fini_list[i]->symbol_scope.r_nlist == 0) {
+			int k, cnt;
+			cnt = _dl_build_local_scope(local_scope, init_fini_list[i]);
+			init_fini_list[i]->symbol_scope.r_list = _dl_malloc(cnt * sizeof(struct elf_resolve *));
+			init_fini_list[i]->symbol_scope.r_nlist = cnt;
+			_dl_memcpy (init_fini_list[i]->symbol_scope.r_list, local_scope,
+					cnt * sizeof (struct elf_resolve *));
+			/* Restoring the init_flag.*/
+			for (k = 0; k < nlist; k++)
+				init_fini_list[k]->init_flag &= ~DL_RESERVED;
+		}
+
+	_dl_free(local_scope);
+
 	/* Sort the INIT/FINI list in dependency order. */
 	for (runp2 = dep_list; runp2; runp2 = runp2->next) {
 		unsigned int j, k;
@@ -505,8 +539,13 @@ void *dlopen(const char *libname, int flag)
 	 */
 	_dl_perform_mips_global_got_relocations(tpnt, !now_flag);
 #endif
+	/* Get the tail of the list */
+	for (ls = &_dl_loaded_modules->symbol_scope; ls && ls->next; ls = ls->next);
 
-	if (_dl_fixup(dyn_chain, now_flag))
+	/* Extend the global scope by adding the local scope of the dlopened DSO. */
+	ls->next = &dyn_chain->dyn->symbol_scope;
+
+	if (_dl_fixup(dyn_chain, &_dl_loaded_modules->symbol_scope, now_flag))
 		goto oops;
 
 	if (relro_ptr) {
@@ -667,7 +706,7 @@ void *dlsym(void *vhandle, const char *name)
 	tpnt = NULL;
 	if (handle == _dl_symbol_tables)
 		tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
-	ret = _dl_find_hash(name2, handle, NULL, 0, &tls_tpnt);
+	ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, NULL, 0, &tls_tpnt);
 
 #if defined(USE_TLS) && USE_TLS && defined SHARED
 	if (tls_tpnt) {
@@ -708,6 +747,7 @@ static int do_dlclose(void *vhandle, int need_fini)
 	struct dyn_elf *handle;
 	unsigned int end;
 	unsigned int i, j;
+	struct r_scope_elem *ls;
 #if defined(USE_TLS) && USE_TLS
 	bool any_tls = false;
 	size_t tls_free_start = NO_TLS_OFFSET;
@@ -873,7 +913,7 @@ static int do_dlclose(void *vhandle, int need_fini)
 			}
 #endif
 
-			DL_LIB_UNMAP (tpnt, end);
+			DL_LIB_UNMAP (tpnt, end - tpnt->mapaddr);
 			/* Free elements in RTLD_LOCAL scope list */
 			for (runp = tpnt->rtld_local; runp; runp = tmp) {
 				tmp = runp->next;
@@ -897,6 +937,16 @@ static int do_dlclose(void *vhandle, int need_fini)
 				}
 			}
 
+			if (handle->dyn == tpnt) {
+				/* Unlink the local scope from global one */
+				for (ls = &_dl_loaded_modules->symbol_scope; ls; ls = ls->next)
+					if (ls->next->r_list[0] == tpnt) {
+						_dl_if_debug_print("removing symbol_scope: %s\n", tpnt->libname);
+						break;
+					}
+				ls->next = ls->next->next;
+			}
+
 			/* Next, remove tpnt from the global symbol table list */
 			if (_dl_symbol_tables) {
 				if (_dl_symbol_tables->dyn == tpnt) {
@@ -918,6 +968,7 @@ static int do_dlclose(void *vhandle, int need_fini)
 				}
 			}
 			free(tpnt->libname);
+			free(tpnt->symbol_scope.r_list);
 			free(tpnt);
 		}
 	}
-- 
1.7.3.4



More information about the uClibc-cvs mailing list