OSDN Git Service

avr32: common do_rem is good for it
[uclinux-h8/uClibc.git] / ldso / ldso / dl-hash.c
index 2a39335..2c659dc 100644 (file)
 
 
 /* Various symbol table handling functions, including symbol lookup */
-
-/*
- * This is the start of the linked list that describes all of the files present
- * in the system with pointers to all of the symbol, string, and hash tables,
- * as well as all of the other good stuff in the binary.
- */
-struct elf_resolve *_dl_loaded_modules = NULL;
-
 /*
  * This is the list of modules that are loaded when the image is first
  * started.  As we add more via dlopen, they get added into other
@@ -103,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;
@@ -122,6 +115,15 @@ struct elf_resolve *_dl_add_elf_hash_table(const char *libname,
        tpnt->dynamic_addr = (ElfW(Dyn) *)dynamic_addr;
        tpnt->libtype = loaded_file;
 
+#ifdef __DSBT__
+       if (dynamic_info[DT_DSBT_BASE_IDX] != 0)
+               tpnt->dsbt_table = (void *)dynamic_info[DT_DSBT_BASE_IDX];
+       if (dynamic_info[DT_DSBT_SIZE_IDX] != 0)
+               tpnt->dsbt_size = dynamic_info[DT_DSBT_SIZE_IDX];
+       if (dynamic_info[DT_DSBT_INDEX_IDX] != 0)
+               tpnt->dsbt_index = dynamic_info[DT_DSBT_INDEX_IDX];
+#endif /* __DSBT__ */
+
 #ifdef __LDSO_GNU_HASH_SUPPORT__
        if (dynamic_info[DT_GNU_HASH_IDX] != 0) {
                Elf32_Word *hash32 = (Elf_Symndx*)dynamic_info[DT_GNU_HASH_IDX];
@@ -153,7 +155,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;
@@ -164,6 +165,22 @@ 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;
@@ -179,7 +196,11 @@ check_match (const ElfW(Sym) *sym, char *strtab, const char* undef_name, int typ
                 * code/data definitions
                 */
                return NULL;
-
+#endif
+#ifdef ARCH_SKIP_RELOC
+       if (ARCH_SKIP_RELOC(type_class, sym))
+               return NULL;
+#endif
        if (_dl_strcmp(strtab + sym->st_name, undef_name) != 0)
                return NULL;
 
@@ -259,109 +280,116 @@ _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_find_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
+       int type_class, struct symbol_ref *sym_ref)
 {
        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;
+       if ((sym_ref) && (sym_ref->sym) && (ELF32_ST_VISIBILITY(sym_ref->sym->st_other) == STV_PROTECTED)) {
+                       sym = sym_ref->sym;
+               if (mytpnt)
+                       tpnt = mytpnt;
+       } else
+       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 (sym_ref) {
+                       sym_ref->sym = sym;
+                       sym_ref->tpnt = 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(sym_ref != NULL);
+                       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:
 #ifdef __FDPIC__
-                               if (tpntp)
-                                       *tpntp = tpnt;
+                       if (sym_ref)
+                               sym_ref->tpnt = 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;
+       if (sym_ref)
+               sym_ref->tpnt = tpnt;
 #endif
-               return (char *) DL_FIND_HASH_VALUE (weak_tpnt, type_class, weak_sym);
-       }
-#ifdef __FDPIC__
-       if (tpntp)
-               *tpntp = NULL;
-#endif
-       return NULL;
+       return weak_result;
 }