Alexandre Julliard : preloader: Added support for the new style DT_GNU_HASH symbol table.

Alexandre Julliard julliard at wine.codeweavers.com
Mon Jul 31 15:01:21 CDT 2006


Module: wine
Branch: refs/heads/master
Commit: 30a3866b78baf978e18197ff714c09346c51665d
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=30a3866b78baf978e18197ff714c09346c51665d

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Mon Jul 31 21:02:38 2006 +0200

preloader: Added support for the new style DT_GNU_HASH symbol table.

---

 loader/preloader.c |   59 +++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 46 insertions(+), 13 deletions(-)

diff --git a/loader/preloader.c b/loader/preloader.c
index 52f4cc1..7140f3a 100644
--- a/loader/preloader.c
+++ b/loader/preloader.c
@@ -131,6 +131,10 @@ #ifndef AT_SYSINFO_EHDR
 #define AT_SYSINFO_EHDR 33
 #endif
 
+#ifndef DT_GNU_HASH
+#define DT_GNU_HASH 0x6ffffef5
+#endif
+
 static unsigned int page_size, page_mask;
 static char *preloader_start, *preloader_end;
 
@@ -758,6 +762,13 @@ static unsigned int elf_hash( const char
     return hash;
 }
 
+static unsigned int gnu_hash( const char *name )
+{
+    unsigned int h = 5381;
+    while (*name) h = h * 33 + (unsigned char)*name++;
+    return h;
+}
+
 /*
  * Find a symbol in the symbol table of the executable loaded
  */
@@ -767,7 +778,9 @@ static void *find_symbol( const ElfW(Phd
     const ElfW(Phdr) *ph;
     const ElfW(Sym) *symtab = NULL;
     const Elf_Symndx *hashtab = NULL;
+    const Elf32_Word *gnu_hashtab = NULL;
     const char *strings = NULL;
+    Elf_Symndx idx;
 
     /* check the values */
 #ifdef DUMP_SYMS
@@ -799,6 +812,8 @@ #endif
             symtab = (const ElfW(Sym) *)dyn->d_un.d_ptr;
         if( dyn->d_tag == DT_HASH )
             hashtab = (const Elf_Symndx *)dyn->d_un.d_ptr;
+        if( dyn->d_tag == DT_GNU_HASH )
+            gnu_hashtab = (const Elf32_Word *)dyn->d_un.d_ptr;
 #ifdef DUMP_SYMS
         wld_printf("%x %x\n", dyn->d_tag, dyn->d_un.d_ptr );
 #endif
@@ -807,28 +822,46 @@ #endif
 
     if( (!symtab) || (!strings) ) return NULL;
 
-    if (hashtab)
+    if (gnu_hashtab)  /* new style hash table */
+    {
+        const unsigned int hash   = gnu_hash(var);
+        const Elf32_Word nbuckets = gnu_hashtab[0];
+        const Elf32_Word symbias  = gnu_hashtab[1];
+        const Elf32_Word nwords   = gnu_hashtab[2];
+        const ElfW(Addr) *bitmask = (const ElfW(Addr) *)(gnu_hashtab + 4);
+        const Elf32_Word *buckets = (const Elf32_Word *)(bitmask + nwords);
+        const Elf32_Word *chains  = buckets + nbuckets - symbias;
+
+        if (!(idx = buckets[hash % nbuckets])) return NULL;
+        do
+        {
+            if ((chains[idx] & ~1u) == (hash & ~1u) &&
+                symtab[idx].st_info == ELF32_ST_INFO( STB_GLOBAL, type ) &&
+                !wld_strcmp( strings + symtab[idx].st_name, var ))
+                goto found;
+        } while (!(chains[idx++] & 1u));
+    }
+    else if (hashtab)  /* old style hash table */
     {
-        Elf_Symndx nbuckets = hashtab[0];
-        unsigned int hash = elf_hash(var) % nbuckets;
+        const unsigned int hash   = elf_hash(var);
+        const Elf_Symndx nbuckets = hashtab[0];
         const Elf_Symndx *buckets = hashtab + 2;
-        const Elf_Symndx *chains = buckets + nbuckets;
-        Elf_Symndx idx = buckets[hash];
+        const Elf_Symndx *chains  = buckets + nbuckets;
 
-        while (idx != STN_UNDEF)
+        for (idx = buckets[hash % nbuckets]; idx != STN_UNDEF; idx = chains[idx])
         {
             if (symtab[idx].st_info == ELF32_ST_INFO( STB_GLOBAL, type ) &&
                 !wld_strcmp( strings + symtab[idx].st_name, var ))
-            {
-#ifdef DUMP_SYMS
-                wld_printf("Found %s -> %x\n", strings + symtab[idx].st_name, symtab[idx].st_value );
-#endif
-                return (void*)symtab[idx].st_value;
-            }
-            idx = chains[idx];
+                goto found;
         }
     }
     return NULL;
+
+found:
+#ifdef DUMP_SYMS
+    wld_printf("Found %s -> %x\n", strings + symtab[idx].st_name, symtab[idx].st_value );
+#endif
+    return (void *)symtab[idx].st_value;
 }
 
 /*




More information about the wine-cvs mailing list