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.
This commit is contained in:
parent
8a112c90fe
commit
fdc90cb46b
25 changed files with 757 additions and 76 deletions
|
@ -1,3 +1,38 @@
|
|||
2006-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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 <nickc@redhat.com>
|
||||
|
||||
PR ld/2659
|
||||
|
|
|
@ -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 *,
|
||||
|
|
23
bfd/elf.c
23
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. */
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
418
bfd/elflink.c
418
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 (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;
|
||||
}
|
||||
|
||||
/* 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,9 +5912,41 @@ 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;
|
||||
|
||||
/* 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;
|
||||
|
||||
elf_hash_table (info)->bucketcount = bucketcount;
|
||||
|
||||
s = bfd_get_section_by_name (dynobj, ".hash");
|
||||
BFD_ASSERT (s != NULL);
|
||||
|
@ -5793,8 +5959,168 @@ bfd_elf_size_dynsym_hash_dynstr (bfd *output_bfd, struct bfd_link_info *info)
|
|||
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;
|
||||
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,6 +7002,13 @@ 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;
|
||||
|
||||
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
|
||||
|
@ -6688,6 +7018,7 @@ elf_link_output_extsym (struct elf_link_hash_entry *h, void *data)
|
|||
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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
2006-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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 <adn@diwi.org>
|
||||
|
||||
PR binutils/2879
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2006-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* bfdlink.h (struct bfd_link_info): Add emit_hash and
|
||||
emit_gnu_hash bitfields.
|
||||
|
||||
2006-04-11 Jim Blandy <jimb@codesourcery.com>
|
||||
|
||||
* libiberty.h (pex_input_file, pex_input_pipe): New declarations.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
2006-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* common.h (SHT_GNU_HASH, DT_GNU_HASH): Define.
|
||||
|
||||
2006-05-31 H.J. Lu <hongjiu.lu@intel.com>
|
||||
|
||||
* internal.h (ELF_SECTION_SIZE): New.
|
||||
|
|
|
@ -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
|
||||
|
|
10
ld/ChangeLog
10
ld/ChangeLog
|
@ -1,3 +1,13 @@
|
|||
2006-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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 <nickc@redhat.com>
|
||||
|
||||
* po/zh_TW.po: New Chinese (traditional) translation.
|
||||
|
|
|
@ -1719,6 +1719,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
|
|||
#define OPTION_GROUP (OPTION_ENABLE_NEW_DTAGS + 1)
|
||||
#define OPTION_EH_FRAME_HDR (OPTION_GROUP + 1)
|
||||
#define OPTION_EXCLUDE_LIBS (OPTION_EH_FRAME_HDR + 1)
|
||||
#define OPTION_HASH_STYLE (OPTION_EXCLUDE_LIBS + 1)
|
||||
|
||||
static void
|
||||
gld${EMULATION_NAME}_add_options
|
||||
|
@ -1735,6 +1736,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
|
|||
{"enable-new-dtags", no_argument, NULL, OPTION_ENABLE_NEW_DTAGS},
|
||||
{"eh-frame-hdr", no_argument, NULL, OPTION_EH_FRAME_HDR},
|
||||
{"exclude-libs", required_argument, NULL, OPTION_EXCLUDE_LIBS},
|
||||
{"hash-style", required_argument, NULL, OPTION_HASH_STYLE},
|
||||
{"Bgroup", no_argument, NULL, OPTION_GROUP},
|
||||
EOF
|
||||
fi
|
||||
|
@ -1791,6 +1793,22 @@ cat >>e${EMULATION_NAME}.c <<EOF
|
|||
add_excluded_libs (optarg);
|
||||
break;
|
||||
|
||||
case OPTION_HASH_STYLE:
|
||||
link_info.emit_hash = FALSE;
|
||||
link_info.emit_gnu_hash = FALSE;
|
||||
if (strcmp (optarg, "sysv") == 0)
|
||||
link_info.emit_hash = TRUE;
|
||||
else if (strcmp (optarg, "gnu") == 0)
|
||||
link_info.emit_gnu_hash = TRUE;
|
||||
else if (strcmp (optarg, "both") == 0)
|
||||
{
|
||||
link_info.emit_hash = TRUE;
|
||||
link_info.emit_gnu_hash = TRUE;
|
||||
}
|
||||
else
|
||||
einfo (_("%P%F: invalid hash style \`%s'\n"), optarg);
|
||||
break;
|
||||
|
||||
case 'z':
|
||||
if (strcmp (optarg, "initfirst") == 0)
|
||||
link_info.flags_1 |= (bfd_vma) DF_1_INITFIRST;
|
||||
|
@ -1894,6 +1912,7 @@ cat >>e${EMULATION_NAME}.c <<EOF
|
|||
fprintf (file, _(" --disable-new-dtags\tDisable new dynamic tags\n"));
|
||||
fprintf (file, _(" --enable-new-dtags\tEnable new dynamic tags\n"));
|
||||
fprintf (file, _(" --eh-frame-hdr\tCreate .eh_frame_hdr section\n"));
|
||||
fprintf (file, _(" --hash-style=STYLE\tSet hash style to sysv, gnu or both\n"));
|
||||
fprintf (file, _(" -z combreloc\t\tMerge dynamic relocs into one section and sort\n"));
|
||||
fprintf (file, _(" -z defs\t\tReport unresolved symbols in object files.\n"));
|
||||
fprintf (file, _(" -z execstack\t\tMark executable as requiring executable stack\n"));
|
||||
|
|
|
@ -1883,6 +1883,14 @@ time it takes the linker to perform its tasks, at the expense of
|
|||
increasing the linker's memory requirements. Similarly reducing this
|
||||
value can reduce the memory requirements at the expense of speed.
|
||||
|
||||
@kindex --hash-style=@var{style}
|
||||
@item --hash-style=@var{style}
|
||||
Set the type of linker's hash table(s). @var{style} can be either
|
||||
@code{sysv} for classic ELF @code{.hash} section, @code{gnu} for
|
||||
new style GNU @code{.gnu.hash} section or @code{both} for both
|
||||
the classic ELF @code{.hash} and new style GNU @code{.gnu.hash}
|
||||
hash tables. The default is @code{sysv}.
|
||||
|
||||
@kindex --reduce-memory-overheads
|
||||
@item --reduce-memory-overheads
|
||||
This option reduces memory requirements at ld runtime, at the expense of
|
||||
|
|
|
@ -304,6 +304,8 @@ main (int argc, char **argv)
|
|||
link_info.create_object_symbols_section = NULL;
|
||||
link_info.gc_sym_list = NULL;
|
||||
link_info.base_file = NULL;
|
||||
link_info.emit_hash = TRUE;
|
||||
link_info.emit_gnu_hash = FALSE;
|
||||
/* SVR4 linkers seem to set DT_INIT and DT_FINI based on magic _init
|
||||
and _fini symbols. We are compatible. */
|
||||
link_info.init_function = "_init";
|
||||
|
|
|
@ -260,6 +260,7 @@ SECTIONS
|
|||
${INITIAL_READONLY_SECTIONS}
|
||||
${TEXT_DYNAMIC+${DYNAMIC}}
|
||||
.hash ${RELOCATING-0} : { *(.hash) }
|
||||
.gnu.hash ${RELOCATING-0} : { *(.gnu.hash) }
|
||||
.dynsym ${RELOCATING-0} : { *(.dynsym) }
|
||||
.dynstr ${RELOCATING-0} : { *(.dynstr) }
|
||||
.gnu.version ${RELOCATING-0} : { *(.gnu.version) }
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
2006-07-10 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
* 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 <ths@mips.com>
|
||||
|
||||
* ld-mips-elf/multi-got-1.d, ld-mips-elf/tls-multi-got-1.got,
|
||||
|
|
|
@ -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 .*
|
||||
|
|
|
@ -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+
|
||||
|
|
|
@ -42,5 +42,5 @@ Disassembly of section \.got:
|
|||
.* <\.got>:
|
||||
\.\.\.
|
||||
.*: 4e 80 00 21 blrl
|
||||
.*: 00 01 04 38 .*
|
||||
.*: 00 01 04 00 .*
|
||||
\.\.\.
|
||||
|
|
|
@ -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 .*
|
||||
|
|
|
@ -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+
|
||||
|
|
|
@ -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 .*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue