Module: wine Branch: refs/heads/master Commit: 30a3866b78baf978e18197ff714c09346c51665d URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=30a3866b78baf978e18197ff...
Author: Alexandre Julliard julliard@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; }
/*