OSDN Git Service

ldso: Rework global scope handling and symbol lookup mechanism
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>
Thu, 29 Jul 2010 09:35:05 +0000 (11:35 +0200)
committerCarmelo Amoroso <carmelo.amoroso@st.com>
Fri, 17 Sep 2010 14:07:25 +0000 (16:07 +0200)
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>
ldso/include/dl-defs.h
ldso/include/dl-elf.h
ldso/include/dl-hash.h
ldso/include/ldso.h
ldso/ldso/dl-elf.c
ldso/ldso/dl-hash.c
ldso/ldso/dl-startup.c
ldso/ldso/ldso.c
ldso/ldso/sh/elfinterp.c
ldso/libdl/libdl.c

index 2d6303c..cbbaa3c 100644 (file)
@@ -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
index dc4af7b..3e85864 100644 (file)
@@ -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);
 
 /*
index edef9d8..f47384c 100644 (file)
@@ -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);
index 1208892..536f7d2 100644 (file)
@@ -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>
index 2a77587..a8ccc5e 100644 (file)
@@ -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]);
                }
index 0048734..2c4571f 100644 (file)
@@ -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 */
index 2aefa6d..feffa78 100644 (file)
@@ -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);
index bb39471..ff3519f 100644 (file)
@@ -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
 
index 715eadc..d3465bc 100644 (file)
@@ -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);
 }
index 3957e84..b641fe3 100644 (file)
@@ -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);
                }
        }