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> 2017-11-04 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (readonly_dynrelocs): Delete info param. Update all * 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; 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. */ /* If H is undefined, make it dynamic if that makes sense. */
static bfd_boolean static bfd_boolean
@ -5801,27 +5840,17 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
return FALSE; return FALSE;
need = 0; 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
if (!eh->elf.def_dynamic) always be the case. It's a little odd if we have
/* We'll just use htab->tlsld_got.offset. This should a local dynamic reloc against a non-local symbol. */
always be the case. It's a little odd if we have htab->tlsld_got.refcount += 1;
a local dynamic reloc against a non-local symbol. */ else
htab->tlsld_got.refcount += 1;
else
need += 8;
}
if ((eh->tls_mask & TLS_GD) != 0)
need += 8; need += 8;
if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
need += 4;
if ((eh->tls_mask & TLS_DTPREL) != 0)
need += 4;
} }
else need += got_entries_needed (eh->tls_mask);
need += 4;
if (need == 0) if (need == 0)
eh->elf.got.offset = (bfd_vma) -1; eh->elf.got.offset = (bfd_vma) -1;
else else
@ -5833,16 +5862,18 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
&& !SYMBOL_REFERENCES_LOCAL (info, &eh->elf))) && !SYMBOL_REFERENCES_LOCAL (info, &eh->elf)))
&& !UNDEFWEAK_NO_DYNAMIC_RELOC (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) if (eh->elf.type == STT_GNU_IFUNC)
rsec = htab->elf.irelplt; rsec = htab->elf.irelplt;
/* All the entries we allocated need relocs. rsec->size += need;
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);
} }
} }
} }
@ -6244,20 +6275,10 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
for (; local_got < end_local_got; ++local_got, ++lgot_masks) for (; local_got < end_local_got; ++local_got, ++lgot_masks)
if (*local_got > 0) if (*local_got > 0)
{ {
unsigned int need = 0; unsigned int need;
if ((*lgot_masks & TLS_TLS) != 0) if ((*lgot_masks & TLS_LD) != 0)
{ htab->tlsld_got.refcount += 1;
if ((*lgot_masks & TLS_GD) != 0) need = got_entries_needed (*lgot_masks);
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;
if (need == 0) if (need == 0)
*local_got = (bfd_vma) -1; *local_got = (bfd_vma) -1;
else else
@ -6265,10 +6286,14 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
*local_got = allocate_got (htab, need); *local_got = allocate_got (htab, need);
if (bfd_link_pic (info)) 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) if ((*lgot_masks & PLT_IFUNC) != 0)
srel = htab->elf.irelplt; 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) || (bfd_link_pic (info)
&& (h == NULL && (h == NULL
|| !UNDEFWEAK_NO_DYNAMIC_RELOC (info, h) || !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; asection *rsec = htab->elf.srelgot;
bfd_byte * loc; bfd_byte * loc;

View File

@ -9584,7 +9584,10 @@ allocate_got (struct elf_link_hash_entry *h,
htab->elf.irelplt->size += rentsize; htab->elf.irelplt->size += rentsize;
htab->got_reli_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 || (htab->elf.dynamic_sections_created
&& h->dynindx != -1 && h->dynindx != -1
&& !SYMBOL_REFERENCES_LOCAL (info, h))) && !SYMBOL_REFERENCES_LOCAL (info, h)))
@ -10072,7 +10075,9 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
htab->elf.irelplt->size += rel_size; htab->elf.irelplt->size += rel_size;
htab->got_reli_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; asection *srel = ppc64_elf_tdata (ibfd)->relgot;
srel->size += rel_size; srel->size += rel_size;
@ -14514,7 +14519,10 @@ ppc64_elf_relocate_section (bfd *output_bfd,
&& (h == NULL && (h == NULL
|| !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf) || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &h->elf)
|| (tls_type == (TLS_TLS | TLS_LD) || (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; relgot = ppc64_elf_tdata (ent->owner)->relgot;
if (relgot != NULL) if (relgot != NULL)
{ {