Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 94929 Details for
Bug 144851
sys-devel/gdb-6.5 - Add .gnu.hash support to (needed for upcoming binutils 2.17.50)
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
gdb 6.5 GNU hash style support
gdb-6.5-bfd-hash-style-20060714.patch (text/plain), 30.10 KB, created by
Christophe Saout
on 2006-08-23 06:09:53 UTC
(
hide
)
Description:
gdb 6.5 GNU hash style support
Filename:
MIME Type:
Creator:
Christophe Saout
Created:
2006-08-23 06:09:53 UTC
Size:
30.10 KB
patch
obsolete
>2006-07-10 Jakub Jelinek <jakub@redhat.com> > >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
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 144851
: 94929