PowerPC indirect calls to __tls_get_addr
authorAlan Modra <amodra@gmail.com>
Sun, 8 Apr 2018 23:41:44 +0000 (09:11 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 9 Apr 2018 07:23:05 +0000 (16:53 +0930)
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.

bfd/ChangeLog
bfd/elf32-ppc.c
bfd/elf64-ppc.c

index a8eaebb..99f5639 100644 (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>
 
        * elf64-x86-64.c (elf_x86_64_info_to_howto): Don't mask out
index c82e405..5377461 100644 (file)
@@ -3226,20 +3226,30 @@ struct ppc_elf_link_hash_entry
   /* Track dynamic relocs copied for this symbol.  */
   struct elf_dyn_relocs *dyn_relocs;
 
-  /* Contexts in which symbol is used in the GOT (or TOC).
-     TLS_GD .. TLS_TLS bits are or'd into the mask as the
-     corresponding relocs are encountered during check_relocs.
-     tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
-     indicate the corresponding GOT entry type is not needed.  */
-#define TLS_GD          1      /* GD reloc. */
-#define TLS_LD          2      /* LD reloc. */
-#define TLS_TPREL       4      /* TPREL reloc, => IE. */
-#define TLS_DTPREL      8      /* DTPREL reloc, => LD. */
-#define TLS_TLS                16      /* Any TLS reloc.  */
-#define TLS_TPRELGD    32      /* TPREL reloc resulting from GD->IE. */
-#define PLT_IFUNC      64      /* STT_GNU_IFUNC.  */
+  /* Contexts in which symbol is used in the GOT.
+     Bits are or'd into the mask as the corresponding relocs are
+     encountered during check_relocs, with TLS_TLS being set when any
+     of the other TLS bits are set.  tls_optimize clears bits when
+     optimizing to indicate the corresponding GOT entry type is not
+     needed.  If set, TLS_TLS is never cleared.  tls_optimize may also
+     set TLS_TPRELGD when a GD reloc turns into a TPREL one.  We use a
+     separate flag rather than setting TPREL just for convenience in
+     distinguishing the two cases.
+     These flags are also kept for local symbols.  */
+#define TLS_TLS                 1      /* Any TLS reloc.  */
+#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;
 
+  /* 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
      symbol.  */
   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_got_tls_masks = (unsigned char *) (local_plt + symtab_hdr->sh_info);
-  local_got_tls_masks[r_symndx] |= tls_type;
-  if (tls_type != PLT_IFUNC)
+  local_got_tls_masks[r_symndx] |= tls_type & 0xff;
+  if ((tls_type & NON_GOT) == 0)
     local_got_refcounts[r_symndx] += 1;
   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.  */
              ifunc = update_local_sym_info (abfd, symtab_hdr, r_symndx,
-                                            PLT_IFUNC);
+                                            NON_GOT | PLT_IFUNC);
              if (ifunc == NULL)
                return FALSE;
 
@@ -4083,6 +4093,12 @@ ppc_elf_check_relocs (bfd *abfd,
        case R_PPC_TLSLD:
          /* These special tls relocs tie a call to __tls_get_addr with
             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;
 
        case R_PPC_GOT_TLSLD16:
@@ -5212,7 +5228,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                  unsigned long r_symndx;
                  struct elf_link_hash_entry *h = NULL;
                  unsigned char *tls_mask;
-                 char tls_set, tls_clear;
+                 unsigned char tls_set, tls_clear;
                  bfd_boolean is_local;
                  bfd_signed_vma *got_count;
 
@@ -5341,23 +5357,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED,
                      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)
                    {
                      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];
                    }
 
+                 /* 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)
                    {
                      /* 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
      condition as that for IE, but ld.so needs to differentiate
      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;
   return need * sizeof (Elf32_External_Rela) / 4;
 }
@@ -5838,7 +5868,7 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
        return FALSE;
 
       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)
            /* 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));
 
              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);
              rsec = htab->elf.srelgot;
              if (eh->elf.type == STT_GNU_IFUNC)
@@ -6272,7 +6303,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
        if (*local_got > 0)
          {
            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;
            need = got_entries_needed (*lgot_masks);
            if (need == 0)
@@ -6287,7 +6318,7 @@ ppc_elf_size_dynamic_sections (bfd *output_bfd,
 
                    need = got_relocs_needed (*lgot_masks, need, tprel_known);
                    srel = htab->elf.srelgot;
-                   if ((*lgot_masks & PLT_IFUNC) != 0)
+                   if ((*lgot_masks & (TLS_TLS | PLT_IFUNC)) == PLT_IFUNC)
                      srel = htab->elf.irelplt;
                    srel->size += need;
                  }
@@ -8425,9 +8456,10 @@ ppc_elf_relocate_section (bfd *output_bfd,
              off &= ~1;
            else
              {
-               unsigned int tls_m = (tls_mask
-                                     & (TLS_LD | TLS_GD | TLS_DTPREL
-                                        | TLS_TPREL | TLS_TPRELGD));
+               unsigned int tls_m = ((tls_mask & TLS_TLS) != 0
+                                     ? tls_mask & (TLS_LD | TLS_GD | TLS_DTPREL
+                                                   | TLS_TPREL | TLS_TPRELGD)
+                                     : 0);
 
                if (offp == &htab->tlsld_got.offset)
                  tls_m = TLS_LD;
index 751ad77..4226120 100644 (file)
@@ -4046,22 +4046,29 @@ struct ppc_link_hash_entry
   unsigned int non_zero_localentry:1;
 
   /* Contexts in which symbol is used in the GOT (or TOC).
-     TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the
-     corresponding relocs are encountered during check_relocs.
-     tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to
-     indicate the corresponding GOT entry type is not needed.
-     tls_optimize may also set TLS_TPRELGD when a GD reloc turns into
-     a TPREL one.  We use a separate flag rather than setting TPREL
-     just for convenience in distinguishing the two cases.  */
-#define TLS_GD          1      /* GD reloc. */
-#define TLS_LD          2      /* LD reloc. */
-#define TLS_TPREL       4      /* TPREL reloc, => IE. */
-#define TLS_DTPREL      8      /* DTPREL reloc, => LD. */
-#define TLS_TLS                16      /* Any TLS reloc.  */
-#define TLS_EXPLICIT   32      /* Marks TOC section TLS relocs. */
+     Bits are or'd into the mask as the corresponding relocs are
+     encountered during check_relocs, with TLS_TLS being set when any
+     of the other TLS bits are set.  tls_optimize clears bits when
+     optimizing to indicate the corresponding GOT entry type is not
+     needed.  If set, TLS_TLS is never cleared.  tls_optimize may also
+     set TLS_TPRELGD when a GD reloc turns into a TPREL one.  We use a
+     separate flag rather than setting TPREL just for convenience in
+     distinguishing the two cases.
+     These flags are also kept for local symbols.  */
+#define TLS_TLS                 1      /* Any TLS reloc.  */
+#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. */
-#define PLT_IFUNC      128     /* STT_GNU_IFUNC.  */
+#define TLS_EXPLICIT   128     /* Marks TOC section TLS relocs. */
   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.  */
@@ -5337,7 +5344,7 @@ update_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr,
       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;
 
@@ -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_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;
 }
@@ -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)
            {
              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)
                return FALSE;
            }
@@ -5504,6 +5512,14 @@ ppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info,
        case R_PPC64_TLSLD:
          /* These special tls relocs tie a call to __tls_get_addr with
             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;
 
        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))
     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
       || ppc64_elf_section_data (sec) == NULL
       || 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;
                              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;
                                  if (retval > 1)
                                    toc_ref[toc_ref_index] = 1;
@@ -8674,9 +8693,6 @@ ppc64_elf_tls_optimize (struct bfd_link_info *info)
                          continue;
                        }
 
-                     if (expecting_tls_get_addr != 1)
-                       continue;
-
                      /* Uh oh, we didn't find the expected call.  We
                         could just mark this symbol to exclude it
                         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;
                    }
 
+                 /* 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)
                    {
                      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;
   /* Run through the TLS GD got entries first if we're changing them
      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)
       if (gent->got.refcount > 0
          && (gent->tls_type & TLS_GD) != 0)
@@ -10074,7 +10104,7 @@ ppc64_elf_size_dynamic_sections (bfd *output_bfd,
                        rel_size *= 2;
                      }
                    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->got_reli_size += rel_size;
@@ -11701,7 +11731,7 @@ ppc64_elf_layout_multitoc (struct bfd_link_info *info)
                  rel_size *= 2;
                }
              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->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,
                                         irela - 1, input_bfd))
                        goto error_ret_free_internal;
-                     if (*tls_mask != 0)
+                     if ((*tls_mask & TLS_TLS) != 0)
                        continue;
                    }
 
@@ -13596,7 +13626,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
            (local_plt + symtab_hdr->sh_info);
          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_TLSGD
              || r_type == R_PPC64_TLSLD))
@@ -13624,7 +13654,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                  || (sym_type == STT_SECTION
                      && (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_TLSGD
                  || r_type == R_PPC64_TLSLD))
@@ -13690,7 +13720,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                if (r_type == R_PPC64_TOC16_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)
                      goto toctprel;
                  }
@@ -13701,12 +13731,14 @@ ppc64_elf_relocate_section (bfd *output_bfd,
                    if (retval == 2)
                      {
                        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;
                      }
                    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;
                      }
                  }
@@ -13716,7 +13748,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
 
        case R_PPC64_GOT_TPREL16_HI:
        case R_PPC64_GOT_TPREL16_HA:
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
              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_LO_DS:
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
            toctprel:
@@ -13753,7 +13785,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        case R_PPC64_TLS:
-         if (tls_mask != 0
+         if ((tls_mask & TLS_TLS) != 0
              && (tls_mask & TLS_TPREL) == 0)
            {
              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_HA:
          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;
          break;
 
        case R_PPC64_GOT_TLSLD16_HI:
        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:
              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_LO:
          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;
          break;
 
        case R_PPC64_GOT_TLSLD16:
        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;
              bfd_vma offset;
@@ -13905,7 +13937,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        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)
            {
              unsigned int insn2;
@@ -13940,7 +13972,7 @@ ppc64_elf_relocate_section (bfd *output_bfd,
          break;
 
        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)
            {
              unsigned int insn2;