aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trunk/ChangeLog.cross26
-rw-r--r--trunk/src/ld-do-lookup.h14
-rw-r--r--trunk/src/ld-libs.c20
-rw-r--r--trunk/src/ld-libs.h4
-rw-r--r--trunk/src/ld-lookup.c126
-rw-r--r--trunk/src/prelink.h7
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;