preloader: Added support for the new style DT_GNU_HASH symbol table.
This commit is contained in:
parent
51d8482222
commit
30a3866b78
|
@ -131,6 +131,10 @@ static struct wine_preload_info preload_info[] =
|
||||||
#define AT_SYSINFO_EHDR 33
|
#define AT_SYSINFO_EHDR 33
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DT_GNU_HASH
|
||||||
|
#define DT_GNU_HASH 0x6ffffef5
|
||||||
|
#endif
|
||||||
|
|
||||||
static unsigned int page_size, page_mask;
|
static unsigned int page_size, page_mask;
|
||||||
static char *preloader_start, *preloader_end;
|
static char *preloader_start, *preloader_end;
|
||||||
|
|
||||||
|
@ -758,6 +762,13 @@ static unsigned int elf_hash( const char *name )
|
||||||
return hash;
|
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
|
* Find a symbol in the symbol table of the executable loaded
|
||||||
*/
|
*/
|
||||||
|
@ -767,7 +778,9 @@ static void *find_symbol( const ElfW(Phdr) *phdr, int num, const char *var, int
|
||||||
const ElfW(Phdr) *ph;
|
const ElfW(Phdr) *ph;
|
||||||
const ElfW(Sym) *symtab = NULL;
|
const ElfW(Sym) *symtab = NULL;
|
||||||
const Elf_Symndx *hashtab = NULL;
|
const Elf_Symndx *hashtab = NULL;
|
||||||
|
const Elf32_Word *gnu_hashtab = NULL;
|
||||||
const char *strings = NULL;
|
const char *strings = NULL;
|
||||||
|
Elf_Symndx idx;
|
||||||
|
|
||||||
/* check the values */
|
/* check the values */
|
||||||
#ifdef DUMP_SYMS
|
#ifdef DUMP_SYMS
|
||||||
|
@ -799,6 +812,8 @@ static void *find_symbol( const ElfW(Phdr) *phdr, int num, const char *var, int
|
||||||
symtab = (const ElfW(Sym) *)dyn->d_un.d_ptr;
|
symtab = (const ElfW(Sym) *)dyn->d_un.d_ptr;
|
||||||
if( dyn->d_tag == DT_HASH )
|
if( dyn->d_tag == DT_HASH )
|
||||||
hashtab = (const Elf_Symndx *)dyn->d_un.d_ptr;
|
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
|
#ifdef DUMP_SYMS
|
||||||
wld_printf("%x %x\n", dyn->d_tag, dyn->d_un.d_ptr );
|
wld_printf("%x %x\n", dyn->d_tag, dyn->d_un.d_ptr );
|
||||||
#endif
|
#endif
|
||||||
|
@ -807,29 +822,47 @@ static void *find_symbol( const ElfW(Phdr) *phdr, int num, const char *var, int
|
||||||
|
|
||||||
if( (!symtab) || (!strings) ) return NULL;
|
if( (!symtab) || (!strings) ) return NULL;
|
||||||
|
|
||||||
if (hashtab)
|
if (gnu_hashtab) /* new style hash table */
|
||||||
{
|
{
|
||||||
Elf_Symndx nbuckets = hashtab[0];
|
const unsigned int hash = gnu_hash(var);
|
||||||
unsigned int hash = elf_hash(var) % nbuckets;
|
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 */
|
||||||
|
{
|
||||||
|
const unsigned int hash = elf_hash(var);
|
||||||
|
const Elf_Symndx nbuckets = hashtab[0];
|
||||||
const Elf_Symndx *buckets = hashtab + 2;
|
const Elf_Symndx *buckets = hashtab + 2;
|
||||||
const Elf_Symndx *chains = buckets + nbuckets;
|
const Elf_Symndx *chains = buckets + nbuckets;
|
||||||
Elf_Symndx idx = buckets[hash];
|
|
||||||
|
|
||||||
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 ) &&
|
if (symtab[idx].st_info == ELF32_ST_INFO( STB_GLOBAL, type ) &&
|
||||||
!wld_strcmp( strings + symtab[idx].st_name, var ))
|
!wld_strcmp( strings + symtab[idx].st_name, var ))
|
||||||
{
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
found:
|
||||||
#ifdef DUMP_SYMS
|
#ifdef DUMP_SYMS
|
||||||
wld_printf("Found %s -> %x\n", strings + symtab[idx].st_name, symtab[idx].st_value );
|
wld_printf("Found %s -> %x\n", strings + symtab[idx].st_name, symtab[idx].st_value );
|
||||||
#endif
|
#endif
|
||||||
return (void *)symtab[idx].st_value;
|
return (void *)symtab[idx].st_value;
|
||||||
}
|
}
|
||||||
idx = chains[idx];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* preload_reserve
|
* preload_reserve
|
||||||
|
|
Loading…
Reference in New Issue