diff options
-rw-r--r-- | trunk/ChangeLog.cross | 26 | ||||
-rw-r--r-- | trunk/src/ld-do-lookup.h | 14 | ||||
-rw-r--r-- | trunk/src/ld-libs.c | 20 | ||||
-rw-r--r-- | trunk/src/ld-libs.h | 4 | ||||
-rw-r--r-- | trunk/src/ld-lookup.c | 126 | ||||
-rw-r--r-- | trunk/src/prelink.h | 7 |
6 files changed, 167 insertions, 30 deletions
diff --git a/trunk/ChangeLog.cross b/trunk/ChangeLog.cross index 880f7b9..7e5d2e3 100644 --- a/trunk/ChangeLog.cross +++ b/trunk/ChangeLog.cross @@ -1,6 +1,32 @@ 2009-04-23 Maciej W. Rozycki <macro@codesourcery.com> Issue #5165 + * src/ld-lookup.c (rtld_elf_hash): Handle an initial NULL + character correctly. Reformat for consistency with + rtld_elf_gnu_hash() + +2009-04-23 Maciej W. Rozycki <macro@codesourcery.com> + + Issue #5165 + * src/ld-do-lookup.h (FCT): Remove the hash argument and + calculate the value within the function. Call + do_lookup_get_first() and do_lookup_get_next() to iterate over + symbols. + * src/prelink.h (dynamic_info_is_set): Convert macro to a + function. Return 1 for success rather than the bit set. + * src/ld-libs.h (ldlibs_link_map): Add l_gnu_hash, l_maskword64, + l_nmaskwords, l_shift and l_maskwords members. + * src/ld-libs.c (create_ldlibs_link_map): Handle the GNU hash. + * src/ld-lookup.c (rtld_elf_gnu_hash): New function. + (rtld_elf_any_hash): Likewise. + (rtld_elf_hash): Move above "ld-do-lookup.h" inclusions. + (do_lookup_get_first, do_lookup_get_next): New functions. + (rtld_lookup_symbol): Remove hash calculation. + (rtld_lookup_symbol_versioned): Likewise. + +2009-04-23 Maciej W. Rozycki <macro@codesourcery.com> + + Issue #5165 * src/execle_open.c (execve_open): Add missing pid initialisation. diff --git a/trunk/src/ld-do-lookup.h b/trunk/src/ld-do-lookup.h index 3e792ba..2d359d7 100644 --- a/trunk/src/ld-do-lookup.h +++ b/trunk/src/ld-do-lookup.h @@ -29,9 +29,9 @@ found the symbol, the value 0 if nothing is found and < 0 if something bad happened. */ static inline int -FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, - struct sym_val *result, struct r_scope_elem *scope, size_t i, ARG, - struct ldlibs_link_map *skip, int type_class, int machine) +FCT (const char *undef_name, const ElfW(Sym) *ref, struct sym_val *result, + struct r_scope_elem *scope, size_t i, ARG, struct ldlibs_link_map *skip, + int type_class, int machine) { struct ldlibs_link_map **list = scope->r_list; size_t n = scope->r_nlist; @@ -39,11 +39,13 @@ FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, do { + unsigned long int hash; const ElfW(Sym) *symtab; const char *strtab; const ElfW(Half) *verstab; Elf_Symndx symidx; const ElfW(Sym) *sym; + int gnu_hash; #if ! VERSIONED int num_versions = 0; const ElfW(Sym) *versioned_sym = NULL; @@ -68,12 +70,14 @@ FCT (const char *undef_name, unsigned long int hash, const ElfW(Sym) *ref, symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); verstab = map->l_versyms; + gnu_hash = map->l_gnu_hash; + hash = rtld_elf_any_hash (undef_name, gnu_hash); /* Search the appropriate hash bucket in this object's symbol table for a definition for the same symbol name. */ - for (symidx = map->l_buckets[hash % map->l_nbuckets]; + for (symidx = do_lookup_get_first (map, hash, gnu_hash); symidx != STN_UNDEF; - symidx = map->l_chain[symidx]) + symidx = do_lookup_get_next (symidx, map, hash, gnu_hash)) { sym = &symtab[symidx]; diff --git a/trunk/src/ld-libs.c b/trunk/src/ld-libs.c index bd2a96e..f5cf629 100644 --- a/trunk/src/ld-libs.c +++ b/trunk/src/ld-libs.c @@ -864,12 +864,28 @@ create_ldlibs_link_map (struct dso_list *cur_dso_ent) data = elf_getdata (dso->scn[i], NULL); map->l_info[DT_STRTAB] = data->d_buf; + map->l_gnu_hash = dynamic_info_is_set (dso, DT_GNU_HASH_BIT); + if (map->l_gnu_hash) + i = addr_to_sec (dso, dso->info_DT_GNU_HASH); + else i = addr_to_sec (dso, dso->info[DT_HASH]); data = elf_getdata (dso->scn[i], NULL); hash = data->d_buf; - map->l_nbuckets = *hash; + map->l_nbuckets = hash[0]; + if (map->l_gnu_hash) + { + map->l_nmaskwords = hash[2]; + map->l_maskword64 = gelf_getclass (dso->elf) == ELFCLASS64; + map->l_shift = hash[3]; + map->l_maskwords = hash + 4; + map->l_buckets = hash + 4 + (map->l_nmaskwords << map->l_maskword64); + map->l_chain = map->l_buckets + map->l_nbuckets - hash[1]; + } + else + { map->l_buckets = hash + 2; - map->l_chain = hash + 2 + map->l_nbuckets; + map->l_chain = map->l_buckets + map->l_nbuckets; + } get_version_info (dso, map); diff --git a/trunk/src/ld-libs.h b/trunk/src/ld-libs.h index 48dd555..d69c7cd 100644 --- a/trunk/src/ld-libs.h +++ b/trunk/src/ld-libs.h @@ -34,7 +34,9 @@ struct ldlibs_link_map void *l_info[DT_NUM + DT_VERSIONTAGNUM]; /* Symbol hash table. */ - Elf_Symndx l_nbuckets; + int l_gnu_hash, l_maskword64; + Elf_Symndx l_nbuckets, l_nmaskwords, l_shift; + const void *l_maskwords; const Elf_Symndx *l_buckets, *l_chain; unsigned int l_nversions; diff --git a/trunk/src/ld-lookup.c b/trunk/src/ld-lookup.c index 69b6bd1..5128dbb 100644 --- a/trunk/src/ld-lookup.c +++ b/trunk/src/ld-lookup.c @@ -45,17 +45,13 @@ struct sym_val struct ldlibs_link_map *m; }; -#include "ld-do-lookup.h" -#define VERSIONED 1 -#include "ld-do-lookup.h" -#undef VERSIONED - static unsigned long rtld_elf_hash (const char *name) { const unsigned char *str = (const unsigned char *) name; - unsigned long int hash, hi; - hash = *str++; + unsigned long int hash = 0; + unsigned long int hi; + while (*str != '\0') { hash = (hash << 4) + *str++; @@ -66,6 +62,97 @@ rtld_elf_hash (const char *name) return hash & 0xffffffff; } +static unsigned long +rtld_elf_gnu_hash (const char *name) +{ + const unsigned char *str = (const unsigned char *) name; + unsigned long int hash = 5381; + + while (*str != '\0') + hash = (hash << 5) + hash + *str++; + return hash & 0xffffffff; +} + +static inline unsigned long +rtld_elf_any_hash (const char *name, int gnu_hash) +{ + return gnu_hash ? rtld_elf_gnu_hash (name) : rtld_elf_hash (name); +} + +static inline Elf_Symndx +do_lookup_get_first (struct ldlibs_link_map *map, + unsigned long int hash, int gnu_hash) +{ + Elf_Symndx symidx = STN_UNDEF; + + if (gnu_hash) + { + Elf_Symndx bucket; + int match; + + if (map->l_maskword64) + { + const Elf64_Xword *const masks = map->l_maskwords; + const Elf64_Xword mask = masks[(hash / 64) % map->l_nmaskwords]; + const Elf64_Xword set = ((1ULL << (hash % 64)) + | (1ULL << ((hash >> map->l_shift) % 64))); + + match = (mask & set) == set; + } + else + { + const Elf32_Word *const masks = map->l_maskwords; + const Elf32_Word mask = masks[(hash / 32) % map->l_nmaskwords]; + const Elf32_Word set = ((1UL << (hash % 32)) + | (1UL << ((hash >> map->l_shift) % 32))); + + match = (mask & set) == set; + } + + if (match + && (bucket = map->l_buckets[hash % map->l_nbuckets]) != STN_UNDEF) + do + if (((map->l_chain[bucket] ^ hash) & ~1UL) == 0) + { + symidx = bucket; + break; + } + while ((map->l_chain[bucket++] & 1) == 0); + } + else + symidx = map->l_buckets[hash % map->l_nbuckets]; + + return symidx; +} + +static inline Elf_Symndx +do_lookup_get_next (Elf_Symndx osymidx, struct ldlibs_link_map *map, + unsigned long int hash, int gnu_hash) +{ + Elf_Symndx symidx = STN_UNDEF; + + if (gnu_hash) + { + Elf_Symndx bucket = osymidx; + + while ((map->l_chain[bucket++] & 1) == 0) + if (((map->l_chain[bucket] ^ hash) & ~1UL) == 0) + { + symidx = bucket; + break; + } + } + else + symidx = map->l_chain[osymidx]; + + return symidx; +} + +#include "ld-do-lookup.h" +#define VERSIONED 1 +#include "ld-do-lookup.h" +#undef VERSIONED + static int _dl_soname_match_p (const char *name, struct ldlibs_link_map *map) { @@ -86,8 +173,7 @@ rtld_lookup_symbol (const char *name, const ElfW(Sym) *sym, struct sym_val result; result.s = NULL; - ret = do_lookup (name, rtld_elf_hash (name), sym, - &result, scope, 0, 0, NULL, rtypeclass); + ret = do_lookup (name, sym, &result, scope, 0, 0, NULL, rtypeclass); if (ret > 0) printf ("name %s /%d\n", name, rtypeclass); #if 0 @@ -125,13 +211,11 @@ rtld_lookup_symbol_versioned (const char *name, const ElfW(Sym) *sym, result2.s = NULL; result2.m = NULL; if (version) - ret = do_lookup_versioned (name, rtld_elf_hash (name), sym, - &result, scope, 0, version, NULL, rtypeclass, - machine); + ret = do_lookup_versioned (name, sym, &result, scope, 0, version, NULL, + rtypeclass, machine); else - ret = do_lookup (name, rtld_elf_hash (name), sym, - &result, scope, 0, 0, NULL, rtypeclass, - machine); + ret = do_lookup (name, sym, &result, scope, 0, 0, NULL, + rtypeclass, machine); if (result.s == NULL && ELFW(ST_BIND) (sym->st_info) != STB_WEAK) printf ("undefined symbol: %s\t(%s)\n", name, undef_map->filename); @@ -145,13 +229,13 @@ rtld_lookup_symbol_versioned (const char *name, const ElfW(Sym) *sym, result2.s = NULL; result2.m = NULL; if (version) - ret = do_lookup_versioned (name, rtld_elf_hash (name), sym, - &result2, undef_map->l_local_scope, 0, version, - NULL, rtypeclass, machine); + ret = do_lookup_versioned (name, sym, &result2, + undef_map->l_local_scope, 0, version, NULL, + rtypeclass, machine); else - ret = do_lookup (name, rtld_elf_hash (name), sym, - &result2, undef_map->l_local_scope, 0, 0, - NULL, rtypeclass, machine); + ret = do_lookup (name, sym, &result2, + undef_map->l_local_scope, 0, 0, NULL, + rtypeclass, machine); if (result2.s != result.s || result2.m != result.m) diff --git a/trunk/src/prelink.h b/trunk/src/prelink.h index 78f775d..117d266 100644 --- a/trunk/src/prelink.h +++ b/trunk/src/prelink.h @@ -1,5 +1,6 @@ /* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Red Hat, Inc. + Copyright (C) 2008 CodeSourcery. Written by Jakub Jelinek <jakub@redhat.com>, 2001. Updated by Maciej W. Rozycki <macro@codesourcery.com>, 2008. @@ -179,7 +180,11 @@ typedef struct GElf_Shdr shdr[0]; } DSO; -#define dynamic_info_is_set(dso,bit) ((dso)->info_set_mask & (1ULL << (bit))) +static inline int +dynamic_info_is_set (DSO *dso, int bit) +{ + return ((dso)->info_set_mask & (1ULL << (bit))) != 0; +} struct layout_libs; |