OSDN Git Service

ldso: Fix loadaddr and mappaddr when prelink support is enabled.
[uclinux-h8/uClibc.git] / ldso / ldso / dl-hash.c
index 5f90a54..bb4c56b 100644 (file)
@@ -146,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;
@@ -158,7 +157,7 @@ static __attribute_noinline__ const ElfW(Sym) *
 check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int type_class)
 {
 
-#if USE_TLS
+#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 */
@@ -268,77 +267,86 @@ _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, struct elf_resolve **tpntp)
+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;
 
        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 USE_TLS
+#if defined(USE_TLS) && USE_TLS
                if (ELF_ST_TYPE(sym->st_info) == STT_TLS) {
-                       _dl_assert(tls_tpnt != NULL);
-                       *tls_tpnt = tpnt;
+                       _dl_assert(tpntp != NULL);
+                       *tpntp = tpnt;
 
                        return (char *)sym->st_value;
                }