type suitable for optimization, and 1 otherwise. */
static int
-get_tls_mask (char **tls_maskp, Elf_Internal_Sym **locsymsp,
+get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
+ Elf_Internal_Sym **locsymsp,
const Elf_Internal_Rela *rel, bfd *ibfd)
{
unsigned long r_symndx;
- unsigned int next_r;
+ int next_r;
struct elf_link_hash_entry *h;
Elf_Internal_Sym *sym;
asection *sec;
next_r = ppc64_elf_section_data (sec)->t_symndx[off / 8 + 1];
if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
return 0;
- if (h == NULL
- || h->root.type == bfd_link_hash_defined
- || h->root.type == bfd_link_hash_defweak)
- {
- if (next_r == (unsigned) -1)
- return 2;
- if (next_r == (unsigned) -2
- && (h == NULL
- || !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
- return 3;
- }
+ if (toc_symndx != NULL)
+ *toc_symndx = r_symndx;
+ if ((h == NULL
+ || ((h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && !(h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC)))
+ && (next_r == -1 || next_r == -2))
+ return 1 - next_r;
return 1;
}
char *toc_tls;
int retval;
- retval = get_tls_mask (&toc_tls, &locsyms,
+ retval = get_tls_mask (&toc_tls, NULL, &locsyms,
rel - 1, ibfd);
if (retval == 0)
goto err_free_rel;
/* Get tls info. */
char *tls_mask;
- if (!get_tls_mask (&tls_mask, &local_syms,
+ if (!get_tls_mask (&tls_mask, NULL, &local_syms,
irela - 1, input_bfd))
goto error_ret_free_internal;
if (*tls_mask != 0)
struct elf_link_hash_entry *h;
struct elf_link_hash_entry *fdh;
const char *sym_name;
- unsigned long r_symndx;
+ unsigned long r_symndx, toc_symndx;
char tls_mask, tls_gd, tls_type;
+ char sym_type;
bfd_vma relocation;
bfd_boolean unresolved_reloc;
bfd_boolean warned;
sym = local_syms + r_symndx;
sec = local_sections[r_symndx];
sym_name = bfd_elf_local_sym_name (input_bfd, sym);
+ sym_type = ELF64_ST_TYPE (sym->st_info);
relocation = _bfd_elf_rela_local_sym (output_bfd, sym, sec, rel);
if (elf_section_data (sec) != NULL)
{
unresolved_reloc, info,
warned);
sym_name = h->root.root.string;
+ sym_type = h->type;
}
/* TLS optimizations. Replace instruction sequences and relocs
for the final instruction stream. */
tls_mask = 0;
tls_gd = 0;
+ toc_symndx = 0;
if (IS_PPC64_TLS_RELOC (r_type))
{
if (h != NULL)
lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
tls_mask = lgot_masks[r_symndx];
}
+ if (tls_mask == 0 && r_type == R_PPC64_TLS)
+ {
+ /* Check for toc tls entries. */
+ char *toc_tls;
+
+ if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
+ rel, input_bfd))
+ return FALSE;
+
+ if (toc_tls)
+ tls_mask = *toc_tls;
+ }
+ }
+
+ /* Check that tls relocs are used with tls syms, and non-tls
+ relocs are used with non-tls syms. */
+ if (r_symndx != 0
+ && r_type != R_PPC64_NONE
+ && (h == NULL
+ || h->root.type == bfd_link_hash_defined
+ || h->root.type == bfd_link_hash_defweak)
+ && IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS))
+ {
+ if (r_type == R_PPC64_TLS && tls_mask != 0)
+ /* R_PPC64_TLS is OK against a symbol in the TOC. */
+ ;
+ else
+ (*_bfd_error_handler)
+ (sym_type == STT_TLS
+ ? _("%s(%s+0x%lx): %s used with TLS symbol %s")
+ : _("%s(%s+0x%lx): %s used with non-TLS symbol %s"),
+ bfd_archive_filename (input_bfd),
+ input_section->name,
+ (long) rel->r_offset,
+ ppc64_elf_howto_table[r_type]->name,
+ sym_name);
}
/* Ensure reloc mapping code below stays sane. */
|| (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TPREL16_HI & 3)
|| (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TPREL16_HA & 3))
abort ();
+
switch (r_type)
{
default:
char *toc_tls;
int retval;
- retval = get_tls_mask (&toc_tls, &local_syms, rel, input_bfd);
+ retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
+ rel, input_bfd);
if (retval == 0)
return FALSE;
insn |= 0x3c0d0000; /* addis 0,13,0 */
bfd_put_32 (output_bfd, insn, contents + rel->r_offset - 2);
r_type = R_PPC64_TPREL16_HA;
- rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ if (toc_symndx != 0)
+ {
+ rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+ /* We changed the symbol. Start over in order to
+ get h, sym, sec etc. right. */
+ rel--;
+ continue;
+ }
+ else
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
}
break;
case R_PPC64_TLS:
- if (tls_mask == 0)
- {
- /* Check for toc tls entries. */
- char *toc_tls;
-
- if (!get_tls_mask (&toc_tls, &local_syms, rel, input_bfd))
- return FALSE;
-
- if (toc_tls)
- tls_mask = *toc_tls;
- }
if (tls_mask != 0
&& (tls_mask & TLS_TPREL) == 0)
{
abort ();
insn |= rtra;
bfd_put_32 (output_bfd, insn, contents + rel->r_offset);
- r_type = R_PPC64_TPREL16_LO;
- rel->r_info = ELF64_R_INFO (r_symndx, r_type);
/* Was PPC64_TLS which sits on insn boundary, now
PPC64_TPREL16_LO which is at insn+2. */
rel->r_offset += 2;
+ r_type = R_PPC64_TPREL16_LO;
+ if (toc_symndx != 0)
+ {
+ rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+ /* We changed the symbol. Start over in order to
+ get h, sym, sec etc. right. */
+ rel--;
+ continue;
+ }
+ else
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
}
break;
rel->r_addend = htab->tls_sec->vma + DTP_OFFSET;
rel[1].r_addend = htab->tls_sec->vma + DTP_OFFSET;
}
+ else if (toc_symndx != 0)
+ r_symndx = toc_symndx;
r_type = R_PPC64_TPREL16_HA;
rel->r_info = ELF64_R_INFO (r_symndx, r_type);
rel[1].r_info = ELF64_R_INFO (r_symndx,
bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - 2);
bfd_put_32 (output_bfd, insn2, contents + offset);
bfd_put_32 (output_bfd, insn3, contents + offset + 4);
- if (tls_gd == 0)
+ if (tls_gd == 0 || toc_symndx != 0)
{
- /* We changed the symbol on an LD reloc. Start over
- in order to get h, sym, sec etc. right. */
+ /* We changed the symbol. Start over in order
+ to get h, sym, sec etc. right. */
rel--;
continue;
}