PowerPC indirect calls to __tls_get_addr

It is possible to construct indirect calls to __tls_get_addr in
assembly that confuse TLS optimization.  (PowerPC gcc doesn't support
such calls, ignoring -mlongcall for __tls_get_addr.)  This patch fixes
the problem by requiring a TLSLD or TLSGD marker reloc before any insn
in an indirect call to __tls_get_addr will be optimized.  They also
need additional marker relocs defined in a later patch, so don't
expect the optimization to work just yet.  The point here is to
prevent mis-optimization of indirect calls without any marker relocs.

The presense of a marker reloc is tracked by a new bit in the tls_mask
field of ppc_link_hash_entry and the corresponding lgot_masks unsigned
char array for local symbols.  Since the field is only 8 bits, we've
run out of space.  However, tracking TLS use for variables, and
tracking IFUNC for functions are independent, and bits can be reused.
TLS_TLS is always set for TLS usage, so can be used to select the
meaning of the other bits.  This patch does that even for elf32-ppc.c
which hasn't yet run out of space in the field.

	* elf64-ppc.c (TLS_TLS, TLS_GD, TLS_LD, TLS_TPREL, TLS_DTPREL,
	TLS_TPRELGD, TLS_EXPLICIT):  Renumber.  Test TLS_TLS throughout
	file when other TLS flags are tested in a mask.
	(TLS_MARK, NON_GOT): Define.
	(PLT_IFUNC): Redefine, and test TLS_TLS throughout file as well.
	(update_local_sym_info): Don't create got entry when NON_GOT.
	(ppc64_elf_check_relocs): Pass NON_GOT with PLT_IFUNC.
	Set TLS_MARK.
	(get_tls_mask): Do toc lookup if tls_mask is just TLS_MARK.
	(ppc64_elf_relocate_section): Likewise.
	(ppc64_elf_tls_optimize): Don't attempt to optimize indirect
	__tls_get_addr calls lacking a marker reloc.
	* elf32-ppc.c (TLS_TLS, TLS_GD, TLS_LD, TLS_TPREL, TLS_DTPREL,
	TLS_TPRELGD): Renumber.  Update comment.
	(TLS_MARK, NON_GOT): Define.
	(PLT_IFUNC): Redefine, and test TLS_TLS throughout file as well.
	(update_local_sym_info): Don't create got entry when NON_GOT.
	(ppc_elf_check_relocs): Pass NON_GOT with PLT_IFUNC.
	Set TLS_MARK.
	(ppc_elf_tls_optimize): Don't attempt to optimize indirect
	__tls_get_addr calls lacking a marker reloc.
This commit is contained in:
Alan Modra
2018-04-09 09:11:44 +09:30
parent 51066b9350
commit 37da22e5c8
3 changed files with 169 additions and 81 deletions

View File

@ -1,3 +1,27 @@
2018-04-09 Alan Modra <amodra@gmail.com>
* elf64-ppc.c (TLS_TLS, TLS_GD, TLS_LD, TLS_TPREL, TLS_DTPREL,
TLS_TPRELGD, TLS_EXPLICIT): Renumber. Test TLS_TLS throughout
file when other TLS flags are tested in a mask.
(TLS_MARK, NON_GOT): Define.
(PLT_IFUNC): Redefine, and test TLS_TLS throughout file as well.
(update_local_sym_info): Don't create got entry when NON_GOT.
(ppc64_elf_check_relocs): Pass NON_GOT with PLT_IFUNC.
Set TLS_MARK.
(get_tls_mask): Do toc lookup if tls_mask is just TLS_MARK.
(ppc64_elf_relocate_section): Likewise.
(ppc64_elf_tls_optimize): Don't attempt to optimize indirect
__tls_get_addr calls lacking a marker reloc.
* elf32-ppc.c (TLS_TLS, TLS_GD, TLS_LD, TLS_TPREL, TLS_DTPREL,
TLS_TPRELGD): Renumber. Update comment.
(TLS_MARK, NON_GOT): Define.
(PLT_IFUNC): Redefine, and test TLS_TLS throughout file as well.
(update_local_sym_info): Don't create got entry when NON_GOT.
(ppc_elf_check_relocs): Pass NON_GOT with PLT_IFUNC.
Set TLS_MARK.
(ppc_elf_tls_optimize): Don't attempt to optimize indirect
__tls_get_addr calls lacking a marker reloc.
2018-04-06 H.J. Lu <hongjiu.lu@intel.com> 2018-04-06 H.J. Lu <hongjiu.lu@intel.com>
* elf64-x86-64.c (elf_x86_64_info_to_howto): Don't mask out * elf64-x86-64.c (elf_x86_64_info_to_howto): Don't mask out

View File

@ -3226,20 +3226,30 @@ struct ppc_elf_link_hash_entry
/* Track dynamic relocs copied for this symbol. */ /* Track dynamic relocs copied for this symbol. */
struct elf_dyn_relocs *dyn_relocs; struct elf_dyn_relocs *dyn_relocs;
/* Contexts in which symbol is used in the GOT (or TOC). /* Contexts in which symbol is used in the GOT.
TLS_GD .. TLS_TLS bits are or'd into the mask as the Bits are or'd into the mask as the corresponding relocs are
corresponding relocs are encountered during check_relocs. encountered during check_relocs, with TLS_TLS being set when any
tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to of the other TLS bits are set. tls_optimize clears bits when
indicate the corresponding GOT entry type is not needed. */ optimizing to indicate the corresponding GOT entry type is not
#define TLS_GD 1 /* GD reloc. */ needed. If set, TLS_TLS is never cleared. tls_optimize may also
#define TLS_LD 2 /* LD reloc. */ set TLS_TPRELGD when a GD reloc turns into a TPREL one. We use a
#define TLS_TPREL 4 /* TPREL reloc, => IE. */ separate flag rather than setting TPREL just for convenience in
#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ distinguishing the two cases.
#define TLS_TLS 16 /* Any TLS reloc. */ These flags are also kept for local symbols. */
#define TLS_TPRELGD 32 /* TPREL reloc resulting from GD->IE. */ #define TLS_TLS 1 /* Any TLS reloc. */
#define PLT_IFUNC 64 /* STT_GNU_IFUNC. */ #define TLS_GD 2 /* GD reloc. */
#define TLS_LD 4 /* LD reloc. */
#define TLS_TPREL 8 /* TPREL reloc, => IE. */
#define TLS_DTPREL 16 /* DTPREL reloc, => LD. */
#define TLS_MARK 32 /* __tls_get_addr call marked. */
#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */
unsigned char tls_mask; unsigned char tls_mask;
/* The above field is also used to mark function symbols. In which
case TLS_TLS will be 0. */
#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */
#define NON_GOT 256 /* local symbol plt, not stored. */
/* Nonzero if we have seen a small data relocation referring to this /* Nonzero if we have seen a small data relocation referring to this
symbol. */ symbol. */
unsigned char has_sda_refs : 1; unsigned char has_sda_refs : 1;
@ -3861,8 +3871,8 @@ update_local_sym_info (bfd *abfd,
local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info); local_plt = (struct plt_entry **) (local_got_refcounts + symtab_hdr->sh_info);
local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info); local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
local_got_tls_masks[r_symndx] |= tls_type; local_got_tls_masks[r_symndx] |= tls_type & 0xff;
if (tls_type != PLT_IFUNC) if ((tls_type & NON_GOT) == 0)
local_got_refcounts[r_symndx] += 1; local_got_refcounts[r_symndx] += 1;
return local_plt + r_symndx; return local_plt + r_symndx;
} }
@ -4038,7 +4048,7 @@ ppc_elf_check_relocs (bfd *abfd,
{ {
/* Set PLT_IFUNC flag for this sym, no GOT entry yet. */ /* Set PLT_IFUNC flag for this sym, no GOT entry yet. */
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
PLT_IFUNC); NON_GOT | PLT_IFUNC);
if (ifunc == NULL) if (ifunc == NULL)
return FALSE; return FALSE;
@ -4083,6 +4093,12 @@ ppc_elf_check_relocs (bfd *abfd,
case R_PPC_TLSLD: case R_PPC_TLSLD:
/* These special tls relocs tie a call to __tls_get_addr with /* These special tls relocs tie a call to __tls_get_addr with
its parameter symbol. */ its parameter symbol. */
if (h != NULL)
ppc_elf_hash_entry (h)->tls_mask |= TLS_TLS | TLS_MARK;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
NON_GOT | TLS_TLS | TLS_MARK))
return FALSE;
break; break;
case R_PPC_GOT_TLSLD16: case R_PPC_GOT_TLSLD16:
@ -5212,7 +5228,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
unsigned long r_symndx; unsigned long r_symndx;
struct elf_link_hash_entry *h = NULL; struct elf_link_hash_entry *h = NULL;
unsigned char *tls_mask; unsigned char *tls_mask;
char tls_set, tls_clear; unsigned char tls_set, tls_clear;
bfd_boolean is_local; bfd_boolean is_local;
bfd_signed_vma *got_count; bfd_signed_vma *got_count;
@ -5341,23 +5357,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
return TRUE; return TRUE;
} }
if (expecting_tls_get_addr)
{
struct plt_entry *ent;
bfd_vma addend = 0;
if (bfd_link_pic (info)
&& ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
addend = rel[1].r_addend;
ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
got2, addend);
if (ent != NULL && ent->plt.refcount > 0)
ent->plt.refcount -= 1;
if (expecting_tls_get_addr == 2)
continue;
}
if (h != NULL) if (h != NULL)
{ {
tls_mask = &ppc_elf_hash_entry (h)->tls_mask; tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
@ -5380,6 +5379,36 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
got_count = &lgot_refs[r_symndx]; got_count = &lgot_refs[r_symndx];
} }
/* If we don't have old-style __tls_get_addr calls
without TLSGD/TLSLD marker relocs, and we haven't
found a new-style __tls_get_addr call with a
marker for this symbol, then we either have a
broken object file or an -mlongcall style
indirect call to __tls_get_addr without a marker.
Disable optimization in this case. */
if ((tls_clear & (TLS_GD | TLS_LD)) != 0
&& !sec->has_tls_get_addr_call
&& ((*tls_mask & (TLS_TLS | TLS_MARK))
!= (TLS_TLS | TLS_MARK)))
continue;
if (expecting_tls_get_addr)
{
struct plt_entry *ent;
bfd_vma addend = 0;
if (bfd_link_pic (info)
&& ELF32_R_TYPE (rel[1].r_info) == R_PPC_PLTREL24)
addend = rel[1].r_addend;
ent = find_plt_ent (&htab->tls_get_addr->plt.plist,
got2, addend);
if (ent != NULL && ent->plt.refcount > 0)
ent->plt.refcount -= 1;
if (expecting_tls_get_addr == 2)
continue;
}
if (tls_set == 0) if (tls_set == 0)
{ {
/* We managed to get rid of a got entry. */ /* We managed to get rid of a got entry. */
@ -5783,7 +5812,8 @@ got_relocs_needed (int tls_mask, unsigned int need, bfd_boolean known)
the DTPREL reloc on the second word of a GD entry under the same 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 condition as that for IE, but ld.so needs to differentiate
LD and GD entries. */ LD and GD entries. */
if ((tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0 && known) if (known && (tls_mask & TLS_TLS) != 0
&& (tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0)
need -= 4; need -= 4;
return need * sizeof (Elf32_External_Rela) / 4; return need * sizeof (Elf32_External_Rela) / 4;
} }
@ -5838,7 +5868,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
return FALSE; return FALSE;
need = 0; need = 0;
if ((eh->tls_mask & TLS_LD) != 0) if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
{ {
if (!eh->elf.def_dynamic) if (!eh->elf.def_dynamic)
/* We'll just use htab->tlsld_got.offset. This should /* We'll just use htab->tlsld_got.offset. This should
@ -5866,7 +5896,8 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
&eh->elf)); &eh->elf));
need = got_relocs_needed (eh->tls_mask, need, tprel_known); need = got_relocs_needed (eh->tls_mask, need, tprel_known);
if ((eh->tls_mask & TLS_LD) != 0 && eh->elf.def_dynamic) if ((eh->tls_mask & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD)
&& eh->elf.def_dynamic)
need -= sizeof (Elf32_External_Rela); need -= sizeof (Elf32_External_Rela);
rsec = htab->elf.srelgot; rsec = htab->elf.srelgot;
if (eh->elf.type == STT_GNU_IFUNC) if (eh->elf.type == STT_GNU_IFUNC)
@ -6272,7 +6303,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
if (*local_got > 0) if (*local_got > 0)
{ {
unsigned int need; unsigned int need;
if ((*lgot_masks & TLS_LD) != 0) if ((*lgot_masks & (TLS_TLS | TLS_LD)) == (TLS_TLS | TLS_LD))
htab->tlsld_got.refcount += 1; htab->tlsld_got.refcount += 1;
need = got_entries_needed (*lgot_masks); need = got_entries_needed (*lgot_masks);
if (need == 0) if (need == 0)
@ -6287,7 +6318,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
need = got_relocs_needed (*lgot_masks, need, tprel_known); need = got_relocs_needed (*lgot_masks, need, tprel_known);
srel = htab->elf.srelgot; srel = htab->elf.srelgot;
if ((*lgot_masks & PLT_IFUNC) != 0) if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
srel = htab->elf.irelplt; srel = htab->elf.irelplt;
srel->size += need; srel->size += need;
} }
@ -8425,9 +8456,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
off &= ~1; off &= ~1;
else else
{ {
unsigned int tls_m = (tls_mask unsigned int tls_m = ((tls_mask & TLS_TLS) != 0
& (TLS_LD | TLS_GD | TLS_DTPREL ? tls_mask & (TLS_LD | TLS_GD | TLS_DTPREL
| TLS_TPREL | TLS_TPRELGD)); | TLS_TPREL | TLS_TPRELGD)
: 0);
if (offp == &htab->tlsld_got.offset) if (offp == &htab->tlsld_got.offset)
tls_m = TLS_LD; tls_m = TLS_LD;

View File

@ -4046,22 +4046,29 @@ struct ppc_link_hash_entry
unsigned int non_zero_localentry:1; unsigned int non_zero_localentry:1;
/* Contexts in which symbol is used in the GOT (or TOC). /* Contexts in which symbol is used in the GOT (or TOC).
TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the Bits are or'd into the mask as the corresponding relocs are
corresponding relocs are encountered during check_relocs. encountered during check_relocs, with TLS_TLS being set when any
tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to of the other TLS bits are set. tls_optimize clears bits when
indicate the corresponding GOT entry type is not needed. optimizing to indicate the corresponding GOT entry type is not
tls_optimize may also set TLS_TPRELGD when a GD reloc turns into needed. If set, TLS_TLS is never cleared. tls_optimize may also
a TPREL one. We use a separate flag rather than setting TPREL set TLS_TPRELGD when a GD reloc turns into a TPREL one. We use a
just for convenience in distinguishing the two cases. */ separate flag rather than setting TPREL just for convenience in
#define TLS_GD 1 /* GD reloc. */ distinguishing the two cases.
#define TLS_LD 2 /* LD reloc. */ These flags are also kept for local symbols. */
#define TLS_TPREL 4 /* TPREL reloc, => IE. */ #define TLS_TLS 1 /* Any TLS reloc. */
#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ #define TLS_GD 2 /* GD reloc. */
#define TLS_TLS 16 /* Any TLS reloc. */ #define TLS_LD 4 /* LD reloc. */
#define TLS_EXPLICIT 32 /* Marks TOC section TLS relocs. */ #define TLS_TPREL 8 /* TPREL reloc, => IE. */
#define TLS_DTPREL 16 /* DTPREL reloc, => LD. */
#define TLS_MARK 32 /* __tls_get_addr call marked. */
#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */ #define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */
#define PLT_IFUNC 128 /* STT_GNU_IFUNC. */ #define TLS_EXPLICIT 128 /* Marks TOC section TLS relocs. */
unsigned char tls_mask; unsigned char tls_mask;
/* The above field is also used to mark function symbols. In which
case TLS_TLS will be 0. */
#define PLT_IFUNC 2 /* STT_GNU_IFUNC. */
#define NON_GOT 256 /* local symbol plt, not stored. */
}; };
/* ppc64 ELF linker hash table. */ /* ppc64 ELF linker hash table. */
@ -5337,7 +5344,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
elf_local_got_ents (abfd) = local_got_ents; elf_local_got_ents (abfd) = local_got_ents;
} }
if ((tls_type & (PLT_IFUNC | TLS_EXPLICIT)) == 0) if ((tls_type & (NON_GOT | TLS_EXPLICIT)) == 0)
{ {
struct got_entry *ent; struct got_entry *ent;
@ -5365,7 +5372,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info); local_plt = (struct plt_entry **) (local_got_ents + symtab_hdr->sh_info);
local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info); local_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
local_got_tls_masks[r_symndx] |= tls_type; local_got_tls_masks[r_symndx] |= tls_type & 0xff;
return local_plt + r_symndx; return local_plt + r_symndx;
} }
@ -5491,7 +5498,8 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC)
{ {
ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx, ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
rel->r_addend, PLT_IFUNC); rel->r_addend,
NON_GOT | PLT_IFUNC);
if (ifunc == NULL) if (ifunc == NULL)
return FALSE; return FALSE;
} }
@ -5504,6 +5512,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
case R_PPC64_TLSLD: case R_PPC64_TLSLD:
/* These special tls relocs tie a call to __tls_get_addr with /* These special tls relocs tie a call to __tls_get_addr with
its parameter symbol. */ its parameter symbol. */
if (h != NULL)
((struct ppc_link_hash_entry *) h)->tls_mask |= TLS_TLS | TLS_MARK;
else
if (!update_local_sym_info (abfd, symtab_hdr, r_symndx,
rel->r_addend,
NON_GOT | TLS_TLS | TLS_MARK))
return FALSE;
sec->has_tls_reloc = 1;
break; break;
case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16:
@ -7498,7 +7514,9 @@ get_tls_mask (unsigned char **tls_maskp,
if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
return 0; return 0;
if ((*tls_maskp != NULL && **tls_maskp != 0) if ((*tls_maskp != NULL
&& (**tls_maskp & TLS_TLS) != 0
&& **tls_maskp != (TLS_TLS | TLS_MARK))
|| sec == NULL || sec == NULL
|| ppc64_elf_section_data (sec) == NULL || ppc64_elf_section_data (sec) == NULL
|| ppc64_elf_section_data (sec)->sec_type != sec_toc) || ppc64_elf_section_data (sec)->sec_type != sec_toc)
@ -8665,7 +8683,8 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
goto err_free_rel; goto err_free_rel;
if (toc_tls != NULL) if (toc_tls != NULL)
{ {
if ((*toc_tls & (TLS_GD | TLS_LD)) != 0) if ((*toc_tls & TLS_TLS) != 0
&& ((*toc_tls & (TLS_GD | TLS_LD)) != 0))
found_tls_get_addr_arg = 1; found_tls_get_addr_arg = 1;
if (retval > 1) if (retval > 1)
toc_ref[toc_ref_index] = 1; toc_ref[toc_ref_index] = 1;
@ -8674,9 +8693,6 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
continue; continue;
} }
if (expecting_tls_get_addr != 1)
continue;
/* Uh oh, we didn't find the expected call. We /* Uh oh, we didn't find the expected call. We
could just mark this symbol to exclude it could just mark this symbol to exclude it
from tls optimization but it's safer to skip from tls optimization but it's safer to skip
@ -8689,6 +8705,20 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
goto err_free_rel; goto err_free_rel;
} }
/* If we don't have old-style __tls_get_addr calls
without TLSGD/TLSLD marker relocs, and we haven't
found a new-style __tls_get_addr call with a
marker for this symbol, then we either have a
broken object file or an -mlongcall style
indirect call to __tls_get_addr without a marker.
Disable optimization in this case. */
if ((tls_clear & (TLS_GD | TLS_LD)) != 0
&& (tls_set & TLS_EXPLICIT) == 0
&& !sec->has_tls_get_addr_call
&& ((*tls_mask & (TLS_TLS | TLS_MARK))
!= (TLS_TLS | TLS_MARK)))
continue;
if (expecting_tls_get_addr && htab->tls_get_addr != NULL) if (expecting_tls_get_addr && htab->tls_get_addr != NULL)
{ {
struct plt_entry *ent; struct plt_entry *ent;
@ -9648,7 +9678,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
eh = (struct ppc_link_hash_entry *) h; eh = (struct ppc_link_hash_entry *) h;
/* Run through the TLS GD got entries first if we're changing them /* Run through the TLS GD got entries first if we're changing them
to TPREL. */ to TPREL. */
if ((eh->tls_mask & TLS_TPRELGD) != 0) if ((eh->tls_mask & (TLS_TLS | TLS_TPRELGD)) == (TLS_TLS | TLS_TPRELGD))
for (gent = h->got.glist; gent != NULL; gent = gent->next) for (gent = h->got.glist; gent != NULL; gent = gent->next)
if (gent->got.refcount > 0 if (gent->got.refcount > 0
&& (gent->tls_type & TLS_GD) != 0) && (gent->tls_type & TLS_GD) != 0)
@ -10074,7 +10104,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
rel_size *= 2; rel_size *= 2;
} }
s->size += ent_size; s->size += ent_size;
if ((*lgot_masks & PLT_IFUNC) != 0) if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
{ {
htab->elf.irelplt->size += rel_size; htab->elf.irelplt->size += rel_size;
htab->got_reli_size += rel_size; htab->got_reli_size += rel_size;
@ -11701,7 +11731,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
rel_size *= 2; rel_size *= 2;
} }
s->size += ent_size; s->size += ent_size;
if ((*lgot_masks & PLT_IFUNC) != 0) if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
{ {
htab->elf.irelplt->size += rel_size; htab->elf.irelplt->size += rel_size;
htab->got_reli_size += rel_size; htab->got_reli_size += rel_size;
@ -12576,7 +12606,7 @@ ppc64_elf_size_stubs (struct bfd_link_info *info)
if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms, if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
irela - 1, input_bfd)) irela - 1, input_bfd))
goto error_ret_free_internal; goto error_ret_free_internal;
if (*tls_mask != 0) if ((*tls_mask & TLS_TLS) != 0)
continue; continue;
} }
@ -13596,7 +13626,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
(local_plt + symtab_hdr->sh_info); (local_plt + symtab_hdr->sh_info);
tls_mask = lgot_masks[r_symndx]; tls_mask = lgot_masks[r_symndx];
} }
if (tls_mask == 0 if (((tls_mask & TLS_TLS) == 0 || tls_mask == (TLS_TLS | TLS_MARK))
&& (r_type == R_PPC64_TLS && (r_type == R_PPC64_TLS
|| r_type == R_PPC64_TLSGD || r_type == R_PPC64_TLSGD
|| r_type == R_PPC64_TLSLD)) || r_type == R_PPC64_TLSLD))
@ -13624,7 +13654,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
|| (sym_type == STT_SECTION || (sym_type == STT_SECTION
&& (sec->flags & SEC_THREAD_LOCAL) != 0)))) && (sec->flags & SEC_THREAD_LOCAL) != 0))))
{ {
if (tls_mask != 0 if ((tls_mask & TLS_TLS) != 0
&& (r_type == R_PPC64_TLS && (r_type == R_PPC64_TLS
|| r_type == R_PPC64_TLSGD || r_type == R_PPC64_TLSGD
|| r_type == R_PPC64_TLSLD)) || r_type == R_PPC64_TLSLD))
@ -13690,7 +13720,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (r_type == R_PPC64_TOC16_DS if (r_type == R_PPC64_TOC16_DS
|| r_type == R_PPC64_TOC16_LO_DS) || r_type == R_PPC64_TOC16_LO_DS)
{ {
if (tls_mask != 0 if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & (TLS_DTPREL | TLS_TPREL)) == 0) && (tls_mask & (TLS_DTPREL | TLS_TPREL)) == 0)
goto toctprel; goto toctprel;
} }
@ -13701,12 +13731,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
if (retval == 2) if (retval == 2)
{ {
tls_gd = TLS_TPRELGD; tls_gd = TLS_TPRELGD;
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_GD) == 0)
goto tls_ldgd_opt; goto tls_ldgd_opt;
} }
else if (retval == 3) else if (retval == 3)
{ {
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_LD) == 0)
goto tls_ldgd_opt; goto tls_ldgd_opt;
} }
} }
@ -13716,7 +13748,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TPREL16_HI: case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA: case R_PPC64_GOT_TPREL16_HA:
if (tls_mask != 0 if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_TPREL) == 0) && (tls_mask & TLS_TPREL) == 0)
{ {
rel->r_offset -= d_offset; rel->r_offset -= d_offset;
@ -13728,7 +13760,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TPREL16_DS: case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_TPREL16_LO_DS: case R_PPC64_GOT_TPREL16_LO_DS:
if (tls_mask != 0 if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_TPREL) == 0) && (tls_mask & TLS_TPREL) == 0)
{ {
toctprel: toctprel:
@ -13753,7 +13785,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
break; break;
case R_PPC64_TLS: case R_PPC64_TLS:
if (tls_mask != 0 if ((tls_mask & TLS_TLS) != 0
&& (tls_mask & TLS_TPREL) == 0) && (tls_mask & TLS_TPREL) == 0)
{ {
insn = bfd_get_32 (input_bfd, contents + rel->r_offset); insn = bfd_get_32 (input_bfd, contents + rel->r_offset);
@ -13781,13 +13813,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TLSGD16_HI: case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA: case R_PPC64_GOT_TLSGD16_HA:
tls_gd = TLS_TPRELGD; tls_gd = TLS_TPRELGD;
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
goto tls_gdld_hi; goto tls_gdld_hi;
break; break;
case R_PPC64_GOT_TLSLD16_HI: case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA: case R_PPC64_GOT_TLSLD16_HA:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
{ {
tls_gdld_hi: tls_gdld_hi:
if ((tls_mask & tls_gd) != 0) if ((tls_mask & tls_gd) != 0)
@ -13806,13 +13838,13 @@ ppc64_elf_relocate_section (bfd *output_bfd,
case R_PPC64_GOT_TLSGD16: case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO: case R_PPC64_GOT_TLSGD16_LO:
tls_gd = TLS_TPRELGD; tls_gd = TLS_TPRELGD;
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0)
goto tls_ldgd_opt; goto tls_ldgd_opt;
break; break;
case R_PPC64_GOT_TLSLD16: case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0)
{ {
unsigned int insn1, insn2; unsigned int insn1, insn2;
bfd_vma offset; bfd_vma offset;
@ -13905,7 +13937,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
break; break;
case R_PPC64_TLSGD: case R_PPC64_TLSGD:
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0 if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_GD) == 0
&& rel + 1 < relend) && rel + 1 < relend)
{ {
unsigned int insn2; unsigned int insn2;
@ -13940,7 +13972,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
break; break;
case R_PPC64_TLSLD: case R_PPC64_TLSLD:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0 if ((tls_mask & TLS_TLS) != 0 && (tls_mask & TLS_LD) == 0
&& rel + 1 < relend) && rel + 1 < relend)
{ {
unsigned int insn2; unsigned int insn2;