* elfxx-mips.c (count_section_dynsyms): Move before the new first use.
	(mips_elf_sort_hash_table): Take the output bfd as a parameter.
	Remove the MAX_LOCAL parameter.  Exit early if there are no
	dynamic symbols, if there is no dynobj, or if there is no
	GOT section.  Use count_section_dynsyms instead of MAX_LOCAL.
	Assert == rather than <= when checking hsd.max_unref_got_dynindx.
	Also assert that g->global_gotno is right.
	(mips_elf_count_forced_local_got_symbols): Rename to...
	(mips_elf_count_got_symbols): ...and count global GOT entries too.
	Set the global_got_area of a forced-local GGA_RELOC_ONLY symbol
	to GGA_NONE.
	(mips_elf_multi_got): Don't sort the symbol table.
	(mips_elf_lay_out_got): Likewise.  Use mips_elf_count_got_symbols
	to count the number of global GOT entries.
	(_bfd_mips_elf_final_link): Unconditionally call
	mips_elf_sort_hash_table.
This commit is contained in:
Richard Sandiford 2008-08-07 19:59:16 +00:00
parent 634835aefb
commit d4596a51eb
2 changed files with 78 additions and 98 deletions

View File

@ -1,3 +1,22 @@
2008-08-07 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (count_section_dynsyms): Move before the new first use.
(mips_elf_sort_hash_table): Take the output bfd as a parameter.
Remove the MAX_LOCAL parameter. Exit early if there are no
dynamic symbols, if there is no dynobj, or if there is no
GOT section. Use count_section_dynsyms instead of MAX_LOCAL.
Assert == rather than <= when checking hsd.max_unref_got_dynindx.
Also assert that g->global_gotno is right.
(mips_elf_count_forced_local_got_symbols): Rename to...
(mips_elf_count_got_symbols): ...and count global GOT entries too.
Set the global_got_area of a forced-local GGA_RELOC_ONLY symbol
to GGA_NONE.
(mips_elf_multi_got): Don't sort the symbol table.
(mips_elf_lay_out_got): Likewise. Use mips_elf_count_got_symbols
to count the number of global GOT entries.
(_bfd_mips_elf_final_link): Unconditionally call
mips_elf_sort_hash_table.
2008-08-07 Richard Sandiford <rdsandiford@googlemail.com>
* elfxx-mips.c (GGA_NORMAL, GGA_RELOC_ONLY, GGA_NONE): New macros.

View File

@ -2909,22 +2909,49 @@ mips_elf_create_local_got_entry (bfd *abfd, struct bfd_link_info *info,
return *loc;
}
/* Return the number of dynamic section symbols required by OUTPUT_BFD.
The number might be exact or a worst-case estimate, depending on how
much information is available to elf_backend_omit_section_dynsym at
the current linking stage. */
static bfd_size_type
count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
{
bfd_size_type count;
count = 0;
if (info->shared || elf_hash_table (info)->is_relocatable_executable)
{
asection *p;
const struct elf_backend_data *bed;
bed = get_elf_backend_data (output_bfd);
for (p = output_bfd->sections; p ; p = p->next)
if ((p->flags & SEC_EXCLUDE) == 0
&& (p->flags & SEC_ALLOC) != 0
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
++count;
}
return count;
}
/* Sort the dynamic symbol table so that symbols that need GOT entries
appear towards the end. This reduces the amount of GOT space
required. MAX_LOCAL is used to set the number of local symbols
known to be in the dynamic symbol table. During
_bfd_mips_elf_size_dynamic_sections, this value is 1. Afterward, the
section symbols are added and the count is higher. */
appear towards the end. */
static bfd_boolean
mips_elf_sort_hash_table (struct bfd_link_info *info, unsigned long max_local)
mips_elf_sort_hash_table (bfd *abfd, struct bfd_link_info *info)
{
struct mips_elf_link_hash_table *htab;
struct mips_elf_hash_sort_data hsd;
struct mips_got_info *g;
if (elf_hash_table (info)->dynsymcount == 0)
return TRUE;
htab = mips_elf_hash_table (info);
g = htab->got_info;
if (g == NULL)
return TRUE;
hsd.low = NULL;
hsd.max_unref_got_dynindx =
@ -2937,7 +2964,7 @@ mips_elf_sort_hash_table (struct bfd_link_info *info, unsigned long max_local)
don't prevent other entries that are referenced from getting
too large offsets. */
- (g->next ? g->assigned_gotno : 0);
hsd.max_non_got_dynindx = max_local;
hsd.max_non_got_dynindx = count_section_dynsyms (abfd, info) + 1;
mips_elf_link_hash_traverse (((struct mips_elf_link_hash_table *)
elf_hash_table (info)),
mips_elf_sort_hash_table_f,
@ -2946,8 +2973,10 @@ mips_elf_sort_hash_table (struct bfd_link_info *info, unsigned long max_local)
/* There should have been enough room in the symbol table to
accommodate both the GOT and non-GOT symbols. */
BFD_ASSERT (hsd.max_non_got_dynindx <= hsd.min_got_dynindx);
BFD_ASSERT ((unsigned long)hsd.max_unref_got_dynindx
<= elf_hash_table (info)->dynsymcount);
BFD_ASSERT ((unsigned long) hsd.max_unref_got_dynindx
== elf_hash_table (info)->dynsymcount);
BFD_ASSERT (elf_hash_table (info)->dynsymcount - hsd.min_got_dynindx
== g->global_gotno);
/* Now we know which dynamic symbol has the lowest dynamic symbol
table index in the GOT. */
@ -3364,25 +3393,27 @@ mips_elf_resolve_final_got_entries (struct mips_got_info *g)
}
/* A mips_elf_link_hash_traverse callback for which DATA points
to a mips_got_info. Add each forced-local GOT symbol to DATA's
local_gotno field. */
to a mips_got_info. Count the number of type (3) entries. */
static int
mips_elf_count_forced_local_got_symbols (struct mips_elf_link_hash_entry *h,
void *data)
mips_elf_count_got_symbols (struct mips_elf_link_hash_entry *h, void *data)
{
struct mips_got_info *g;
g = (struct mips_got_info *) data;
if (h->global_got_area != GGA_NONE
&& (h->root.forced_local || h->root.dynindx == -1))
if (h->global_got_area != GGA_NONE)
{
/* We no longer need this entry if it was only used for
relocations; those relocations will be against the
null or section symbol instead of H. */
if (h->global_got_area != GGA_RELOC_ONLY)
g->local_gotno++;
h->global_got_area = GGA_NONE;
if (h->root.forced_local || h->root.dynindx == -1)
{
/* We no longer need this entry if it was only used for
relocations; those relocations will be against the
null or section symbol instead of H. */
if (h->global_got_area != GGA_RELOC_ONLY)
g->local_gotno++;
h->global_got_area = GGA_NONE;
}
else
g->global_gotno++;
}
return 1;
}
@ -3943,8 +3974,6 @@ mips_elf_multi_got (bfd *abfd, struct bfd_link_info *info,
set_got_offset_arg.value = GGA_NORMAL;
htab_traverse (g->got_entries, mips_elf_set_global_got_offset,
&set_got_offset_arg);
if (! mips_elf_sort_hash_table (info, 1))
return FALSE;
/* Now go through the GOTs assigning them offset ranges.
[assigned_gotno, local_gotno[ will be set to the range of local
@ -7792,32 +7821,6 @@ _bfd_mips_vxworks_adjust_dynamic_symbol (struct bfd_link_info *info,
return _bfd_elf_adjust_dynamic_copy (h, htab->sdynbss);
}
/* Return the number of dynamic section symbols required by OUTPUT_BFD.
The number might be exact or a worst-case estimate, depending on how
much information is available to elf_backend_omit_section_dynsym at
the current linking stage. */
static bfd_size_type
count_section_dynsyms (bfd *output_bfd, struct bfd_link_info *info)
{
bfd_size_type count;
count = 0;
if (info->shared || elf_hash_table (info)->is_relocatable_executable)
{
asection *p;
const struct elf_backend_data *bed;
bed = get_elf_backend_data (output_bfd);
for (p = output_bfd->sections; p ; p = p->next)
if ((p->flags & SEC_EXCLUDE) == 0
&& (p->flags & SEC_ALLOC) != 0
&& !(*bed->elf_backend_omit_section_dynsym) (output_bfd, info, p))
++count;
}
return count;
}
/* This function is called after all the input files have been read,
and the input sections have been assigned to output sections. We
check for any mips16 stub sections that we can discard. */
@ -7852,7 +7855,6 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
bfd *dynobj;
asection *s;
struct mips_got_info *g;
int i;
bfd_size_type loadable_size = 0;
bfd_size_type page_gotno;
bfd *sub;
@ -7872,24 +7874,8 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
if (!mips_elf_resolve_final_got_entries (g))
return FALSE;
/* Count the number of forced-local entries. */
mips_elf_link_hash_traverse (htab,
mips_elf_count_forced_local_got_symbols, g);
/* There has to be a global GOT entry for every symbol with
a dynamic symbol table index of DT_MIPS_GOTSYM or
higher. Therefore, it make sense to put those symbols
that need GOT entries at the end of the symbol table. We
do that here. */
if (! mips_elf_sort_hash_table (info, 1))
return FALSE;
if (g->global_gotsym != NULL)
i = elf_hash_table (info)->dynsymcount - g->global_gotsym->dynindx;
else
/* If there are no global symbols, or none requiring
relocations, then GLOBAL_GOTSYM will be NULL. */
i = 0;
/* Count the number of GOT symbols. */
mips_elf_link_hash_traverse (htab, mips_elf_count_got_symbols, g);
/* Calculate the total loadable size of the output. That
will give us the maximum number of GOT_PAGE entries
@ -7926,9 +7912,7 @@ mips_elf_lay_out_got (bfd *output_bfd, struct bfd_link_info *info)
g->local_gotno += page_gotno;
s->size += g->local_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
g->global_gotno = i;
s->size += i * MIPS_ELF_GOT_SIZE (output_bfd);
s->size += g->global_gotno * MIPS_ELF_GOT_SIZE (output_bfd);
/* We need to calculate tls_gotno for global symbols at this point
instead of building it up earlier, to avoid doublecounting
@ -10791,34 +10775,11 @@ _bfd_mips_elf_final_link (bfd *abfd, struct bfd_link_info *info)
scRData, scSData, scSBss, scBss
};
/* We'd carefully arranged the dynamic symbol indices, and then the
generic size_dynamic_sections renumbered them out from under us.
Rather than trying somehow to prevent the renumbering, just do
the sort again. */
/* Sort the dynamic symbols so that those with GOT entries come after
those without. */
htab = mips_elf_hash_table (info);
if (elf_hash_table (info)->dynamic_sections_created)
{
struct mips_got_info *g;
bfd_size_type dynsecsymcount;
/* When we resort, we must tell mips_elf_sort_hash_table what
the lowest index it may use is. That's the number of section
symbols we're going to add. The generic ELF linker only
adds these symbols when building a shared object. Note that
we count the sections after (possibly) removing the .options
section above. */
dynsecsymcount = count_section_dynsyms (abfd, info);
if (! mips_elf_sort_hash_table (info, dynsecsymcount + 1))
return FALSE;
/* Make sure we didn't grow the global .got region. */
g = htab->got_info;
if (g->global_gotsym != NULL)
BFD_ASSERT ((elf_hash_table (info)->dynsymcount
- g->global_gotsym->dynindx)
<= g->global_gotno);
}
if (!mips_elf_sort_hash_table (abfd, info))
return FALSE;
/* Get a value for the GP register. */
if (elf_gp (abfd) == 0)