summaryrefslogtreecommitdiff
path: root/ldso
diff options
context:
space:
mode:
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>2010-07-29 11:35:05 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2010-09-17 16:07:25 +0200
commit94cc6edb78a12655c0602a246fa1cbdc8c6d0ad9 (patch)
tree4dcffeee2396c0cd7d7b30f5a493c31ad7e171ad /ldso
parent637e2b2440f69e22932edd71bd2f0b1210dc32ea (diff)
ldso: Rework global scope handling and symbol lookup mechanism
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@st.com> Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
Diffstat (limited to 'ldso')
-rw-r--r--ldso/include/dl-defs.h2
-rw-r--r--ldso/include/dl-elf.h5
-rw-r--r--ldso/include/dl-hash.h19
-rw-r--r--ldso/include/ldso.h1
-rw-r--r--ldso/ldso/dl-elf.c9
-rw-r--r--ldso/ldso/dl-hash.c83
-rw-r--r--ldso/ldso/dl-startup.c2
-rw-r--r--ldso/ldso/ldso.c78
-rw-r--r--ldso/ldso/sh/elfinterp.c14
-rw-r--r--ldso/libdl/libdl.c59
10 files changed, 197 insertions, 75 deletions
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index 2d6303cfe..cbbaa3cea 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 dc4af7bce..3e8586444 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 edef9d81b..f47384c31 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 120889216..536f7d266 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 2a77587db..a8ccc5e91 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 0048734ba..2c4571f20 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 2aefa6d74..feffa787b 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 bb394714f..ff3519f7c 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 715eadc15..d3465bcd5 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 3957e846f..b641fe366 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);
}
}