mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 11:00:01 +08:00
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:
@ -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
|
||||||
|
114
bfd/elf32-ppc.c
114
bfd/elf32-ppc.c
@ -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;
|
||||||
|
112
bfd/elf64-ppc.c
112
bfd/elf64-ppc.c
@ -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;
|
||||||
|
Reference in New Issue
Block a user