OSDN Git Service

ldso: Fix loadaddr and mappaddr when prelink support is enabled.
[uclinux-h8/uClibc.git] / ldso / ldso / dl-hash.c
index a251aaf..bb4c56b 100644 (file)
@@ -95,17 +95,18 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
        struct elf_resolve *tpnt;
        int i;
 
-       if (!_dl_loaded_modules) {
-               tpnt = _dl_loaded_modules = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
-               _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
-       } else {
-               tpnt = _dl_loaded_modules;
-               while (tpnt->next)
-                       tpnt = tpnt->next;
-               tpnt->next = (struct elf_resolve *) _dl_malloc(sizeof(struct elf_resolve));
-               _dl_memset(tpnt->next, 0, sizeof(struct elf_resolve));
-               tpnt->next->prev = tpnt;
-               tpnt = tpnt->next;
+       tpnt = _dl_malloc(sizeof(struct elf_resolve));
+       _dl_memset(tpnt, 0, sizeof(struct elf_resolve));
+
+       if (!_dl_loaded_modules)
+               _dl_loaded_modules = tpnt;
+       else {
+               struct elf_resolve *t = _dl_loaded_modules;
+               while (t->next)
+                       t = t->next;
+               t->next = tpnt;
+               t->next->prev = t;
+               tpnt = t->next;
        }
 
        tpnt->next = NULL;
@@ -145,7 +146,6 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
                tpnt->chains = hash_addr;
        }
        tpnt->loadaddr = loadaddr;
-       tpnt->mapaddr = DL_RELOC_ADDR(loadaddr, 0);
        for (i = 0; i < DYNAMIC_SIZE; i++)
                tpnt->dynamic_info[i] = dynamic_info[i];
        return tpnt;
@@ -156,15 +156,26 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
 static __attribute_noinline__ const ElfW(Sym) *
 check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int type_class)
 {
+
+#if defined(USE_TLS) && USE_TLS
+       if ((sym->st_value == 0 && (ELF_ST_TYPE(sym->st_info) != STT_TLS))
+                     || (type_class & (sym->st_shndx == SHN_UNDEF)))
+               /* No value or undefined symbol itself */
+               return NULL;
+
+       if (ELF_ST_TYPE(sym->st_info) > STT_FUNC
+               && ELF_ST_TYPE(sym->st_info) != STT_COMMON
+               && ELF_ST_TYPE(sym->st_info) != STT_TLS)
+               /* Ignore all but STT_NOTYPE, STT_OBJECT, STT_FUNC and STT_COMMON
+                * entries (and STT_TLS if TLS is supported) since these
+                * are no code/data definitions.
+                */
+               return NULL;
+#else
        if (type_class & (sym->st_shndx == SHN_UNDEF))
                /* undefined symbol itself */
                return NULL;
 
-#ifdef __mips__
-    if (sym->st_shndx == SHN_UNDEF && !(sym->st_other & STO_MIPS_PLT))
-        return NULL;
-#endif
-
        if (sym->st_value == 0)
                /* No value */
                return NULL;
@@ -176,7 +187,7 @@ check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int typ
                 * code/data definitions
                 */
                return NULL;
-
+#endif
        if (_dl_strcmp(strtab + sym->st_name, undef_name) != 0)
                return NULL;
 
@@ -256,87 +267,98 @@ _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, int type_class
-#ifdef __FDPIC__
-                     , struct elf_resolve **tpntp
-#endif
-                     )
+char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
+       struct sym_val *symbol, 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;
 
-       const ElfW(Sym) *weak_sym = 0;
-       struct elf_resolve *weak_tpnt = 0;
+       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) {
+               if (symbol) {
+                       symbol->s = sym;
+                       symbol->m = tpnt;
+               }
                /* At this point we have found the requested symbol, do binding */
+#if defined(USE_TLS) && USE_TLS
+               if (ELF_ST_TYPE(sym->st_info) == STT_TLS) {
+                       _dl_assert(tpntp != NULL);
+                       *tpntp = tpnt;
+
+                       return (char *)sym->st_value;
+               }
+#endif
+
                switch (ELF_ST_BIND(sym->st_info)) {
                        case STB_WEAK:
 #if 0
-/* Perhaps we should support old style weak symbol handling
- * per what glibc does when you export LD_DYNAMIC_WEAK */
-                               if (!weak_sym) {
-                                       weak_tpnt = tpnt;
-                                       weak_sym = sym;
-                               }
+       /* Perhaps we should support old style weak symbol handling
+       * per what glibc does when you export LD_DYNAMIC_WEAK */
+                               if (!weak_result)
+                                       weak_result = (char *)DL_FIND_HASH_VALUE(tpnt, type_class, sym);
                                break;
 #endif
                        case STB_GLOBAL:
@@ -344,21 +366,14 @@ char *_dl_lookup_hash(const char *name, struct dyn_elf *rpnt,
                                if (tpntp)
                                        *tpntp = tpnt;
 #endif
-                               return (char *) DL_FIND_HASH_VALUE (tpnt, type_class, sym);
+                               return (char *)DL_FIND_HASH_VALUE(tpnt, type_class, sym);
                        default:        /* Local symbols not handled here */
                                break;
                }
        }
-       if (weak_sym) {
-#ifdef __FDPIC__
-               if (tpntp)
-                       *tpntp = weak_tpnt;
-#endif
-               return (char *) DL_FIND_HASH_VALUE (weak_tpnt, type_class, weak_sym);
-       }
 #ifdef __FDPIC__
        if (tpntp)
-               *tpntp = NULL;
+               *tpntp = tpnt;
 #endif
-       return NULL;
+       return weak_result;
 }