Store estimated istrances in compressed_size

elf_x86_64_convert_load is very time consuming since it is called on
each input section and has a loop over input text sections to estimate
the branch distrance.  We can store the estimated distrances in the
compressed_size field of the output section, which is only used to
decompress the compressed input section.

Before the patch, linking clang 3.9 takes 52 seconds.  After the patch,
it only takes 2.5 seconds.

	PR ld/19542
	* elf64-x86-64.c (elf_x86_64_convert_load): Store the estimated
	distrances in the compressed_size field of the output section.
This commit is contained in:
H.J. Lu 2016-02-02 08:14:43 -08:00
parent 46d70d04a4
commit 4a539596f5
2 changed files with 29 additions and 15 deletions

View File

@ -1,3 +1,9 @@
2016-02-02 H.J. Lu <hongjiu.lu@intel.com>
PR ld/19542
* elf64-x86-64.c (elf_x86_64_convert_load): Store the estimated
distrances in the compressed_size field of the output section.
2016-02-02 Alan Modra <amodra@gmail.com> 2016-02-02 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (ppc64_elf_relocate_section): Further restrict * elf64-ppc.c (ppc64_elf_relocate_section): Further restrict

View File

@ -3190,35 +3190,43 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec,
} }
else else
{ {
asection *asect; bfd_signed_vma distance;
bfd_size_type size;
/* At this point, we don't know the load addresses of TSEC /* At this point, we don't know the load addresses of TSEC
section nor SEC section. We estimate the distrance between section nor SEC section. We estimate the distrance between
SEC and TSEC. */ SEC and TSEC. We store the estimated distrances in the
size = 0; compressed_size field of the output section, which is only
for (asect = sec->output_section; used to decompress the compressed input section. */
asect != NULL && asect != tsec->output_section; if (sec->output_section->compressed_size == 0)
asect = asect->next)
{ {
asection *i; asection *asect;
for (i = asect->output_section->map_head.s; bfd_size_type size = 0;
i != NULL; for (asect = link_info->output_bfd->sections;
i = i->map_head.s) asect != NULL;
asect = asect->next)
{ {
size = align_power (size, i->alignment_power); asection *i;
size += i->size; for (i = asect->map_head.s;
i != NULL;
i = i->map_head.s)
{
size = align_power (size, i->alignment_power);
size += i->size;
}
asect->compressed_size = size;
} }
} }
/* Don't convert GOTPCREL relocations if TSEC isn't placed /* Don't convert GOTPCREL relocations if TSEC isn't placed
after SEC. */ after SEC. */
if (asect == NULL) distance = (tsec->output_section->compressed_size
- sec->output_section->compressed_size);
if (distance < 0)
continue; continue;
/* Take PT_GNU_RELRO segment into account by adding /* Take PT_GNU_RELRO segment into account by adding
maxpagesize. */ maxpagesize. */
if ((toff + size + maxpagesize - roff + 0x80000000) if ((toff + distance + maxpagesize - roff + 0x80000000)
> 0xffffffff) > 0xffffffff)
continue; continue;
} }