2006-09-04 Jakub Jelinek <jakub@redhat.com> * Makerules (shlib.lds): If have-hash-style, put .hash section at the end of the RO segment. 2006-09-04 Ulrich Drepper <drepper@redhat.com> * elf/do-lookup.h (do_lookup_x): Initialize symidx in case the new style hash table format is used. 2006-08-02 Ulrich Drepper <drepper@redhat.com> * elf/dl-addr.c (_dl_addr): If GNU-style hash tables are present, walk them instead of the symbol table. 2006-07-10 Ulrich Drepper <drepper@redhat.com> * elf/dl-lookup.c (dl_new_hash): New functions. (_dl_lookup_symbol_x): Rename hash to old_hash and don't compute value here. Compute new-style hash value. Pass new hash value and reference to variable with the old value to do_lookup_x. (_dl_setup_hash): If DT_GNU_HASH is defined, use it and not old-style hash table. (_dl_debug_bindings): Pass new hash value and reference to variable with the old value to do_lookup_x. * elf/do-lookup.h (do_lookup_x): Accept additional parameter with new-style hash value and change old-style hash value parameter to be a reference. Reoganize functions to determine whether new-style hash table is available. Only fall back on old-style table. If old-style hash value is needed, compute it here. * elf/dynamic-link.h (elf_get_dynamic_info): Relocate DT_GNU_HASH entry. * elf/elf.h: Define SHT_GNU_HASH, DT_GNU_HASH, DT_TLSDEC_PLT, DT_TLSDEC_GOT. Adjust DT_ADDRNUM. * include/link.h (struct link_map): Add l_gnu_bitmask_idxbits, l_gnu_shift, l_gnu_bitmask, l_gnu_buckets and l_gnu_chain_zero. * Makeconfig: If linker supports --hash-style option add it to all linker command lines to build DSOs. * config.make.in: Define have-hash-style. * configure.in: Test whether linker supports --hash-style option. * elf/dl-misc.c (_dl_name_match_p): Make MAP parameter const. * sysdeps/generic/ldsodefs.h: Adjust prototype. --- glibc-2.4.90/elf/dynamic-link.h.DT_GNU_HASH 2005-04-30 10:11:54.000000000 +0200 +++ glibc-2.4.90/elf/dynamic-link.h 2007-01-12 19:14:19.000000000 +0100 @@ -1,5 +1,5 @@ /* Inline functions for dynamic linking. - Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -143,6 +143,8 @@ elf_get_dynamic_info (struct link_map *l # endif ADJUST_DYN_INFO (DT_JMPREL); ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM)); + ADJUST_DYN_INFO (DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM); # undef ADJUST_DYN_INFO assert (cnt <= DL_RO_DYN_TEMP_CNT); } --- glibc-2.4.90/elf/elf.h.DT_GNU_HASH 2006-03-20 10:39:02.000000000 +0100 +++ glibc-2.4.90/elf/elf.h 2007-01-12 19:14:19.000000000 +0100 @@ -329,7 +329,8 @@ typedef struct #define SHT_GROUP 17 /* Section group */ #define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */ #define SHT_NUM 19 /* Number of defined types. */ -#define SHT_LOOS 0x60000000 /* Start OS-specific */ +#define SHT_LOOS 0x60000000 /* Start OS-specific. */ +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ #define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */ #define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */ #define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */ @@ -699,6 +700,9 @@ typedef struct If any adjustment is made to the ELF object after it has been built these entries will need to be adjusted. */ #define DT_ADDRRNGLO 0x6ffffe00 +#define DT_GNU_HASH 0x6ffffef5 /* GNU-style hash table. */ +#define DT_TLSDESC_PLT 0x6ffffef6 +#define DT_TLSDESC_GOT 0x6ffffef7 #define DT_GNU_CONFLICT 0x6ffffef8 /* Start of conflict section */ #define DT_GNU_LIBLIST 0x6ffffef9 /* Library list */ #define DT_CONFIG 0x6ffffefa /* Configuration information. */ @@ -709,7 +713,7 @@ typedef struct #define DT_SYMINFO 0x6ffffeff /* Syminfo table. */ #define DT_ADDRRNGHI 0x6ffffeff #define DT_ADDRTAGIDX(tag) (DT_ADDRRNGHI - (tag)) /* Reverse order! */ -#define DT_ADDRNUM 10 +#define DT_ADDRNUM 11 /* The versioning entry types. The next are defined as part of the GNU extension. */ --- glibc-2.4.90/elf/dl-lookup.c.DT_GNU_HASH 2006-02-16 15:31:37.000000000 +0100 +++ glibc-2.4.90/elf/dl-lookup.c 2007-01-12 19:54:26.000000000 +0100 @@ -1,5 +1,5 @@ /* Look up a symbol in the loaded objects. - Copyright (C) 1995-2002, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -72,6 +72,16 @@ struct sym_val #include "do-lookup.h" +static uint_fast32_t +dl_new_hash (const char *s) +{ + uint_fast32_t h = 5381; + for (unsigned char c = *s; c != '\0'; c = *++s) + h = h * 33 + c; + return h & 0xffffffff; +} + + /* Add extra dependency on MAP to UNDEF_MAP. */ static int internal_function @@ -206,7 +216,8 @@ _dl_lookup_symbol_x (const char *undef_n const struct r_found_version *version, int type_class, int flags, struct link_map *skip_map) { - const unsigned long int hash = _dl_elf_hash (undef_name); + const uint_fast32_t new_hash = dl_new_hash (undef_name); + unsigned long int old_hash = 0xffffffff; struct sym_val current_value = { NULL, NULL }; struct r_scope_elem **scope = symbol_scope; @@ -229,8 +240,9 @@ _dl_lookup_symbol_x (const char *undef_n /* Search the relevant loaded objects for a definition. */ for (size_t start = i; *scope != NULL; start = 0, ++scope) { - int res = do_lookup_x (undef_name, hash, *ref, ¤t_value, *scope, - start, version, flags, skip_map, type_class); + int res = do_lookup_x (undef_name, new_hash, &old_hash, *ref, + ¤t_value, *scope, start, version, flags, + skip_map, type_class); if (res > 0) break; @@ -301,9 +313,9 @@ _dl_lookup_symbol_x (const char *undef_n struct sym_val protected_value = { NULL, NULL }; for (scope = symbol_scope; *scope != NULL; i = 0, ++scope) - if (do_lookup_x (undef_name, hash, *ref, &protected_value, - *scope, i, version, flags, skip_map, - ELF_RTYPE_CLASS_PLT) != 0) + if (do_lookup_x (undef_name, new_hash, &old_hash, *ref, + &protected_value, *scope, i, version, flags, + skip_map, ELF_RTYPE_CLASS_PLT) != 0) break; if (protected_value.s != NULL && protected_value.m != undef_map) @@ -352,6 +364,31 @@ _dl_setup_hash (struct link_map *map) Elf_Symndx *hash; Elf_Symndx nchain; + if (__builtin_expect (map->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + + DT_THISPROCNUM + DT_VERSIONTAGNUM + + DT_EXTRANUM + DT_VALNUM] != NULL, 1)) + { + Elf32_Word *hash32 + = (void *) D_PTR (map, l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + + DT_THISPROCNUM + DT_VERSIONTAGNUM + + DT_EXTRANUM + DT_VALNUM]); + map->l_nbuckets = *hash32++; + Elf32_Word symbias = *hash32++; + Elf32_Word bitmask_nwords = *hash32++; + /* Must be a power of two. */ + assert ((bitmask_nwords & (bitmask_nwords - 1)) == 0); + map->l_gnu_bitmask_idxbits = bitmask_nwords - 1; + map->l_gnu_shift = *hash32++; + + map->l_gnu_bitmask = (ElfW(Addr) *) hash32; + hash32 += __ELF_NATIVE_CLASS / 32 * bitmask_nwords; + + map->l_gnu_buckets = hash32; + hash32 += map->l_nbuckets; + map->l_gnu_chain_zero = hash32 - symbias; + return; + } + if (!map->l_info[DT_HASH]) return; hash = (void *) D_PTR (map, l_info[DT_HASH]); @@ -399,9 +436,10 @@ _dl_debug_bindings (const char *undef_na || GLRO(dl_trace_prelink_map) == GL(dl_ns)[LM_ID_BASE]._ns_loaded) && undef_map != GL(dl_ns)[LM_ID_BASE]._ns_loaded) { - const unsigned long int hash = _dl_elf_hash (undef_name); + const uint_fast32_t new_hash = dl_new_hash (undef_name); + unsigned long int old_hash = 0xffffffff; - do_lookup_x (undef_name, hash, *ref, &val, + do_lookup_x (undef_name, new_hash, &old_hash, *ref, &val, undef_map->l_local_scope[0], 0, version, 0, NULL, type_class); --- glibc-2.4.90/elf/do-lookup.h.DT_GNU_HASH 2006-03-20 10:39:02.000000000 +0100 +++ glibc-2.4.90/elf/do-lookup.h 2007-01-12 20:03:23.000000000 +0100 @@ -17,32 +17,29 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ + /* Inner part of the lookup functions. We return a value > 0 if we found the symbol, the value 0 if nothing is found and < 0 if something bad happened. */ static int __attribute_noinline__ -do_lookup_x (const char *undef_name, unsigned long int hash, - const ElfW(Sym) *ref, struct sym_val *result, - struct r_scope_elem *scope, size_t i, +do_lookup_x (const char *undef_name, uint_fast32_t new_hash, + unsigned long int *old_hash, const ElfW(Sym) *ref, + struct sym_val *result, struct r_scope_elem *scope, size_t i, const struct r_found_version *const version, int flags, struct link_map *skip, int type_class) { struct link_map **list = scope->r_list; size_t n = scope->r_nlist; - struct link_map *map; do { - const ElfW(Sym) *symtab; - const char *strtab; - const ElfW(Half) *verstab; + /* These variables are used in the nested function. */ Elf_Symndx symidx; - const ElfW(Sym) *sym; int num_versions = 0; const ElfW(Sym) *versioned_sym = NULL; - map = list[i]->l_real; + const struct link_map *map = list[i]->l_real; /* Here come the extra test needed for `_dl_lookup_symbol_skip'. */ if (map == skip) @@ -63,109 +60,160 @@ do_lookup_x (const char *undef_name, uns map->l_name[0] ? map->l_name : rtld_progname, map->l_ns); - symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); - strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); - verstab = map->l_versyms; - - /* 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]; - symidx != STN_UNDEF; - symidx = map->l_chain[symidx]) - { - sym = &symtab[symidx]; + /* If the hash table is empty there is nothing to do here. */ + if (map->l_nbuckets == 0) + continue; - assert (ELF_RTYPE_CLASS_PLT == 1); - if ((sym->st_value == 0 /* No value. */ -#ifdef USE_TLS - && ELFW(ST_TYPE) (sym->st_info) != STT_TLS -#endif - ) - || (type_class & (sym->st_shndx == SHN_UNDEF))) - continue; - - if (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC -#ifdef USE_TLS - && ELFW(ST_TYPE) (sym->st_info) != STT_TLS -#endif - ) - /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC - entries (and STT_TLS if TLS is supported) since these - are no code/data definitions. */ - continue; - - if (sym != ref && strcmp (strtab + sym->st_name, undef_name)) - /* Not the symbol we are looking for. */ - continue; + /* The tables for this map. */ + const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); + const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); + + + /* Nested routine to check whether the symbol matches. */ + const ElfW(Sym) * + __attribute_noinline__ + check_match (const ElfW(Sym) *sym) + { + assert (ELF_RTYPE_CLASS_PLT == 1); + if (__builtin_expect ((sym->st_value == 0 /* No value. */ + && ELFW(ST_TYPE) (sym->st_info) != STT_TLS) + || (type_class & (sym->st_shndx == SHN_UNDEF)), + 0)) + return NULL; + + if (__builtin_expect (ELFW(ST_TYPE) (sym->st_info) > STT_FUNC + && ELFW(ST_TYPE) (sym->st_info) != STT_TLS, 0)) + /* Ignore all but STT_NOTYPE, STT_OBJECT and STT_FUNC + entries (and STT_TLS if TLS is supported) since these + are no code/data definitions. */ + return NULL; + + if (sym != ref && strcmp (strtab + sym->st_name, undef_name)) + /* Not the symbol we are looking for. */ + return NULL; + + const ElfW(Half) *verstab = map->l_versyms; + if (version != NULL) + { + if (__builtin_expect (verstab == NULL, 0)) + { + /* We need a versioned symbol but haven't found any. If + this is the object which is referenced in the verneed + entry it is a bug in the library since a symbol must + not simply disappear. + + It would also be a bug in the object since it means that + the list of required versions is incomplete and so the + tests in dl-version.c haven't found a problem.*/ + assert (version->filename == NULL + || ! _dl_name_match_p (version->filename, map)); + + /* Otherwise we accept the symbol. */ + } + else + { + /* We can match the version information or use the + default one if it is not hidden. */ + ElfW(Half) ndx = verstab[symidx] & 0x7fff; + if ((map->l_versions[ndx].hash != version->hash + || strcmp (map->l_versions[ndx].name, version->name)) + && (version->hidden || map->l_versions[ndx].hash + || (verstab[symidx] & 0x8000))) + /* It's not the version we want. */ + return NULL; + } + } + else + { + /* No specific version is selected. There are two ways we + can got here: + + - a binary which does not include versioning information + is loaded + + - dlsym() instead of dlvsym() is used to get a symbol which + might exist in more than one form + + If the library does not provide symbol version information + there is no problem at at: we simply use the symbol if it + is defined. + + These two lookups need to be handled differently if the + library defines versions. In the case of the old + unversioned application the oldest (default) version + should be used. In case of a dlsym() call the latest and + public interface should be returned. */ + if (verstab != NULL) + { + if ((verstab[symidx] & 0x7fff) + >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3)) + { + /* Don't accept hidden symbols. */ + if ((verstab[symidx] & 0x8000) == 0 + && num_versions++ == 0) + /* No version so far. */ + versioned_sym = sym; + + return NULL; + } + } + } + + /* There cannot be another entry for this symbol so stop here. */ + return sym; + } - if (version != NULL) - { - if (__builtin_expect (verstab == NULL, 0)) - { - /* We need a versioned symbol but haven't found any. If - this is the object which is referenced in the verneed - entry it is a bug in the library since a symbol must - not simply disappear. - - It would also be a bug in the object since it means that - the list of required versions is incomplete and so the - tests in dl-version.c haven't found a problem.*/ - assert (version->filename == NULL - || ! _dl_name_match_p (version->filename, map)); + const ElfW(Sym) *sym; + const ElfW(Addr) *bitmask = map->l_gnu_bitmask; + if (__builtin_expect (bitmask != NULL, 1)) + { + ElfW(Addr) bitmask_word + = bitmask[(new_hash / __ELF_NATIVE_CLASS) + & map->l_gnu_bitmask_idxbits]; + + unsigned int hashbit1 = new_hash & (__ELF_NATIVE_CLASS - 1); + unsigned int hashbit2 = ((new_hash >> map->l_gnu_shift) + & (__ELF_NATIVE_CLASS - 1)); - /* Otherwise we accept the symbol. */ - } - else - { - /* We can match the version information or use the - default one if it is not hidden. */ - ElfW(Half) ndx = verstab[symidx] & 0x7fff; - if ((map->l_versions[ndx].hash != version->hash - || strcmp (map->l_versions[ndx].name, version->name)) - && (version->hidden || map->l_versions[ndx].hash - || (verstab[symidx] & 0x8000))) - /* It's not the version we want. */ - continue; - } - } - else + if (__builtin_expect ((bitmask_word >> hashbit1) + & (bitmask_word >> hashbit2) & 1, 0)) { - /* No specific version is selected. There are two ways we - can got here: - - - a binary which does not include versioning information - is loaded - - - dlsym() instead of dlvsym() is used to get a symbol which - might exist in more than one form - - If the library does not provide symbol version - information there is no problem at at: we simply use the - symbol if it is defined. - - These two lookups need to be handled differently if the - library defines versions. In the case of the old - unversioned application the oldest (default) version - should be used. In case of a dlsym() call the latest and - public interface should be returned. */ - if (verstab != NULL) + Elf32_Word bucket = map->l_gnu_buckets[new_hash + % map->l_nbuckets]; + if (bucket != 0) { - if ((verstab[symidx] & 0x7fff) - >= ((flags & DL_LOOKUP_RETURN_NEWEST) ? 2 : 3)) - { - /* Don't accept hidden symbols. */ - if ((verstab[symidx] & 0x8000) == 0 - && num_versions++ == 0) - /* No version so far. */ - versioned_sym = sym; + const Elf32_Word *hasharr = &map->l_gnu_chain_zero[bucket]; - continue; - } + do + if ((*hasharr & ~1u) == (new_hash & ~1u)) + { + symidx = hasharr - map->l_gnu_chain_zero; + sym = check_match (&symtab[symidx]); + if (sym != NULL) + goto found_it; + } + while ((*hasharr++ & 1u) == 0); } } + /* No symbol found. */ + symidx = SHN_UNDEF; + } + else + { + if (*old_hash == 0xffffffff) + *old_hash = _dl_elf_hash (undef_name); - /* There cannot be another entry for this symbol so stop here. */ - goto found_it; + /* Use the old SysV-style hash table. Search the appropriate + hash bucket in this object's symbol table for a definition + for the same symbol name. */ + for (symidx = map->l_buckets[*old_hash % map->l_nbuckets]; + symidx != STN_UNDEF; + symidx = map->l_chain[symidx]) + { + sym = check_match (&symtab[symidx]); + if (sym != NULL) + goto found_it; + } } /* If we have seen exactly one versioned symbol while we are @@ -186,7 +234,7 @@ do_lookup_x (const char *undef_name, uns if (! result->s) { result->s = sym; - result->m = map; + result->m = (struct link_map *) map; } break; } @@ -194,7 +242,7 @@ do_lookup_x (const char *undef_name, uns case STB_GLOBAL: /* Global definition. Just what we need. */ result->s = sym; - result->m = map; + result->m = (struct link_map *) map; return 1; default: /* Local symbols are ignored. */ @@ -213,7 +261,3 @@ do_lookup_x (const char *undef_name, uns /* We have not found anything until now. */ return 0; } - -#undef FCT -#undef ARG -#undef VERSIONED --- glibc-2.4.90/elf/dl-addr.c.DT_GNU_HASH 2007-01-12 19:14:19.000000000 +0100 +++ glibc-2.4.90/elf/dl-addr.c 2007-01-12 19:14:19.000000000 +0100 @@ -74,29 +74,64 @@ _dl_addr (const void *address, Dl_info * ElfW(Word) strtabsize = match->l_info[DT_STRSZ]->d_un.d_val; - const ElfW(Sym) *symtabend; - if (match->l_info[DT_HASH] != NULL) - symtabend = (symtab - + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]); + const ElfW(Sym) *matchsym = NULL; + if (match->l_info[DT_ADDRTAGIDX (DT_GNU_HASH) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] != NULL) + { + /* We look at all symbol table entries referenced by the + hash table. */ + for (Elf_Symndx bucket = 0; bucket < match->l_nbuckets; ++bucket) + { + Elf32_Word symndx = match->l_gnu_buckets[bucket]; + if (symndx != 0) + { + const Elf32_Word *hasharr = &match->l_gnu_chain_zero[symndx]; + + do + { + /* The hash table never references local symbols + so we can omit that test here. */ + if ((symtab[symndx].st_shndx != SHN_UNDEF + || symtab[symndx].st_value != 0) +#ifdef USE_TLS + && ELFW(ST_TYPE) (symtab[symndx].st_info) != STT_TLS +#endif + && DL_ADDR_SYM_MATCH (match, &symtab[symndx], + matchsym, addr) + && symtab[symndx].st_name < strtabsize) + matchsym = (ElfW(Sym) *) &symtab[symndx]; + + ++symndx; + } + while ((*hasharr++ & 1u) == 0); + } + } + } else - /* There is no direct way to determine the number of symbols in the - dynamic symbol table and no hash table is present. The ELF - binary is ill-formed but what shall we do? Use the beginning of - the string table which generally follows the symbol table. */ - symtabend = (const ElfW(Sym) *) strtab; - - const ElfW(Sym) *matchsym; - for (matchsym = NULL; (void *) symtab < (void *) symtabend; ++symtab) - if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL - || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK) -#if defined USE_TLS - && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS + { + const ElfW(Sym) *symtabend; + if (match->l_info[DT_HASH] != NULL) + symtabend = (symtab + + ((Elf_Symndx *) D_PTR (match, l_info[DT_HASH]))[1]); + else + /* There is no direct way to determine the number of symbols in the + dynamic symbol table and no hash table is present. The ELF + binary is ill-formed but what shall we do? Use the beginning of + the string table which generally follows the symbol table. */ + symtabend = (const ElfW(Sym) *) strtab; + + for (; (void *) symtab < (void *) symtabend; ++symtab) + if ((ELFW(ST_BIND) (symtab->st_info) == STB_GLOBAL + || ELFW(ST_BIND) (symtab->st_info) == STB_WEAK) +#ifdef USE_TLS + && ELFW(ST_TYPE) (symtab->st_info) != STT_TLS #endif - && (symtab->st_shndx != SHN_UNDEF - || symtab->st_value != 0) - && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr) - && symtab->st_name < strtabsize) - matchsym = (ElfW(Sym) *) symtab; + && (symtab->st_shndx != SHN_UNDEF + || symtab->st_value != 0) + && DL_ADDR_SYM_MATCH (match, symtab, matchsym, addr) + && symtab->st_name < strtabsize) + matchsym = (ElfW(Sym) *) symtab; + } if (mapp) *mapp = match; --- glibc-2.4.90/elf/dl-misc.c.DT_GNU_HASH 2004-07-07 15:33:34.000000000 +0200 +++ glibc-2.4.90/elf/dl-misc.c 2007-01-12 20:07:12.000000000 +0100 @@ -1,5 +1,5 @@ /* Miscellaneous support functions for dynamic linker - Copyright (C) 1997-2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 1997-2002, 2003, 2004, 2006 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -308,7 +308,7 @@ _dl_dprintf (int fd, const char *fmt, .. /* Test whether given NAME matches any of the names of the given object. */ int internal_function -_dl_name_match_p (const char *name, struct link_map *map) +_dl_name_match_p (const char *name, const struct link_map *map) { if (strcmp (name, map->l_name) == 0) return 1; --- glibc-2.4.90/include/link.h.DT_GNU_HASH 2006-03-20 10:39:02.000000000 +0100 +++ glibc-2.4.90/include/link.h 2007-01-12 20:17:26.000000000 +0100 @@ -124,7 +124,7 @@ struct link_map const ElfW(Phdr) *l_phdr; /* Pointer to program header table in core. */ ElfW(Addr) l_entry; /* Entry point location. */ ElfW(Half) l_phnum; /* Number of program header entries. */ - ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */ + ElfW(Half) l_ldnum; /* Number of dynamic segment entries. */ /* Array of DT_NEEDED dependencies and their dependencies, in dependency order for symbol lookup (with and without @@ -141,7 +141,19 @@ struct link_map /* Symbol hash table. */ Elf_Symndx l_nbuckets; - const Elf_Symndx *l_buckets, *l_chain; + Elf32_Word l_gnu_bitmask_idxbits; + Elf32_Word l_gnu_shift; + const ElfW(Addr) *l_gnu_bitmask; + union + { + const Elf32_Word *l_gnu_buckets; + const Elf_Symndx *l_chain; + }; + union + { + const Elf32_Word *l_gnu_chain_zero; + const Elf_Symndx *l_buckets; + }; unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose. */ enum /* Where this object came from. */ --- glibc-2.4.90/sysdeps/generic/ldsodefs.h.DT_GNU_HASH 2007-01-12 19:14:19.000000000 +0100 +++ glibc-2.4.90/sysdeps/generic/ldsodefs.h 2007-01-12 20:10:20.000000000 +0100 @@ -331,7 +331,7 @@ struct audit_ifaces /* Test whether given NAME matches any of the names of the given object. */ -extern int _dl_name_match_p (const char *__name, struct link_map *__map) +extern int _dl_name_match_p (const char *__name, const struct link_map *__map) internal_function; /* Function used as argument for `_dl_receive_error' function. The --- glibc-2.4.90/Makeconfig.DT_GNU_HASH 2007-01-12 19:14:19.000000000 +0100 +++ glibc-2.4.90/Makeconfig 2007-01-12 19:14:19.000000000 +0100 @@ -413,11 +413,20 @@ LDFLAGS.so += $(relro-LDFLAGS) LDFLAGS-rtld += $(relro-LDFLAGS) endif +ifeq (yes,$(have-hash-style)) +# For the time being we unconditionally use 'both'. At some time we +# should declare statically linked code as 'out of luck' and compile +# with --hash-style=gnu only. +hashstyle-LDFLAGS = -Wl,--hash-style=both +LDFLAGS.so += $(hashstyle-LDFLAGS) +LDFLAGS-rtld += $(hashstyle-LDFLAGS) +endif + # Command for linking programs with the C library. ifndef +link +link = $(CC) -nostdlib -nostartfiles -o $@ \ $(sysdep-LDFLAGS) $(config-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \ - $(combreloc-LDFLAGS) $(relro-LDFLAGS) \ + $(combreloc-LDFLAGS) $(relro-LDFLAGS) $(hashstyle-LDFLAGS) \ $(addprefix $(csu-objpfx),$(start-installed-name)) \ $(+preinit) $(+prector) \ $(filter-out $(addprefix $(csu-objpfx),start.o \ --- glibc-2.4.90/config.make.in.DT_GNU_HASH 2006-04-27 14:54:33.000000000 +0200 +++ glibc-2.4.90/config.make.in 2007-01-12 19:14:19.000000000 +0100 @@ -65,6 +65,7 @@ have-libcap = @have_libcap@ have-cc-with-libunwind = @libc_cv_cc_with_libunwind@ fno-unit-at-a-time = @fno_unit_at_a_time@ bind-now = @bindnow@ +have-hash-style = @libc_cv_hashstyle@ static-libgcc = @libc_cv_gcc_static_libgcc@ --- glibc-2.4.90/configure.in.DT_GNU_HASH 2006-04-27 14:54:33.000000000 +0200 +++ glibc-2.4.90/configure.in 2007-01-12 19:14:19.000000000 +0100 @@ -1589,6 +1589,22 @@ EOF rm -f conftest*]) AC_SUBST(libc_cv_fpie) + + AC_CACHE_CHECK(for --hash-style option, + libc_cv_hashstyle, [dnl + cat > conftest.c <<EOF +int _start (void) { return 42; } +EOF + if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS + -fPIC -shared -o conftest.so conftest.c + -Wl,--hash-style=both -nostdlib 1>&AS_MESSAGE_LOG_FD]) + then + libc_cv_hashstyle=yes + else + libc_cv_hashstyle=no + fi + rm -f conftest*]) + AC_SUBST(libc_cv_hashstyle) fi AC_CACHE_CHECK(for -fno-toplevel-reorder, libc_cv_fno_toplevel_reorder, [dnl --- glibc-2.4.90/Makerules.DT_GNU_HASH 2006-03-20 10:39:01.000000000 +0100 +++ glibc-2.4.90/Makerules 2007-01-12 19:14:19.000000000 +0100 @@ -487,7 +487,13 @@ $(common-objpfx)shlib.lds: $(common-objp -Wl,--verbose 2>&1 | \ sed > $@T \ -e '/^=========/,/^=========/!d;/^=========/d' \ - -e 's/^.*\.hash[ ]*:.*$$/ .note.ABI-tag : { *(.note.ABI-tag) } &/' \ + $(if $(filter yes,$(have-hash-style)), \ + -e 's/^.*\.gnu\.hash[ ]*:.*$$/ .note.ABI-tag : { *(.note.ABI-tag) } &/' \ + -e '/^[ ]*\.hash[ ]*:.*$$/{h;d;}' \ + -e '/DATA_SEGMENT_ALIGN/{H;g}' \ + , \ + -e 's/^.*\.hash[ ]*:.*$$/ .note.ABI-tag : { *(.note.ABI-tag) } &/' \ + ) \ -e 's/^.*\*(\.dynbss).*$$/& \ PROVIDE(__start___libc_freeres_ptrs = .); \ *(__libc_freeres_ptrs) \