From 37da22e5c85375b30e1211ecff1b261f425375f0 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 9 Apr 2018 09:11:44 +0930 Subject: [PATCH] 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. --- bfd/ChangeLog | 24 ++++++++++++ bfd/elf32-ppc.c | 114 ++++++++++++++++++++++++++++++++++++-------------------- bfd/elf64-ppc.c | 112 +++++++++++++++++++++++++++++++++++-------------------- 3 files changed, 169 insertions(+), 81 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a8eaebb..99f5639 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,27 @@ +2018-04-09 Alan Modra + + * 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 * elf64-x86-64.c (elf_x86_64_info_to_howto): Don't mask out diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index c82e405..5377461 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -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; diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 751ad77..4226120 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -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; -- 2.7.4