From: Jakub Jelinek Date: Mon, 10 Jul 2006 21:40:25 +0000 (+0000) Subject: include/ X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fdc90cb46b0f96dd4444ec3d126c87de75fb6e6b;p=binutils-gdb.git 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. ld/ * scripttempl/elf.sc: Add .gnu.hash section. * emultempl/elf32.em (OPTION_HASH_STYLE): Define. (gld${EMULATION_NAME}_add_options): Register --hash-style option. (gld${EMULATION_NAME}_handle_option): Handle it. (gld${EMULATION_NAME}_list_options): Document it. * ldmain.c (main): Initialize emit_hash and emit_gnu_hash. * ld.texinfo: Document --hash-style option. 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. binutils/ * readelf.c (get_dynamic_type): Handle DT_GNU_HASH. (get_section_type_name): Handle SHT_GNU_HASH. (dynamic_info_DT_GNU_HASH): New variable. (process_dynamic_section): Handle DT_GNU_HASH. (process_symbol_table): Print also DT_GNU_HASH histogram. ld/testsuite/ * ld-powerpc/tlsso32.r: Adjust. * ld-powerpc/tlsso32.d: Adjust. * ld-powerpc/tlsso32.g: Adjust. * ld-powerpc/tlsso.r: Adjust. * ld-powerpc/tlsso.g: Adjust. * ld-powerpc/tlstocso.g: Adjust. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 55b13326fbf..5603c24f77f 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,38 @@ +2006-07-10 Jakub Jelinek + + * 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. + 2006-07-05 Nick Clifton PR ld/2659 diff --git a/bfd/elf-bfd.h b/bfd/elf-bfd.h index 95686d3d502..e7d3b188804 100644 --- a/bfd/elf-bfd.h +++ b/bfd/elf-bfd.h @@ -1038,6 +1038,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; @@ -1481,6 +1484,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 **); @@ -1651,6 +1656,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 *, diff --git a/bfd/elf.c b/bfd/elf.c index abb50829e63..85f9e0f1327 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -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) { @@ -1240,6 +1255,7 @@ _bfd_elf_print_private_bfd_data (bfd *abfd, void *farg) 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); @@ -1824,6 +1840,7 @@ bfd_section_from_shdr (bfd *abfd, unsigned int shindex) 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. */ @@ -2296,6 +2313,7 @@ static const struct bfd_elf_special_section special_sections_g[] = { ".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 } }; @@ -2812,6 +2830,10 @@ elf_fake_sections (bfd *abfd, asection *asect, void *failedptrarg) 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) @@ -3257,6 +3279,7 @@ assign_section_numbers (bfd *abfd, struct bfd_link_info *link_info) 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. */ diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 35b0525f296..ab02b2cad2c 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -3839,6 +3839,18 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt, 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" @@ -3879,6 +3891,7 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt, #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" diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index b9cf0a33318..6ca622a0d23 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -3620,6 +3620,19 @@ elf64_x86_64_additional_program_headers (bfd *abfd, 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[]= { @@ -3693,5 +3706,7 @@ static const struct bfd_elf_special_section 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" diff --git a/bfd/elflink.c b/bfd/elflink.c index 4b20749e11e..9d65b5fc9d8 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -240,12 +240,30 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) 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 @@ -4811,6 +4829,131 @@ elf_collect_hash_codes (struct elf_link_hash_entry *h, void *data) 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, @@ -4832,42 +4975,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 @@ -4876,6 +5003,13 @@ compute_bucket_count (struct bfd_link_info *info) 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. */ @@ -4883,10 +5017,7 @@ compute_bucket_count (struct bfd_link_info *info) 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 @@ -4898,6 +5029,9 @@ compute_bucket_count (struct bfd_link_info *info) 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. */ @@ -4913,9 +5047,9 @@ compute_bucket_count (struct bfd_link_info *info) # 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 @@ -4925,7 +5059,7 @@ compute_bucket_count (struct bfd_link_info *info) 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 @@ -4936,7 +5070,7 @@ compute_bucket_count (struct bfd_link_info *info) /* 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 @@ -4959,14 +5093,13 @@ compute_bucket_count (struct bfd_link_info *info) 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; } @@ -5324,7 +5457,10 @@ bfd_elf_size_dynamic_sections (bfd *output_bfd, 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) @@ -5726,8 +5862,6 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) 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; @@ -5778,23 +5912,215 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info) 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); + + nsyms = hashcodesp - hashcodes; + bucketcount + = compute_bucket_count (info, hashcodes, nsyms, 0); + free (hashcodes); + + if (bucketcount == 0) + 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); + elf_hash_table (info)->bucketcount = bucketcount; - 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); @@ -6663,9 +6989,6 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) { 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; @@ -6679,15 +7002,23 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data) 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) { @@ -7861,7 +8192,7 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) { 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. */ } @@ -8621,6 +8952,9 @@ bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) 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; diff --git a/bfd/elfxx-target.h b/bfd/elfxx-target.h index 38aa3737f82..fed6ea901e4 100644 --- a/bfd/elfxx-target.h +++ b/bfd/elfxx-target.h @@ -563,6 +563,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 @@ -643,6 +647,7 @@ static struct elf_backend_data elfNN_bed = 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, diff --git a/binutils/ChangeLog b/binutils/ChangeLog index c7e4b3f5947..8508a18c8ab 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,11 @@ +2006-07-10 Jakub Jelinek + + * readelf.c (get_dynamic_type): Handle DT_GNU_HASH. + (get_section_type_name): Handle SHT_GNU_HASH. + (dynamic_info_DT_GNU_HASH): New variable. + (process_dynamic_section): Handle DT_GNU_HASH. + (process_symbol_table): Print also DT_GNU_HASH histogram. + 2006-07-06 Mohammed Adnène Trojette PR binutils/2879 diff --git a/binutils/readelf.c b/binutils/readelf.c index 8550ce4c584..55f5a434add 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -135,6 +135,7 @@ static unsigned long dynamic_syminfo_offset; static unsigned int dynamic_syminfo_nent; static char program_interpreter[64]; static bfd_vma dynamic_info[DT_JMPREL + 1]; +static bfd_vma dynamic_info_DT_GNU_HASH; static bfd_vma version_info[16]; static Elf_Internal_Ehdr elf_header; static Elf_Internal_Shdr *section_headers; @@ -1501,6 +1502,7 @@ get_dynamic_type (unsigned long type) case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; case DT_GNU_LIBLIST: return "GNU_LIBLIST"; case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; + case DT_GNU_HASH: return "GNU_HASH"; default: if ((type >= DT_LOPROC) && (type <= DT_HIPROC)) @@ -2571,6 +2573,7 @@ get_section_type_name (unsigned int sh_type) case SHT_INIT_ARRAY: return "INIT_ARRAY"; case SHT_FINI_ARRAY: return "FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY"; + case SHT_GNU_HASH: return "GNU_HASH"; case SHT_GROUP: return "GROUP"; case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICIES"; case SHT_GNU_verdef: return "VERDEF"; @@ -6245,6 +6248,15 @@ process_dynamic_section (FILE *file) } break; + case DT_GNU_HASH: + dynamic_info_DT_GNU_HASH = entry->d_un.d_val; + if (do_dynamic) + { + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } + break; + default: if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) version_info[DT_VERSIONTAGIDX (entry->d_tag)] = @@ -6920,6 +6932,9 @@ process_symbol_table (FILE *file) bfd_vma nchains = 0; bfd_vma *buckets = NULL; bfd_vma *chains = NULL; + bfd_vma ngnubuckets = 0; + bfd_vma *gnubuckets = NULL; + bfd_vma *gnuchains = NULL; if (! do_syms && !do_histogram) return 1; @@ -7299,6 +7314,166 @@ process_symbol_table (FILE *file) free (chains); } + if (do_histogram && dynamic_info_DT_GNU_HASH) + { + unsigned char nb[16]; + bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords; + unsigned long *lengths; + unsigned long *counts; + unsigned long hn; + unsigned long maxlength = 0; + unsigned long nzero_counts = 0; + unsigned long nsyms = 0; + bfd_vma buckets_vma; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, dynamic_info_DT_GNU_HASH, + sizeof nb)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information")); + return 0; + } + + if (fread (nb, 16, 1, file) != 1) + { + error (_("Failed to read in number of buckets\n")); + return 0; + } + + ngnubuckets = byte_get (nb, 4); + symidx = byte_get (nb + 4, 4); + bitmaskwords = byte_get (nb + 8, 4); + buckets_vma = dynamic_info_DT_GNU_HASH + 16; + if (is_32bit_elf) + buckets_vma += bitmaskwords * 4; + else + buckets_vma += bitmaskwords * 8; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, buckets_vma, 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information")); + return 0; + } + + gnubuckets = get_dynamic_data (file, ngnubuckets, 4); + + if (gnubuckets == NULL) + return 0; + + for (i = 0; i < ngnubuckets; i++) + if (gnubuckets[i] != 0) + { + if (gnubuckets[i] < symidx) + return 0; + + if (maxchain == 0xffffffff || gnubuckets[i] > maxchain) + maxchain = gnubuckets[i]; + } + + if (maxchain == 0xffffffff) + return 0; + + maxchain -= symidx; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, buckets_vma + + 4 * (ngnubuckets + maxchain), 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information")); + return 0; + } + + do + { + if (fread (nb, 4, 1, file) != 1) + { + error (_("Failed to determine last chain length\n")); + return 0; + } + + if (maxchain + 1 == 0) + return 0; + + ++maxchain; + } + while ((byte_get (nb, 4) & 1) == 0); + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information")); + return 0; + } + + gnuchains = get_dynamic_data (file, maxchain, 4); + + if (gnuchains == NULL) + return 0; + + lengths = calloc (ngnubuckets, sizeof (*lengths)); + if (lengths == NULL) + { + error (_("Out of memory")); + return 0; + } + + printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"), + (unsigned long) ngnubuckets); + printf (_(" Length Number %% of total Coverage\n")); + + for (hn = 0; hn < ngnubuckets; ++hn) + if (gnubuckets[hn] != 0) + { + bfd_vma off, length = 1; + + for (off = gnubuckets[hn] - symidx; + (gnuchains[off] & 1) == 0; ++off) + ++length; + lengths[hn] = length; + if (length > maxlength) + maxlength = length; + nsyms += length; + } + + counts = calloc (maxlength + 1, sizeof (*counts)); + if (counts == NULL) + { + error (_("Out of memory")); + return 0; + } + + for (hn = 0; hn < ngnubuckets; ++hn) + ++counts[lengths[hn]]; + + if (ngnubuckets > 0) + { + unsigned long j; + printf (" 0 %-10lu (%5.1f%%)\n", + counts[0], (counts[0] * 100.0) / ngnubuckets); + for (j = 1; j <= maxlength; ++j) + { + nzero_counts += counts[j] * j; + printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", + j, counts[j], (counts[j] * 100.0) / ngnubuckets, + (nzero_counts * 100.0) / nsyms); + } + } + + free (counts); + free (lengths); + free (gnubuckets); + free (gnuchains); + } + return 1; } diff --git a/include/ChangeLog b/include/ChangeLog index 6f695ffc8a9..75f1ed22f05 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,8 @@ +2006-07-10 Jakub Jelinek + + * bfdlink.h (struct bfd_link_info): Add emit_hash and + emit_gnu_hash bitfields. + 2006-04-11 Jim Blandy * libiberty.h (pex_input_file, pex_input_pipe): New declarations. diff --git a/include/bfdlink.h b/include/bfdlink.h index f4b7aa7cfa4..761bd0513e3 100644 --- a/include/bfdlink.h +++ b/include/bfdlink.h @@ -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 diff --git a/include/elf/ChangeLog b/include/elf/ChangeLog index 285457ed91f..f1c15b52c7d 100644 --- a/include/elf/ChangeLog +++ b/include/elf/ChangeLog @@ -1,3 +1,7 @@ +2006-07-10 Jakub Jelinek + + * common.h (SHT_GNU_HASH, DT_GNU_HASH): Define. + 2006-05-31 H.J. Lu * internal.h (ELF_SECTION_SIZE): New. diff --git a/include/elf/common.h b/include/elf/common.h index b11171b56b4..0380a8fd7f9 100644 --- a/include/elf/common.h +++ b/include/elf/common.h @@ -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 diff --git a/ld/ChangeLog b/ld/ChangeLog index 1d1cc1b10e9..24141f654d2 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,13 @@ +2006-07-10 Jakub Jelinek + + * scripttempl/elf.sc: Add .gnu.hash section. + * emultempl/elf32.em (OPTION_HASH_STYLE): Define. + (gld${EMULATION_NAME}_add_options): Register --hash-style option. + (gld${EMULATION_NAME}_handle_option): Handle it. + (gld${EMULATION_NAME}_list_options): Document it. + * ldmain.c (main): Initialize emit_hash and emit_gnu_hash. + * ld.texinfo: Document --hash-style option. + 2006-07-10 Nick Clifton * po/zh_TW.po: New Chinese (traditional) translation. diff --git a/ld/emultempl/elf32.em b/ld/emultempl/elf32.em index 9eb532386db..7ce112a1c16 100644 --- a/ld/emultempl/elf32.em +++ b/ld/emultempl/elf32.em @@ -1719,6 +1719,7 @@ cat >>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c <>e${EMULATION_NAME}.c < + + * ld-powerpc/tlsso32.r: Adjust. + * ld-powerpc/tlsso32.d: Adjust. + * ld-powerpc/tlsso32.g: Adjust. + * ld-powerpc/tlsso.r: Adjust. + * ld-powerpc/tlsso.g: Adjust. + * ld-powerpc/tlstocso.g: Adjust. + 2006-07-05 Thiemo Seufer * ld-mips-elf/multi-got-1.d, ld-mips-elf/tls-multi-got-1.got, diff --git a/ld/testsuite/ld-powerpc/tlsso.g b/ld/testsuite/ld-powerpc/tlsso.g index caef9dd503e..6113155fab9 100644 --- a/ld/testsuite/ld-powerpc/tlsso.g +++ b/ld/testsuite/ld-powerpc/tlsso.g @@ -7,7 +7,7 @@ .*: +file format elf64-powerpc Contents of section \.got: -.* 00000000 000187f0 00000000 00000000 .* +.* 00000000 000187b8 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* diff --git a/ld/testsuite/ld-powerpc/tlsso.r b/ld/testsuite/ld-powerpc/tlsso.r index e0e0f00e48e..db541547b44 100644 --- a/ld/testsuite/ld-powerpc/tlsso.r +++ b/ld/testsuite/ld-powerpc/tlsso.r @@ -49,9 +49,9 @@ Relocation section '\.rela\.dyn' at offset .* contains 16 entries: [0-9a-f ]+R_PPC64_TPREL16 +0+60 le0 \+ 0 [0-9a-f ]+R_PPC64_TPREL16_HA +0+68 le1 \+ 0 [0-9a-f ]+R_PPC64_TPREL16_LO +0+68 le1 \+ 0 -[0-9a-f ]+R_PPC64_TPREL16_DS +0+10668 \.tdata \+ 28 -[0-9a-f ]+R_PPC64_TPREL16_HA +0+10668 \.tdata \+ 30 -[0-9a-f ]+R_PPC64_TPREL16_LO +0+10668 \.tdata \+ 30 +[0-9a-f ]+R_PPC64_TPREL16_DS +0+10630 \.tdata \+ 28 +[0-9a-f ]+R_PPC64_TPREL16_HA +0+10630 \.tdata \+ 30 +[0-9a-f ]+R_PPC64_TPREL16_LO +0+10630 \.tdata \+ 30 [0-9a-f ]+R_PPC64_DTPMOD64 +0+ [0-9a-f ]+R_PPC64_DTPMOD64 +0+ [0-9a-f ]+R_PPC64_DTPREL64 +0+ diff --git a/ld/testsuite/ld-powerpc/tlsso32.d b/ld/testsuite/ld-powerpc/tlsso32.d index 45432db33e3..dafca7d34f6 100644 --- a/ld/testsuite/ld-powerpc/tlsso32.d +++ b/ld/testsuite/ld-powerpc/tlsso32.d @@ -42,5 +42,5 @@ Disassembly of section \.got: .* <\.got>: \.\.\. .*: 4e 80 00 21 blrl -.*: 00 01 04 38 .* +.*: 00 01 04 00 .* \.\.\. diff --git a/ld/testsuite/ld-powerpc/tlsso32.g b/ld/testsuite/ld-powerpc/tlsso32.g index 7014419a691..c097ffa3451 100644 --- a/ld/testsuite/ld-powerpc/tlsso32.g +++ b/ld/testsuite/ld-powerpc/tlsso32.g @@ -9,5 +9,5 @@ Contents of section \.got: .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* -.* 00000000 4e800021 00010438 00000000 .* +.* 00000000 4e800021 00010400 00000000 .* .* 00000000 .* diff --git a/ld/testsuite/ld-powerpc/tlsso32.r b/ld/testsuite/ld-powerpc/tlsso32.r index 7044c356e0a..a0ede5f5bef 100644 --- a/ld/testsuite/ld-powerpc/tlsso32.r +++ b/ld/testsuite/ld-powerpc/tlsso32.r @@ -52,9 +52,9 @@ Relocation section '\.rela\.dyn' at offset 0x[0-9a-f]+ contains 18 entries: [0-9a-f ]+R_PPC_TPREL16 +0+30 +le0 \+ 0 [0-9a-f ]+R_PPC_TPREL16_HA +0+34 +le1 \+ 0 [0-9a-f ]+R_PPC_TPREL16_LO +0+34 +le1 \+ 0 -[0-9a-f ]+R_PPC_TPREL16 +0+1041c +\.tdata \+ 10430 -[0-9a-f ]+R_PPC_TPREL16_HA +0+1041c +\.tdata \+ 10434 -[0-9a-f ]+R_PPC_TPREL16_LO +0+1041c +\.tdata \+ 10434 +[0-9a-f ]+R_PPC_TPREL16 +0+103e4 +\.tdata \+ 103f8 +[0-9a-f ]+R_PPC_TPREL16_HA +0+103e4 +\.tdata \+ 103fc +[0-9a-f ]+R_PPC_TPREL16_LO +0+103e4 +\.tdata \+ 103fc [0-9a-f ]+R_PPC_DTPMOD32 +0+ [0-9a-f ]+R_PPC_DTPREL32 +0+ [0-9a-f ]+R_PPC_DTPMOD32 +0+ diff --git a/ld/testsuite/ld-powerpc/tlstocso.g b/ld/testsuite/ld-powerpc/tlstocso.g index b5d7d647cc2..3d59c435f9d 100644 --- a/ld/testsuite/ld-powerpc/tlstocso.g +++ b/ld/testsuite/ld-powerpc/tlstocso.g @@ -7,7 +7,7 @@ .*: +file format elf64-powerpc Contents of section \.got: -.* 00000000 00018738 00000000 00000000 .* +.* 00000000 00018700 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .* .* 00000000 00000000 00000000 00000000 .*