From: Paweł Sikora Date: Mon, 9 Oct 2006 18:42:40 +0000 (+0000) Subject: - support for .gnu.hash. X-Git-Tag: auto/th/gdb-6_5-2~1 X-Git-Url: http://git.pld-linux.org/?a=commitdiff_plain;h=82b216b88b7f20a6a3b05564071307bd99f99cce;p=packages%2Fgdb.git - support for .gnu.hash. Changed files: gdb-gnu_hash.patch -> 1.1 --- diff --git a/gdb-gnu_hash.patch b/gdb-gnu_hash.patch new file mode 100644 index 0000000..d782118 --- /dev/null +++ b/gdb-gnu_hash.patch @@ -0,0 +1,880 @@ +2006-07-10 Jakub Jelinek + +include/ + * bfdlink.h (struct bfd_link_info): Add emit_hash and + emit_gnu_hash bitfields. +include/elf/ + * common.h (SHT_GNU_HASH, DT_GNU_HASH): Define. +bfd/ + * elf.c (_bfd_elf_print_private_bfd_data): Handle DT_GNU_HASH. + (bfd_section_from_shdr, elf_fake_sections, assign_section_numbers): + Handle SHT_GNU_HASH. + (special_sections_g): Include .gnu.hash section. + (bfd_elf_gnu_hash): New function. + * elf-bfd.h (bfd_elf_gnu_hash, _bfd_elf_hash_symbol): New prototypes. + (struct elf_backend_data): Add elf_hash_symbol method. + * elflink.c (_bfd_elf_link_create_dynamic_sections): Create .hash + only if info->emit_hash, create .gnu.hash section if + info->emit_gnu_hash. + (struct collect_gnu_hash_codes): New type. + (elf_collect_gnu_hash_codes, elf_renumber_gnu_hash_syms, + _bfd_elf_hash_symbol): New functions. + (compute_bucket_count): Don't compute HASHCODES array, instead add + that and NSYMS as arguments. Use bed->s->sizeof_hash_entry + instead of bed->s->arch_size / 8. Fix .hash size estimation. + When not optimizing, use the number of hashed symbols rather than + dynsymcount. + (bfd_elf_size_dynamic_sections): Only add DT_HASH if info->emit_hash, + and ADD DT_GNU_HASH if info->emit_gnu_hash. + (bfd_elf_size_dynsym_hash_dynstr): Size .hash only if info->emit_hash, + adjust compute_bucket_count caller. Create and populate .gnu.hash + section if info->emit_gnu_hash. + (elf_link_output_extsym): Only populate .hash section if + finfo->hash_sec != NULL. + (bfd_elf_final_link): Adjust assertion. Handle DT_GNU_HASH. + * elfxx-target.h (elf_backend_hash_symbol): Define if not yet defined. + (elfNN_bed): Add elf_backend_hash_symbol. + * elf64-x86-64.c (elf64_x86_64_hash_symbol): New function. + (elf_backend_hash_symbol): Define. + * elf32-i386.c (elf_i386_hash_symbol): New function. + (elf_backend_hash_symbol): Define. + +Index: gdb-6.5/bfd/elf-bfd.h +=================================================================== +--- gdb-6.5.orig/bfd/elf-bfd.h 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/bfd/elf-bfd.h 2006-07-14 01:31:25.000000000 -0300 +@@ -1022,6 +1022,9 @@ struct elf_backend_data + bfd_boolean *, bfd_boolean *, + bfd *, asection **); + ++ /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ bfd_boolean (*elf_hash_symbol) (struct elf_link_hash_entry *); ++ + /* Used to handle bad SHF_LINK_ORDER input. */ + bfd_error_handler_type link_order_error_handler; + +@@ -1462,6 +1465,8 @@ extern bfd_vma _bfd_elf_section_offset + + extern unsigned long bfd_elf_hash + (const char *); ++extern unsigned long bfd_elf_gnu_hash ++ (const char *); + + extern bfd_reloc_status_type bfd_elf_generic_reloc + (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); +@@ -1632,6 +1637,8 @@ extern bfd_boolean _bfd_elf_merge_symbol + struct elf_link_hash_entry **, bfd_boolean *, + bfd_boolean *, bfd_boolean *, bfd_boolean *); + ++extern bfd_boolean _bfd_elf_hash_symbol (struct elf_link_hash_entry *); ++ + extern bfd_boolean _bfd_elf_add_default_symbol + (bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, + const char *, Elf_Internal_Sym *, asection **, bfd_vma *, +Index: gdb-6.5/bfd/elf64-x86-64.c +=================================================================== +--- gdb-6.5.orig/bfd/elf64-x86-64.c 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/bfd/elf64-x86-64.c 2006-07-14 01:31:26.000000000 -0300 +@@ -3614,6 +3614,19 @@ elf64_x86_64_additional_program_headers + return count; + } + ++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ ++static bfd_boolean ++elf64_x86_64_hash_symbol (struct elf_link_hash_entry *h) ++{ ++ if (h->plt.offset != (bfd_vma) -1 ++ && !h->def_regular ++ && !h->pointer_equality_needed) ++ return FALSE; ++ ++ return _bfd_elf_hash_symbol (h); ++} ++ + static const struct bfd_elf_special_section + elf64_x86_64_special_sections[]= + { +@@ -3685,5 +3698,7 @@ static const struct bfd_elf_special_sect + elf64_x86_64_special_sections + #define elf_backend_additional_program_headers \ + elf64_x86_64_additional_program_headers ++#define elf_backend_hash_symbol \ ++ elf64_x86_64_hash_symbol + + #include "elf64-target.h" +Index: gdb-6.5/bfd/elf.c +=================================================================== +--- gdb-6.5.orig/bfd/elf.c 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/bfd/elf.c 2006-07-14 01:31:26.000000000 -0300 +@@ -206,6 +206,21 @@ bfd_elf_hash (const char *namearg) + return h & 0xffffffff; + } + ++/* DT_GNU_HASH hash function. Do not change this function; you will ++ cause invalid hash tables to be generated. */ ++ ++unsigned long ++bfd_elf_gnu_hash (const char *namearg) ++{ ++ const unsigned char *name = (const unsigned char *) namearg; ++ unsigned long h = 5381; ++ unsigned char ch; ++ ++ while ((ch = *name++) != '\0') ++ h = (h << 5) + h + ch; ++ return h & 0xffffffff; ++} ++ + bfd_boolean + bfd_elf_mkobject (bfd *abfd) + { +@@ -1239,6 +1254,7 @@ _bfd_elf_print_private_bfd_data (bfd *ab + case DT_AUXILIARY: name = "AUXILIARY"; stringp = TRUE; break; + case DT_USED: name = "USED"; break; + case DT_FILTER: name = "FILTER"; stringp = TRUE; break; ++ case DT_GNU_HASH: name = "GNU_HASH"; break; + } + + fprintf (f, " %-11s ", name); +@@ -1822,6 +1838,7 @@ bfd_section_from_shdr (bfd *abfd, unsign + case SHT_FINI_ARRAY: /* .fini_array section. */ + case SHT_PREINIT_ARRAY: /* .preinit_array section. */ + case SHT_GNU_LIBLIST: /* .gnu.liblist section. */ ++ case SHT_GNU_HASH: /* .gnu.hash section. */ + return _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex); + + case SHT_DYNAMIC: /* Dynamic linking information. */ +@@ -2294,6 +2311,7 @@ static const struct bfd_elf_special_sect + { ".gnu.version_r", 14, 0, SHT_GNU_verneed, 0 }, + { ".gnu.liblist", 12, 0, SHT_GNU_LIBLIST, SHF_ALLOC }, + { ".gnu.conflict", 13, 0, SHT_RELA, SHF_ALLOC }, ++ { ".gnu.hash", 9, 0, SHT_GNU_HASH, SHF_ALLOC }, + { NULL, 0, 0, 0, 0 } + }; + +@@ -2810,6 +2828,10 @@ elf_fake_sections (bfd *abfd, asection * + case SHT_GROUP: + this_hdr->sh_entsize = 4; + break; ++ ++ case SHT_GNU_HASH: ++ this_hdr->sh_entsize = bed->s->arch_size == 64 ? 0 : 4; ++ break; + } + + if ((asect->flags & SEC_ALLOC) != 0) +@@ -3255,6 +3277,7 @@ assign_section_numbers (bfd *abfd, struc + break; + + case SHT_HASH: ++ case SHT_GNU_HASH: + case SHT_GNU_versym: + /* sh_link is the section header index of the symbol table + this hash table or version table is for. */ +Index: gdb-6.5/bfd/elf32-i386.c +=================================================================== +--- gdb-6.5.orig/bfd/elf32-i386.c 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/bfd/elf32-i386.c 2006-07-14 01:31:26.000000000 -0300 +@@ -3872,6 +3872,18 @@ elf_i386_plt_sym_val (bfd_vma i, const a + return plt->vma + (i + 1) * PLT_ENTRY_SIZE; + } + ++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ ++static bfd_boolean ++elf_i386_hash_symbol (struct elf_link_hash_entry *h) ++{ ++ if (h->plt.offset != (bfd_vma) -1 ++ && !h->def_regular ++ && !h->pointer_equality_needed) ++ return FALSE; ++ ++ return _bfd_elf_hash_symbol (h); ++} + + #define TARGET_LITTLE_SYM bfd_elf32_i386_vec + #define TARGET_LITTLE_NAME "elf32-i386" +@@ -3912,6 +3924,7 @@ elf_i386_plt_sym_val (bfd_vma i, const a + #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections + #define elf_backend_always_size_sections elf_i386_always_size_sections + #define elf_backend_plt_sym_val elf_i386_plt_sym_val ++#define elf_backend_hash_symbol elf_i386_hash_symbol + + #include "elf32-target.h" + +Index: gdb-6.5/bfd/elflink.c +=================================================================== +--- gdb-6.5.orig/bfd/elflink.c 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/bfd/elflink.c 2006-07-14 01:31:26.000000000 -0300 +@@ -240,12 +240,30 @@ _bfd_elf_link_create_dynamic_sections (b + if (!_bfd_elf_define_linkage_sym (abfd, info, s, "_DYNAMIC")) + return FALSE; + +- s = bfd_make_section_with_flags (abfd, ".hash", +- flags | SEC_READONLY); +- if (s == NULL +- || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) +- return FALSE; +- elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; ++ if (info->emit_hash) ++ { ++ s = bfd_make_section_with_flags (abfd, ".hash", flags | SEC_READONLY); ++ if (s == NULL ++ || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) ++ return FALSE; ++ elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; ++ } ++ ++ if (info->emit_gnu_hash) ++ { ++ s = bfd_make_section_with_flags (abfd, ".gnu.hash", ++ flags | SEC_READONLY); ++ if (s == NULL ++ || ! bfd_set_section_alignment (abfd, s, bed->s->log_file_align)) ++ return FALSE; ++ /* For 64-bit ELF, .gnu.hash is a non-uniform entity size section: ++ 4 32-bit words followed by variable count of 64-bit words, then ++ variable count of 32-bit words. */ ++ if (bed->s->arch_size == 64) ++ elf_section_data (s)->this_hdr.sh_entsize = 0; ++ else ++ elf_section_data (s)->this_hdr.sh_entsize = 4; ++ } + + /* Let the backend create the rest of the sections. This lets the + backend set the right flags. The backend will normally create +@@ -4795,6 +4813,131 @@ elf_collect_hash_codes (struct elf_link_ + return TRUE; + } + ++struct collect_gnu_hash_codes ++{ ++ bfd *output_bfd; ++ const struct elf_backend_data *bed; ++ unsigned long int nsyms; ++ unsigned long int maskbits; ++ unsigned long int *hashcodes; ++ unsigned long int *hashval; ++ unsigned long int *indx; ++ unsigned long int *counts; ++ bfd_vma *bitmask; ++ bfd_byte *contents; ++ long int min_dynindx; ++ unsigned long int bucketcount; ++ unsigned long int symindx; ++ long int local_indx; ++ long int shift1, shift2; ++ unsigned long int mask; ++}; ++ ++/* This function will be called though elf_link_hash_traverse to store ++ all hash value of the exported symbols in an array. */ ++ ++static bfd_boolean ++elf_collect_gnu_hash_codes (struct elf_link_hash_entry *h, void *data) ++{ ++ struct collect_gnu_hash_codes *s = data; ++ const char *name; ++ char *p; ++ unsigned long ha; ++ char *alc = NULL; ++ ++ if (h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ /* Ignore indirect symbols. These are added by the versioning code. */ ++ if (h->dynindx == -1) ++ return TRUE; ++ ++ /* Ignore also local symbols and undefined symbols. */ ++ if (! (*s->bed->elf_hash_symbol) (h)) ++ return TRUE; ++ ++ name = h->root.root.string; ++ p = strchr (name, ELF_VER_CHR); ++ if (p != NULL) ++ { ++ alc = bfd_malloc (p - name + 1); ++ memcpy (alc, name, p - name); ++ alc[p - name] = '\0'; ++ name = alc; ++ } ++ ++ /* Compute the hash value. */ ++ ha = bfd_elf_gnu_hash (name); ++ ++ /* Store the found hash value in the array for compute_bucket_count, ++ and also for .dynsym reordering purposes. */ ++ s->hashcodes[s->nsyms] = ha; ++ s->hashval[h->dynindx] = ha; ++ ++s->nsyms; ++ if (s->min_dynindx < 0 || s->min_dynindx > h->dynindx) ++ s->min_dynindx = h->dynindx; ++ ++ if (alc != NULL) ++ free (alc); ++ ++ return TRUE; ++} ++ ++/* This function will be called though elf_link_hash_traverse to do ++ final dynaminc symbol renumbering. */ ++ ++static bfd_boolean ++elf_renumber_gnu_hash_syms (struct elf_link_hash_entry *h, void *data) ++{ ++ struct collect_gnu_hash_codes *s = data; ++ unsigned long int bucket; ++ unsigned long int val; ++ ++ if (h->root.type == bfd_link_hash_warning) ++ h = (struct elf_link_hash_entry *) h->root.u.i.link; ++ ++ /* Ignore indirect symbols. */ ++ if (h->dynindx == -1) ++ return TRUE; ++ ++ /* Ignore also local symbols and undefined symbols. */ ++ if (! (*s->bed->elf_hash_symbol) (h)) ++ { ++ if (h->dynindx >= s->min_dynindx) ++ h->dynindx = s->local_indx++; ++ return TRUE; ++ } ++ ++ bucket = s->hashval[h->dynindx] % s->bucketcount; ++ val = (s->hashval[h->dynindx] >> s->shift1) ++ & ((s->maskbits >> s->shift1) - 1); ++ s->bitmask[val] |= ((bfd_vma) 1) << (s->hashval[h->dynindx] & s->mask); ++ s->bitmask[val] ++ |= ((bfd_vma) 1) << ((s->hashval[h->dynindx] >> s->shift2) & s->mask); ++ val = s->hashval[h->dynindx] & ~(unsigned long int) 1; ++ if (s->counts[bucket] == 1) ++ /* Last element terminates the chain. */ ++ val |= 1; ++ bfd_put_32 (s->output_bfd, val, ++ s->contents + (s->indx[bucket] - s->symindx) * 4); ++ --s->counts[bucket]; ++ h->dynindx = s->indx[bucket]++; ++ return TRUE; ++} ++ ++/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ ++ ++bfd_boolean ++_bfd_elf_hash_symbol (struct elf_link_hash_entry *h) ++{ ++ return !(h->forced_local ++ || h->root.type == bfd_link_hash_undefined ++ || h->root.type == bfd_link_hash_undefweak ++ || ((h->root.type == bfd_link_hash_defined ++ || h->root.type == bfd_link_hash_defweak) ++ && h->root.u.def.section->output_section == NULL)); ++} ++ + /* Array used to determine the number of hash table buckets to use + based on the number of symbols there are. If there are fewer than + 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 buckets, +@@ -4816,42 +4959,26 @@ static const size_t elf_buckets[] = + Therefore the result is always a good payoff between few collisions + (= short chain lengths) and table size. */ + static size_t +-compute_bucket_count (struct bfd_link_info *info) ++compute_bucket_count (struct bfd_link_info *info, unsigned long int *hashcodes, ++ unsigned long int nsyms, int gnu_hash) + { + size_t dynsymcount = elf_hash_table (info)->dynsymcount; + size_t best_size = 0; +- unsigned long int *hashcodes; +- unsigned long int *hashcodesp; + unsigned long int i; + bfd_size_type amt; + +- /* Compute the hash values for all exported symbols. At the same +- time store the values in an array so that we could use them for +- optimizations. */ +- amt = dynsymcount; +- amt *= sizeof (unsigned long int); +- hashcodes = bfd_malloc (amt); +- if (hashcodes == NULL) +- return 0; +- hashcodesp = hashcodes; +- +- /* Put all hash values in HASHCODES. */ +- elf_link_hash_traverse (elf_hash_table (info), +- elf_collect_hash_codes, &hashcodesp); +- + /* We have a problem here. The following code to optimize the table + size requires an integer type with more the 32 bits. If + BFD_HOST_U_64_BIT is set we know about such a type. */ + #ifdef BFD_HOST_U_64_BIT + if (info->optimize) + { +- unsigned long int nsyms = hashcodesp - hashcodes; + size_t minsize; + size_t maxsize; + BFD_HOST_U_64_BIT best_chlen = ~((BFD_HOST_U_64_BIT) 0); +- unsigned long int *counts ; + bfd *dynobj = elf_hash_table (info)->dynobj; + const struct elf_backend_data *bed = get_elf_backend_data (dynobj); ++ unsigned long int *counts; + + /* Possible optimization parameters: if we have NSYMS symbols we say + that the hashing table must at least have NSYMS/4 and at most +@@ -4860,6 +4987,13 @@ compute_bucket_count (struct bfd_link_in + if (minsize == 0) + minsize = 1; + best_size = maxsize = nsyms * 2; ++ if (gnu_hash) ++ { ++ if (minsize < 2) ++ minsize = 2; ++ if ((best_size & 31) == 0) ++ ++best_size; ++ } + + /* Create array where we count the collisions in. We must use bfd_malloc + since the size could be large. */ +@@ -4867,10 +5001,7 @@ compute_bucket_count (struct bfd_link_in + amt *= sizeof (unsigned long int); + counts = bfd_malloc (amt); + if (counts == NULL) +- { +- free (hashcodes); +- return 0; +- } ++ return 0; + + /* Compute the "optimal" size for the hash table. The criteria is a + minimal chain length. The minor criteria is (of course) the size +@@ -4882,6 +5013,9 @@ compute_bucket_count (struct bfd_link_in + unsigned long int j; + unsigned long int fact; + ++ if (gnu_hash && (i & 31) == 0) ++ continue; ++ + memset (counts, '\0', i * sizeof (unsigned long int)); + + /* Determine how often each hash bucket is used. */ +@@ -4897,9 +5031,9 @@ compute_bucket_count (struct bfd_link_in + # define BFD_TARGET_PAGESIZE (4096) + # endif + +- /* We in any case need 2 + NSYMS entries for the size values and +- the chains. */ +- max = (2 + nsyms) * (bed->s->arch_size / 8); ++ /* We in any case need 2 + DYNSYMCOUNT entries for the size values ++ and the chains. */ ++ max = (2 + dynsymcount) * bed->s->sizeof_hash_entry; + + # if 1 + /* Variant 1: optimize for short chains. We add the squares +@@ -4909,7 +5043,7 @@ compute_bucket_count (struct bfd_link_in + max += counts[j] * counts[j]; + + /* This adds penalties for the overall size of the table. */ +- fact = i / (BFD_TARGET_PAGESIZE / (bed->s->arch_size / 8)) + 1; ++ fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1; + max *= fact * fact; + # else + /* Variant 2: Optimize a lot more for small table. Here we +@@ -4920,7 +5054,7 @@ compute_bucket_count (struct bfd_link_in + + /* The overall size of the table is considered, but not as + strong as in variant 1, where it is squared. */ +- fact = i / (BFD_TARGET_PAGESIZE / (bed->s->arch_size / 8)) + 1; ++ fact = i / (BFD_TARGET_PAGESIZE / bed->s->sizeof_hash_entry) + 1; + max *= fact; + # endif + +@@ -4943,14 +5077,13 @@ compute_bucket_count (struct bfd_link_in + for (i = 0; elf_buckets[i] != 0; i++) + { + best_size = elf_buckets[i]; +- if (dynsymcount < elf_buckets[i + 1]) ++ if (nsyms < elf_buckets[i + 1]) + break; + } ++ if (gnu_hash && best_size < 2) ++ best_size = 2; + } + +- /* Free the arrays we needed. */ +- free (hashcodes); +- + return best_size; + } + +@@ -5308,7 +5441,10 @@ bfd_elf_size_dynamic_sections (bfd *outp + bfd_size_type strsize; + + strsize = _bfd_elf_strtab_size (elf_hash_table (info)->dynstr); +- if (!_bfd_elf_add_dynamic_entry (info, DT_HASH, 0) ++ if ((info->emit_hash ++ && !_bfd_elf_add_dynamic_entry (info, DT_HASH, 0)) ++ || (info->emit_gnu_hash ++ && !_bfd_elf_add_dynamic_entry (info, DT_GNU_HASH, 0)) + || !_bfd_elf_add_dynamic_entry (info, DT_STRTAB, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_SYMTAB, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_STRSZ, strsize) +@@ -5710,8 +5846,6 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *ou + asection *s; + bfd_size_type dynsymcount; + unsigned long section_sym_count; +- size_t bucketcount = 0; +- size_t hash_entry_size; + unsigned int dtagcount; + + dynobj = elf_hash_table (info)->dynobj; +@@ -5762,23 +5896,215 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *ou + memset (s->contents, 0, section_sym_count * bed->s->sizeof_sym); + } + ++ elf_hash_table (info)->bucketcount = 0; ++ + /* Compute the size of the hashing table. As a side effect this + computes the hash values for all the names we export. */ +- bucketcount = compute_bucket_count (info); ++ if (info->emit_hash) ++ { ++ unsigned long int *hashcodes; ++ unsigned long int *hashcodesp; ++ bfd_size_type amt; ++ unsigned long int nsyms; ++ size_t bucketcount; ++ size_t hash_entry_size; ++ ++ /* Compute the hash values for all exported symbols. At the same ++ time store the values in an array so that we could use them for ++ optimizations. */ ++ amt = dynsymcount * sizeof (unsigned long int); ++ hashcodes = bfd_malloc (amt); ++ if (hashcodes == NULL) ++ return FALSE; ++ hashcodesp = hashcodes; + +- s = bfd_get_section_by_name (dynobj, ".hash"); +- BFD_ASSERT (s != NULL); +- hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; +- s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); +- s->contents = bfd_zalloc (output_bfd, s->size); +- if (s->contents == NULL) +- return FALSE; ++ /* Put all hash values in HASHCODES. */ ++ elf_link_hash_traverse (elf_hash_table (info), ++ elf_collect_hash_codes, &hashcodesp); + +- bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); +- bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, +- s->contents + hash_entry_size); ++ nsyms = hashcodesp - hashcodes; ++ bucketcount ++ = compute_bucket_count (info, hashcodes, nsyms, 0); ++ free (hashcodes); + +- elf_hash_table (info)->bucketcount = bucketcount; ++ if (bucketcount == 0) ++ return FALSE; ++ ++ elf_hash_table (info)->bucketcount = bucketcount; ++ ++ s = bfd_get_section_by_name (dynobj, ".hash"); ++ BFD_ASSERT (s != NULL); ++ hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; ++ s->size = ((2 + bucketcount + dynsymcount) * hash_entry_size); ++ s->contents = bfd_zalloc (output_bfd, s->size); ++ if (s->contents == NULL) ++ return FALSE; ++ ++ bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); ++ bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, ++ s->contents + hash_entry_size); ++ } ++ ++ if (info->emit_gnu_hash) ++ { ++ size_t i, cnt; ++ unsigned char *contents; ++ struct collect_gnu_hash_codes cinfo; ++ bfd_size_type amt; ++ size_t bucketcount; ++ ++ memset (&cinfo, 0, sizeof (cinfo)); ++ ++ /* Compute the hash values for all exported symbols. At the same ++ time store the values in an array so that we could use them for ++ optimizations. */ ++ amt = dynsymcount * 2 * sizeof (unsigned long int); ++ cinfo.hashcodes = bfd_malloc (amt); ++ if (cinfo.hashcodes == NULL) ++ return FALSE; ++ ++ cinfo.hashval = cinfo.hashcodes + dynsymcount; ++ cinfo.min_dynindx = -1; ++ cinfo.output_bfd = output_bfd; ++ cinfo.bed = bed; ++ ++ /* Put all hash values in HASHCODES. */ ++ elf_link_hash_traverse (elf_hash_table (info), ++ elf_collect_gnu_hash_codes, &cinfo); ++ ++ bucketcount ++ = compute_bucket_count (info, cinfo.hashcodes, cinfo.nsyms, 1); ++ ++ if (bucketcount == 0) ++ { ++ free (cinfo.hashcodes); ++ return FALSE; ++ } ++ ++ s = bfd_get_section_by_name (dynobj, ".gnu.hash"); ++ BFD_ASSERT (s != NULL); ++ ++ if (cinfo.nsyms == 0) ++ { ++ /* Empty .gnu.hash section is special. */ ++ BFD_ASSERT (cinfo.min_dynindx == -1); ++ free (cinfo.hashcodes); ++ s->size = 5 * 4 + bed->s->arch_size / 8; ++ contents = bfd_zalloc (output_bfd, s->size); ++ if (contents == NULL) ++ return FALSE; ++ s->contents = contents; ++ /* 1 empty bucket. */ ++ bfd_put_32 (output_bfd, 1, contents); ++ /* SYMIDX above the special symbol 0. */ ++ bfd_put_32 (output_bfd, 1, contents + 4); ++ /* Just one word for bitmask. */ ++ bfd_put_32 (output_bfd, 1, contents + 8); ++ /* Only hash fn bloom filter. */ ++ bfd_put_32 (output_bfd, 0, contents + 12); ++ /* No hashes are valid - empty bitmask. */ ++ bfd_put (bed->s->arch_size, output_bfd, 0, contents + 16); ++ /* No hashes in the only bucket. */ ++ bfd_put_32 (output_bfd, 0, ++ contents + 16 + bed->s->arch_size / 8); ++ } ++ else ++ { ++ BFD_ASSERT (cinfo.min_dynindx != -1); ++ unsigned long int maskwords, maskbitslog2; ++ ++ maskbitslog2 = bfd_log2 (cinfo.nsyms) + 1; ++ if (maskbitslog2 < 3) ++ maskbitslog2 = 5; ++ else if ((1 << (maskbitslog2 - 2)) & cinfo.nsyms) ++ maskbitslog2 = maskbitslog2 + 3; ++ else ++ maskbitslog2 = maskbitslog2 + 2; ++ if (bed->s->arch_size == 64) ++ { ++ if (maskbitslog2 == 5) ++ maskbitslog2 = 6; ++ cinfo.shift1 = 6; ++ } ++ else ++ cinfo.shift1 = 5; ++ cinfo.mask = (1 << cinfo.shift1) - 1; ++ cinfo.shift2 = maskbitslog2 + cinfo.shift1; ++ cinfo.maskbits = 1 << maskbitslog2; ++ maskwords = 1 << (maskbitslog2 - cinfo.shift1); ++ amt = bucketcount * sizeof (unsigned long int) * 2; ++ amt += maskwords * sizeof (bfd_vma); ++ cinfo.bitmask = bfd_malloc (amt); ++ if (cinfo.bitmask == NULL) ++ { ++ free (cinfo.hashcodes); ++ return FALSE; ++ } ++ ++ cinfo.counts = (void *) (cinfo.bitmask + maskwords); ++ cinfo.indx = cinfo.counts + bucketcount; ++ cinfo.symindx = dynsymcount - cinfo.nsyms; ++ memset (cinfo.bitmask, 0, maskwords * sizeof (bfd_vma)); ++ ++ /* Determine how often each hash bucket is used. */ ++ memset (cinfo.counts, 0, bucketcount * sizeof (cinfo.counts[0])); ++ for (i = 0; i < cinfo.nsyms; ++i) ++ ++cinfo.counts[cinfo.hashcodes[i] % bucketcount]; ++ ++ for (i = 0, cnt = cinfo.symindx; i < bucketcount; ++i) ++ if (cinfo.counts[i] != 0) ++ { ++ cinfo.indx[i] = cnt; ++ cnt += cinfo.counts[i]; ++ } ++ BFD_ASSERT (cnt == dynsymcount); ++ cinfo.bucketcount = bucketcount; ++ cinfo.local_indx = cinfo.min_dynindx; ++ ++ s->size = (4 + bucketcount + cinfo.nsyms) * 4; ++ s->size += cinfo.maskbits / 8; ++ contents = bfd_zalloc (output_bfd, s->size); ++ if (contents == NULL) ++ { ++ free (cinfo.bitmask); ++ free (cinfo.hashcodes); ++ return FALSE; ++ } ++ ++ s->contents = contents; ++ bfd_put_32 (output_bfd, bucketcount, contents); ++ bfd_put_32 (output_bfd, cinfo.symindx, contents + 4); ++ bfd_put_32 (output_bfd, maskwords, contents + 8); ++ bfd_put_32 (output_bfd, cinfo.shift2, contents + 12); ++ contents += 16 + cinfo.maskbits / 8; ++ ++ for (i = 0; i < bucketcount; ++i) ++ { ++ if (cinfo.counts[i] == 0) ++ bfd_put_32 (output_bfd, 0, contents); ++ else ++ bfd_put_32 (output_bfd, cinfo.indx[i], contents); ++ contents += 4; ++ } ++ ++ cinfo.contents = contents; ++ ++ /* Renumber dynamic symbols, populate .gnu.hash section. */ ++ elf_link_hash_traverse (elf_hash_table (info), ++ elf_renumber_gnu_hash_syms, &cinfo); ++ ++ contents = s->contents + 16; ++ for (i = 0; i < maskwords; ++i) ++ { ++ bfd_put (bed->s->arch_size, output_bfd, cinfo.bitmask[i], ++ contents); ++ contents += bed->s->arch_size / 8; ++ } ++ ++ free (cinfo.bitmask); ++ free (cinfo.hashcodes); ++ } ++ } + + s = bfd_get_section_by_name (dynobj, ".dynstr"); + BFD_ASSERT (s != NULL); +@@ -6647,9 +6973,6 @@ elf_link_output_extsym (struct elf_link_ + { + size_t bucketcount; + size_t bucket; +- size_t hash_entry_size; +- bfd_byte *bucketpos; +- bfd_vma chain; + bfd_byte *esym; + + sym.st_name = h->dynstr_index; +@@ -6663,15 +6986,23 @@ elf_link_output_extsym (struct elf_link_ + + bucketcount = elf_hash_table (finfo->info)->bucketcount; + bucket = h->u.elf_hash_value % bucketcount; +- hash_entry_size +- = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; +- bucketpos = ((bfd_byte *) finfo->hash_sec->contents +- + (bucket + 2) * hash_entry_size); +- chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); +- bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos); +- bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, +- ((bfd_byte *) finfo->hash_sec->contents +- + (bucketcount + 2 + h->dynindx) * hash_entry_size)); ++ ++ if (finfo->hash_sec != NULL) ++ { ++ size_t hash_entry_size; ++ bfd_byte *bucketpos; ++ bfd_vma chain; ++ ++ hash_entry_size ++ = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; ++ bucketpos = ((bfd_byte *) finfo->hash_sec->contents ++ + (bucket + 2) * hash_entry_size); ++ chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); ++ bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos); ++ bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, ++ ((bfd_byte *) finfo->hash_sec->contents ++ + (bucketcount + 2 + h->dynindx) * hash_entry_size)); ++ } + + if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) + { +@@ -7845,7 +8176,7 @@ bfd_elf_final_link (bfd *abfd, struct bf + { + finfo.dynsym_sec = bfd_get_section_by_name (dynobj, ".dynsym"); + finfo.hash_sec = bfd_get_section_by_name (dynobj, ".hash"); +- BFD_ASSERT (finfo.dynsym_sec != NULL && finfo.hash_sec != NULL); ++ BFD_ASSERT (finfo.dynsym_sec != NULL); + finfo.symver_sec = bfd_get_section_by_name (dynobj, ".gnu.version"); + /* Note that it is OK if symver_sec is NULL. */ + } +@@ -8591,6 +8922,9 @@ bfd_elf_final_link (bfd *abfd, struct bf + case DT_HASH: + name = ".hash"; + goto get_vma; ++ case DT_GNU_HASH: ++ name = ".gnu.hash"; ++ goto get_vma; + case DT_STRTAB: + name = ".dynstr"; + goto get_vma; +Index: gdb-6.5/bfd/elfxx-target.h +=================================================================== +--- gdb-6.5.orig/bfd/elfxx-target.h 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/bfd/elfxx-target.h 2006-07-14 01:31:26.000000000 -0300 +@@ -553,6 +553,10 @@ + #define elf_backend_merge_symbol NULL + #endif + ++#ifndef elf_backend_hash_symbol ++#define elf_backend_hash_symbol _bfd_elf_hash_symbol ++#endif ++ + extern const struct elf_size_info _bfd_elfNN_size_info; + + #ifndef INCLUDED_TARGET_FILE +@@ -630,6 +634,7 @@ static const struct elf_backend_data elf + elf_backend_common_section_index, + elf_backend_common_section, + elf_backend_merge_symbol, ++ elf_backend_hash_symbol, + elf_backend_link_order_error_handler, + elf_backend_relplt_name, + ELF_MACHINE_ALT1, +Index: gdb-6.5/include/elf/common.h +=================================================================== +--- gdb-6.5.orig/include/elf/common.h 2006-07-14 01:30:51.000000000 -0300 ++++ gdb-6.5/include/elf/common.h 2006-07-14 01:31:26.000000000 -0300 +@@ -338,6 +338,7 @@ + #define SHT_LOOS 0x60000000 /* First of OS specific semantics */ + #define SHT_HIOS 0x6fffffff /* Last of OS specific semantics */ + ++#define SHT_GNU_HASH 0x6ffffff6 /* GNU style symbol hash table */ + #define SHT_GNU_LIBLIST 0x6ffffff7 /* List of prelink dependencies */ + + /* The next three section types are defined by Solaris, and are named +@@ -577,6 +578,7 @@ + #define DT_VALRNGHI 0x6ffffdff + + #define DT_ADDRRNGLO 0x6ffffe00 ++#define DT_GNU_HASH 0x6ffffef5 + #define DT_TLSDESC_PLT 0x6ffffef6 + #define DT_TLSDESC_GOT 0x6ffffef7 + #define DT_GNU_CONFLICT 0x6ffffef8 +Index: gdb-6.5/include/bfdlink.h +=================================================================== +--- gdb-6.5.orig/include/bfdlink.h 2006-04-06 15:52:45.000000000 -0300 ++++ gdb-6.5/include/bfdlink.h 2006-07-14 01:31:26.000000000 -0300 +@@ -324,6 +324,12 @@ struct bfd_link_info + /* TRUE if unreferenced sections should be removed. */ + unsigned int gc_sections: 1; + ++ /* TRUE if .hash section should be created. */ ++ unsigned int emit_hash: 1; ++ ++ /* TRUE if .gnu.hash section should be created. */ ++ unsigned int emit_gnu_hash: 1; ++ + /* What to do with unresolved symbols in an object file. + When producing executables the default is GENERATE_ERROR. + When producing shared libraries the default is IGNORE. The