powerpc TLS in PIEs

This patch removes unnecessary GOT IE TLS relocations in PIEs.  Useful
with --no-tls-optimize, or with an enormous TLS segment.  With the
default --tls-optimize in effect IE code sequences will be edited to
LE under the same circumstances we can remove the GOT reloc.

	* elf32-ppc.c (got_entries_needed, got_relocs_needed): New functions.
	(allocate_dynrelocs, ppc_elf_size_dynamic_sections): Use them here.
	(ppc_elf_relocate_section): Don't output a dynamic relocation
	for IE GOT entries in an executable.
	* elf64-ppc.c (allocate_got): Trim unnecessary TPREL relocs.
	(ppc64_elf_size_dynamic_sections): Likewise.
	(ppc64_elf_relocate_section): Likewise.
This commit is contained in:
Alan Modra 2017-11-04 13:41:29 +10:30
parent 98bbb1b861
commit f15d0b545b
3 changed files with 91 additions and 45 deletions

View File

@ -1,3 +1,13 @@
2017-11-04 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (got_entries_needed, got_relocs_needed): New functions.
(allocate_dynrelocs, ppc_elf_size_dynamic_sections): Use them here.
(ppc_elf_relocate_section): Don't output a dynamic relocation
for IE GOT entries in an executable.
* elf64-ppc.c (allocate_got): Trim unnecessary TPREL relocs.
(ppc64_elf_size_dynamic_sections): Likewise.
(ppc64_elf_relocate_section): Likewise.
2017-11-04 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (readonly_dynrelocs): Delete info param. Update all

View File

@ -5751,6 +5751,45 @@ allocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need)
return where;
}
/* Calculate size of GOT entries for symbol given its TLS_MASK.
TLS_LD is excluded because those go in a special GOT slot. */
static inline unsigned int
got_entries_needed (int tls_mask)
{
unsigned int need;
if ((tls_mask & TLS_TLS) == 0)
need = 4;
else
{
need = 0;
if ((tls_mask & TLS_GD) != 0)
need += 8;
if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
need += 4;
if ((tls_mask & TLS_DTPREL) != 0)
need += 4;
}
return need;
}
/* Calculate size of relocs needed for symbol given its TLS_MASK and
NEEDed GOT entries. KNOWN says a TPREL offset can be calculated at
link time. */
static inline unsigned int
got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known)
{
/* All the entries we allocated need relocs.
Except IE in executable with a local symbol. We could also omit
the DTPREL reloc on the second word of a GD entry under the same
condition as that for IE, but ld.so needs to differentiate
LD and GD entries. */
if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known)
need -= 4;
return need * sizeof (Elf32_External_Rela) / 4;
}
/* If H is undefined, make it dynamic if that makes sense. */
static bfd_boolean
@ -5801,27 +5840,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
return FALSE;
need = 0;
if ((eh->tls_mask & TLS_TLS) != 0)
if ((eh->tls_mask & TLS_LD) != 0)
{
if ((eh->tls_mask & TLS_LD) != 0)
{
if (!eh->elf.def_dynamic)
/* We'll just use htab->tlsld_got.offset. This should
always be the case. It's a little odd if we have
a local dynamic reloc against a non-local symbol. */
htab->tlsld_got.refcount += 1;
else
need += 8;
}
if ((eh->tls_mask & TLS_GD) != 0)
if (!eh->elf.def_dynamic)
/* We'll just use htab->tlsld_got.offset. This should
always be the case. It's a little odd if we have
a local dynamic reloc against a non-local symbol. */
htab->tlsld_got.refcount += 1;
else
need += 8;
if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
need += 4;
if ((eh->tls_mask & TLS_DTPREL) != 0)
need += 4;
}
else
need += 4;
need += got_entries_needed (eh->tls_mask);
if (need == 0)
eh->elf.got.offset = (bfd_vma) -1;
else
@ -5833,16 +5862,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
&& !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &eh->elf))
{
asection *rsec = htab->elf.srelgot;
asection *rsec;
bfd_boolean tprel_known = (bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info,
&eh->elf));
need = got_relocs_needed (eh->tls_mask, need, tprel_known);
if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic)
need -= sizeof (Elf32_External_Rela);
rsec = htab->elf.srelgot;
if (eh->elf.type == STT_GNU_IFUNC)
rsec = htab->elf.irelplt;
/* All the entries we allocated need relocs.
Except LD only needs one. */
if ((eh->tls_mask & TLS_LD) != 0
&& eh->elf.def_dynamic)
need -= 4;
rsec->size += need * (sizeof (Elf32_External_Rela) / 4);
rsec->size += need;
}
}
}
@ -6244,20 +6275,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
for (; local_got < end_local_got; ++local_got, ++lgot_masks)
if (*local_got > 0)
{
unsigned int need = 0;
if ((*lgot_masks & TLS_TLS) != 0)
{
if ((*lgot_masks & TLS_GD) != 0)
need += 8;
if ((*lgot_masks & TLS_LD) != 0)
htab->tlsld_got.refcount += 1;
if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0)
need += 4;
if ((*lgot_masks & TLS_DTPREL) != 0)
need += 4;
}
else
need += 4;
unsigned int need;
if ((*lgot_masks & TLS_LD) != 0)
htab->tlsld_got.refcount += 1;
need = got_entries_needed (*lgot_masks);
if (need == 0)
*local_got = (bfd_vma) -1;
else
@ -6265,10 +6286,14 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
*local_got = allocate_got (htab, need);
if (bfd_link_pic (info))
{
asection *srel = htab->elf.srelgot;
asection *srel;
bfd_boolean tprel_known = bfd_link_executable (info);
need = got_relocs_needed (*lgot_masks, need, tprel_known);
srel = htab->elf.srelgot;
if ((*lgot_masks & PLT_IFUNC) != 0)
srel = htab->elf.irelplt;
srel->size += need * (sizeof (Elf32_External_Rela) / 4);
srel->size += need;
}
}
}
@ -8428,7 +8453,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
|| (bfd_link_pic (info)
&& (h == NULL
|| !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h)
|| offp == &htab->tlsld_got.offset)))
|| offp == &htab->tlsld_got.offset)
&& !(tls_ty == (TLS_TLS | TLS_TPREL)
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, h))))
{
asection *rsec = htab->elf.srelgot;
bfd_byte * loc;

View File

@ -9584,7 +9584,10 @@ allocate_got (struct elf_link_hash_entry *h,
htab->elf.irelplt->size += rentsize;
htab->got_reli_size += rentsize;
}
else if ((bfd_link_pic (info)
else if (((bfd_link_pic (info)
&& !((gent->tls_type & TLS_TPREL) != 0
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, h)))
|| (htab->elf.dynamic_sections_created
&& h->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, h)))
@ -10072,7 +10075,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
htab->elf.irelplt->size += rel_size;
htab->got_reli_size += rel_size;
}
else if (bfd_link_pic (info))
else if (bfd_link_pic (info)
&& !((ent->tls_type & TLS_TPREL) != 0
&& bfd_link_executable (info)))
{
asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += rel_size;
@ -14514,7 +14519,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
&& (h == NULL
|| !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
|| (tls_type == (TLS_TLS | TLS_LD)
&& !h->elf.def_dynamic))))
&& !h->elf.def_dynamic))
&& !(tls_type == (TLS_TLS | TLS_TPREL)
&& bfd_link_executable (info)
&& SYMBOL_REFERENCES_LOCAL (info, &h->elf))))
relgot = ppc64_elf_tdata (ent->owner)->relgot;
if (relgot != NULL)
{