summaryrefslogtreecommitdiffstats
path: root/trunk/src/ld-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/ld-lookup.c')
-rw-r--r--trunk/src/ld-lookup.c126
1 files changed, 105 insertions, 21 deletions
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)