/* PowerPC64-specific support for 64-bit ELF.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
Written by Linus Nordberg, Swox AB <info@swox.com>,
based on elf32-ppc.c by Ian Lance Taylor.
Largely rewritten by Alan Modra <amodra@bigpond.net.au>
0xfffc, /* dst_mask */
FALSE), /* pcrel_offset */
- /* Marker reloc for TLS. */
+ /* Marker relocs for TLS. */
HOWTO (R_PPC64_TLS,
0, /* rightshift */
2, /* size (0 = byte, 1 = short, 2 = long) */
0, /* dst_mask */
FALSE), /* pcrel_offset */
+ HOWTO (R_PPC64_TLSGD,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC64_TLSGD", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
+ HOWTO (R_PPC64_TLSLD,
+ 0, /* rightshift */
+ 2, /* size (0 = byte, 1 = short, 2 = long) */
+ 32, /* bitsize */
+ FALSE, /* pc_relative */
+ 0, /* bitpos */
+ complain_overflow_dont, /* complain_on_overflow */
+ bfd_elf_generic_reloc, /* special_function */
+ "R_PPC64_TLSLD", /* name */
+ FALSE, /* partial_inplace */
+ 0, /* src_mask */
+ 0, /* dst_mask */
+ FALSE), /* pcrel_offset */
+
/* Computes the load module index of the load module that contains the
definition of its TLS sym. */
HOWTO (R_PPC64_DTPMOD64,
break;
case BFD_RELOC_PPC_TLS: r = R_PPC64_TLS;
break;
+ case BFD_RELOC_PPC_TLSGD: r = R_PPC64_TLSGD;
+ break;
+ case BFD_RELOC_PPC_TLSLD: r = R_PPC64_TLSLD;
+ break;
case BFD_RELOC_PPC_DTPMOD: r = R_PPC64_DTPMOD64;
break;
case BFD_RELOC_PPC_TPREL16: r = R_PPC64_TPREL16;
long *adjust;
} opd;
- /* An array for toc sections, indexed by offset/8.
- Specifies the relocation symbol index used at a given toc offset. */
- unsigned *t_symndx;
+ /* An array for toc sections, indexed by offset/8. */
+ struct _toc_sec_data
+ {
+ /* Specifies the relocation symbol index used at a given toc offset. */
+ unsigned *symndx;
+
+ /* And the relocation addend. */
+ bfd_vma *add;
+ } toc;
} u;
enum _ppc64_sec_type sec_type:2;
}
\f
/* Parameters for the qsort hook. */
-static asection *synthetic_opd;
static bfd_boolean synthetic_relocatable;
/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */
return 1;
/* then .opd symbols. */
- if (a->section == synthetic_opd && b->section != synthetic_opd)
+ if (strcmp (a->section->name, ".opd") == 0
+ && strcmp (b->section->name, ".opd") != 0)
return -1;
- if (a->section != synthetic_opd && b->section == synthetic_opd)
+ if (strcmp (a->section->name, ".opd") != 0
+ && strcmp (b->section->name, ".opd") == 0)
return 1;
/* then other code symbols. */
else
memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms));
- synthetic_opd = opd;
synthetic_relocatable = relocatable;
qsort (syms, symcount, sizeof (*syms), compare_symbols);
}
i = 0;
- if (syms[i]->section == opd)
+ if (strcmp (syms[i]->section->name, ".opd") == 0)
++i;
codesecsym = i;
secsymend = i;
for (; i < symcount; ++i)
- if (syms[i]->section != opd)
+ if (strcmp (syms[i]->section->name, ".opd") != 0)
break;
opdsymend = i;
const Elf_Internal_Rela *rel_end;
asection *sreloc;
asection **opd_sym_map;
+ struct elf_link_hash_entry *tga, *dottga;
if (info->relocatable)
return TRUE;
BFD_ASSERT (is_ppc64_elf (abfd));
htab = ppc_hash_table (info);
+ tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+ FALSE, FALSE, TRUE);
+ dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+ FALSE, FALSE, TRUE);
symtab_hdr = &elf_symtab_hdr (abfd);
sym_hashes = elf_sym_hashes (abfd);
unsigned long r_symndx;
struct elf_link_hash_entry *h;
enum elf_ppc64_reloc_type r_type;
- int tls_type = 0;
+ int tls_type;
struct _ppc64_elf_section_data *ppc64_sec;
r_symndx = ELF64_R_SYM (rel->r_info);
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
+ tls_type = 0;
r_type = ELF64_R_TYPE (rel->r_info);
+ if (h != NULL && (h == tga || h == dottga))
+ switch (r_type)
+ {
+ default:
+ break;
+
+ case R_PPC64_REL24:
+ case R_PPC64_REL14:
+ case R_PPC64_REL14_BRTAKEN:
+ case R_PPC64_REL14_BRNTAKEN:
+ case R_PPC64_ADDR24:
+ case R_PPC64_ADDR14:
+ case R_PPC64_ADDR14_BRTAKEN:
+ case R_PPC64_ADDR14_BRNTAKEN:
+ if (rel != relocs
+ && (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+ || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+ /* We have a new-style __tls_get_addr call with a marker
+ reloc. */
+ ;
+ else
+ /* Mark this section as having an old-style call. */
+ sec->has_tls_get_addr_call = 1;
+ break;
+ }
+
switch (r_type)
{
+ case R_PPC64_TLSGD:
+ case R_PPC64_TLSLD:
+ /* These special tls relocs tie a call to __tls_get_addr with
+ its parameter symbol. */
+ break;
+
case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
rel->r_addend))
return FALSE;
- if (h == &htab->tls_get_addr->elf
- || h == &htab->tls_get_addr_fd->elf)
+ if (h == tga || h == dottga)
sec->has_tls_reloc = 1;
- else if (htab->tls_get_addr == NULL
- && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr")
- && (h->root.root.string[15] == 0
- || h->root.root.string[15] == '@'))
- {
- htab->tls_get_addr = (struct ppc_link_hash_entry *) h;
- sec->has_tls_reloc = 1;
- }
- else if (htab->tls_get_addr_fd == NULL
- && CONST_STRNEQ (h->root.root.string, "__tls_get_addr")
- && (h->root.root.string[14] == 0
- || h->root.root.string[14] == '@'))
- {
- htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h;
- sec->has_tls_reloc = 1;
- }
}
break;
ppc64_sec = ppc64_elf_section_data (sec);
if (ppc64_sec->sec_type != sec_toc)
{
+ bfd_size_type amt;
+
/* One extra to simplify get_tls_mask. */
- bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1;
- ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt);
- if (ppc64_sec->u.t_symndx == NULL)
+ amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
+ ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
+ if (ppc64_sec->u.toc.symndx == NULL)
+ return FALSE;
+ amt = sec->size * sizeof (bfd_vma) / 8;
+ ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
+ if (ppc64_sec->u.toc.add == NULL)
return FALSE;
BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
ppc64_sec->sec_type = sec_toc;
}
BFD_ASSERT (rel->r_offset % 8 == 0);
- ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx;
+ ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
+ ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
/* Mark the second slot of a GD or LD entry.
-1 to indicate GD and -2 to indicate LD. */
if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD))
- ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1;
+ ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1;
else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD))
- ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2;
+ ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2;
goto dodyn;
case R_PPC64_TPREL16:
this reloc. */
if (sreloc == NULL)
{
- const char *name;
- bfd *dynobj;
-
- name = (bfd_elf_string_from_elf_section
- (abfd,
- elf_elfheader (abfd)->e_shstrndx,
- elf_section_data (sec)->rel_hdr.sh_name));
- if (name == NULL)
- return FALSE;
+ sreloc = _bfd_elf_make_dynamic_reloc_section
+ (sec, htab->elf.dynobj, 3, abfd, /*rela?*/ TRUE);
- if (! CONST_STRNEQ (name, ".rela")
- || strcmp (bfd_get_section_name (abfd, sec),
- name + 5) != 0)
- {
- (*_bfd_error_handler)
- (_("%B: bad relocation section name `%s\'"),
- abfd, name);
- bfd_set_error (bfd_error_bad_value);
- }
-
- dynobj = htab->elf.dynobj;
- sreloc = bfd_get_section_by_name (dynobj, name);
if (sreloc == NULL)
- {
- flagword flags;
-
- flags = (SEC_HAS_CONTENTS | SEC_READONLY
- | SEC_IN_MEMORY | SEC_LINKER_CREATED
- | SEC_ALLOC | SEC_LOAD);
- sreloc = bfd_make_section_with_flags (dynobj,
- name,
- flags);
- if (sreloc == NULL
- || ! bfd_set_section_alignment (dynobj, sreloc, 3))
- return FALSE;
- }
- elf_section_data (sec)->sreloc = sreloc;
+ return FALSE;
}
/* If this is a global symbol, we count the number of
fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link;
if (fdh == NULL
- && info->shared
+ && !info->executable
&& (fh->elf.root.type == bfd_link_hash_undefined
|| fh->elf.root.type == bfd_link_hash_undefweak))
{
if (fdh != NULL
&& !fdh->elf.forced_local
- && (info->shared
+ && (!info->executable
|| fdh->elf.def_dynamic
|| fdh->elf.ref_dynamic
|| (fdh->elf.root.type == bfd_link_hash_undefweak
type suitable for optimization, and 1 otherwise. */
static int
-get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
+get_tls_mask (char **tls_maskp,
+ unsigned long *toc_symndx,
+ bfd_vma *toc_addend,
Elf_Internal_Sym **locsymsp,
- const Elf_Internal_Rela *rel, bfd *ibfd)
+ const Elf_Internal_Rela *rel,
+ bfd *ibfd)
{
unsigned long r_symndx;
int next_r;
off = sym->st_value;
off += rel->r_addend;
BFD_ASSERT (off % 8 == 0);
- r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8];
- next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1];
- if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
- return 0;
+ r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8];
+ next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1];
if (toc_symndx != NULL)
*toc_symndx = r_symndx;
+ if (toc_addend != NULL)
+ *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
+ 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)
struct ppc_link_hash_table *htab;
htab = ppc_hash_table (info);
- if (htab->tls_get_addr != NULL)
- {
- struct ppc_link_hash_entry *h = htab->tls_get_addr;
-
- while (h->elf.root.type == bfd_link_hash_indirect
- || h->elf.root.type == bfd_link_hash_warning)
- h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+ htab->tls_get_addr = ((struct ppc_link_hash_entry *)
+ elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+ FALSE, FALSE, TRUE));
+ htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
+ elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+ FALSE, FALSE, TRUE));
+ return _bfd_elf_tls_setup (obfd, info);
+}
- htab->tls_get_addr = h;
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+ HASH1 or HASH2. */
- if (htab->tls_get_addr_fd == NULL
- && h->oh != NULL
- && h->oh->is_func_descriptor
- && (h->oh->elf.root.type == bfd_link_hash_defined
- || h->oh->elf.root.type == bfd_link_hash_defweak))
- htab->tls_get_addr_fd = h->oh;
- }
-
- if (htab->tls_get_addr_fd != NULL)
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+ const Elf_Internal_Rela *rel,
+ const struct ppc_link_hash_entry *hash1,
+ const struct ppc_link_hash_entry *hash2)
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+ enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
+ unsigned int r_symndx = ELF64_R_SYM (rel->r_info);
+
+ if (r_symndx >= symtab_hdr->sh_info
+ && (r_type == R_PPC64_REL24
+ || r_type == R_PPC64_REL14
+ || r_type == R_PPC64_REL14_BRTAKEN
+ || r_type == R_PPC64_REL14_BRNTAKEN
+ || r_type == R_PPC64_ADDR24
+ || r_type == R_PPC64_ADDR14
+ || r_type == R_PPC64_ADDR14_BRTAKEN
+ || r_type == R_PPC64_ADDR14_BRNTAKEN))
{
- struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;
-
- while (h->elf.root.type == bfd_link_hash_indirect
- || h->elf.root.type == bfd_link_hash_warning)
- h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+ struct elf_link_hash_entry *h;
- htab->tls_get_addr_fd = h;
+ h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+ while (h->root.type == bfd_link_hash_indirect
+ || h->root.type == bfd_link_hash_warning)
+ h = (struct elf_link_hash_entry *) h->root.u.i.link;
+ if (h == &hash1->elf || h == &hash2->elf)
+ return TRUE;
}
-
- return _bfd_elf_tls_setup (obfd, info);
+ return FALSE;
}
/* Run through all the TLS relocs looking for optimization
case R_PPC64_TOC16:
case R_PPC64_TOC16_LO:
case R_PPC64_TLS:
+ case R_PPC64_TLSGD:
+ case R_PPC64_TLSLD:
if (sym_sec == NULL || sym_sec != toc)
continue;
value += rel->r_addend;
BFD_ASSERT (value < toc->size && value % 8 == 0);
toc_ref_index = value / 8;
- if (r_type == R_PPC64_TLS)
+ if (r_type == R_PPC64_TLS
+ || r_type == R_PPC64_TLSGD
+ || r_type == R_PPC64_TLSLD)
{
toc_ref[toc_ref_index] = 1;
continue;
if (pass == 0)
{
- if (!expecting_tls_get_addr)
+ if (!expecting_tls_get_addr
+ || !sec->has_tls_get_addr_call)
continue;
- if (rel + 1 < relend)
+ if (rel + 1 < relend
+ && branch_reloc_hash_match (ibfd, rel + 1,
+ htab->tls_get_addr,
+ htab->tls_get_addr_fd))
{
- Elf_Internal_Shdr *symtab_hdr;
- enum elf_ppc64_reloc_type r_type2;
- unsigned long r_symndx2;
- struct elf_link_hash_entry *h2;
-
- symtab_hdr = &elf_symtab_hdr (ibfd);
-
- /* The next instruction should be a call to
- __tls_get_addr. Peek at the reloc to be sure. */
- r_type2 = ELF64_R_TYPE (rel[1].r_info);
- r_symndx2 = ELF64_R_SYM (rel[1].r_info);
- if (r_symndx2 >= symtab_hdr->sh_info
- && (r_type2 == R_PPC64_REL14
- || r_type2 == R_PPC64_REL14_BRTAKEN
- || r_type2 == R_PPC64_REL14_BRNTAKEN
- || r_type2 == R_PPC64_REL24))
+ if (expecting_tls_get_addr == 2)
{
- struct elf_link_hash_entry **sym_hashes;
-
- sym_hashes = elf_sym_hashes (ibfd);
-
- h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
- while (h2->root.type == bfd_link_hash_indirect
- || h2->root.type == bfd_link_hash_warning)
- h2 = ((struct elf_link_hash_entry *)
- h2->root.u.i.link);
- if (h2 != NULL
- && (h2 == &htab->tls_get_addr->elf
- || h2 == &htab->tls_get_addr_fd->elf))
- {
- if (expecting_tls_get_addr == 2)
- {
- /* Check for toc tls entries. */
- char *toc_tls;
- int retval;
-
- retval = get_tls_mask (&toc_tls, NULL,
- &locsyms,
- rel, ibfd);
- if (retval == 0)
- goto err_free_rel;
- if (retval > 1 && toc_tls != NULL)
- toc_ref[toc_ref_index] = 1;
- }
- continue;
- }
+ /* Check for toc tls entries. */
+ char *toc_tls;
+ int retval;
+
+ retval = get_tls_mask (&toc_tls, NULL, NULL,
+ &locsyms,
+ rel, ibfd);
+ if (retval == 0)
+ goto err_free_rel;
+ if (retval > 1 && toc_tls != NULL)
+ toc_ref[toc_ref_index] = 1;
}
+ continue;
}
if (expecting_tls_get_addr != 1)
free (relstart);
}
- if (toc_ref != NULL)
- free (toc_ref);
+ if (toc_ref != NULL)
+ free (toc_ref);
- if (locsyms != NULL
- && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
- {
- if (!info->keep_memory)
- free (locsyms);
- else
- elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
- }
- }
+ if (locsyms != NULL
+ && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
+ {
+ if (!info->keep_memory)
+ free (locsyms);
+ else
+ elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
+ }
+ }
return TRUE;
}
/* Get tls info. */
char *tls_mask;
- if (!get_tls_mask (&tls_mask, NULL, &local_syms,
+ if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
irela - 1, input_bfd))
goto error_ret_free_internal;
if (*tls_mask != 0)
struct ppc_link_hash_entry *fdh;
const char *sym_name;
unsigned long r_symndx, toc_symndx;
+ bfd_vma toc_addend;
char tls_mask, tls_gd, tls_type;
char sym_type;
bfd_vma relocation;
tls_mask = 0;
tls_gd = 0;
toc_symndx = 0;
- if (IS_PPC64_TLS_RELOC (r_type))
+ if (h != NULL)
+ tls_mask = h->tls_mask;
+ else if (local_got_ents != NULL)
{
- if (h != NULL)
- tls_mask = h->tls_mask;
- else if (local_got_ents != NULL)
- {
- char *lgot_masks;
- 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;
+ char *lgot_masks;
+ 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
+ || r_type == R_PPC64_TLSGD
+ || r_type == R_PPC64_TLSLD))
+ {
+ /* Check for toc tls entries. */
+ char *toc_tls;
- if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
- rel, input_bfd))
- return FALSE;
+ if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+ &local_syms, rel, input_bfd))
+ return FALSE;
- if (toc_tls)
- tls_mask = *toc_tls;
- }
+ if (toc_tls)
+ tls_mask = *toc_tls;
}
/* Check that tls relocs are used with tls syms, and non-tls
|| (sym_type == STT_SECTION
&& (sec->flags & SEC_THREAD_LOCAL) != 0))))
{
- if (r_type == R_PPC64_TLS && tls_mask != 0)
+ if (tls_mask != 0
+ && (r_type == R_PPC64_TLS
+ || r_type == R_PPC64_TLSGD
+ || r_type == R_PPC64_TLSLD))
/* R_PPC64_TLS is OK against a symbol in the TOC. */
;
else
char *toc_tls;
int retval;
- retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
- rel, input_bfd);
+ retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+ &local_syms, rel, input_bfd);
if (retval == 0)
return FALSE;
if (toc_symndx != 0)
{
rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+ rel->r_addend = toc_addend;
/* We changed the symbol. Start over in order to
get h, sym, sec etc. right. */
rel--;
if (toc_symndx != 0)
{
rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+ rel->r_addend = toc_addend;
/* We changed the symbol. Start over in order to
get h, sym, sec etc. right. */
rel--;
case R_PPC64_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
{
- bfd_vma insn1, insn2, insn3;
+ unsigned int insn1, insn2, insn3;
bfd_vma offset;
tls_ldgd_opt:
- /* We know that the next reloc is on a tls_get_addr
- call, since ppc64_elf_tls_optimize checks this. */
- offset = rel[1].r_offset;
- insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - d_offset);
- insn3 = bfd_get_32 (output_bfd,
- contents + offset + 4);
+ offset = (bfd_vma) -1;
+ /* If not using the newer R_PPC64_TLSGD/LD to mark
+ __tls_get_addr calls, we must trust that the call
+ stays with its arg setup insns, ie. that the next
+ reloc is the __tls_get_addr call associated with
+ the current reloc. Edit both insns. */
+ if (input_section->has_tls_get_addr_call
+ && rel + 1 < relend
+ && branch_reloc_hash_match (input_bfd, rel + 1,
+ htab->tls_get_addr,
+ htab->tls_get_addr_fd))
+ offset = rel[1].r_offset;
if ((tls_mask & tls_gd) != 0)
{
/* IE */
+ insn1 = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - (1 << 2);
insn1 |= 58 << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */
- rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
- R_PPC64_NONE);
+ if (offset != (bfd_vma) -1)
+ rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+ R_PPC64_NONE);
if ((tls_mask & TLS_EXPLICIT) == 0)
r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3)
+ R_PPC64_GOT_TPREL16_DS);
rel->r_addend -= (local_syms[r_symndx].st_value
+ sec->output_offset
+ sec->output_section->vma);
- rel[1].r_addend = rel->r_addend;
}
else if (toc_symndx != 0)
- r_symndx = toc_symndx;
+ {
+ r_symndx = toc_symndx;
+ rel->r_addend = toc_addend;
+ }
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,
- R_PPC64_TPREL16_LO);
- rel[1].r_offset += d_offset;
+ if (offset != (bfd_vma) -1)
+ {
+ rel[1].r_info = ELF64_R_INFO (r_symndx,
+ R_PPC64_TPREL16_LO);
+ rel[1].r_offset = offset + d_offset;
+ rel[1].r_addend = rel->r_addend;
+ }
+ }
+ bfd_put_32 (output_bfd, insn1,
+ contents + rel->r_offset - d_offset);
+ if (offset != (bfd_vma) -1)
+ {
+ insn3 = bfd_get_32 (output_bfd,
+ contents + offset + 4);
+ if (insn3 == NOP
+ || insn3 == CROR_151515 || insn3 == CROR_313131)
+ {
+ rel[1].r_offset += 4;
+ bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+ insn2 = NOP;
+ }
+ bfd_put_32 (output_bfd, insn2, contents + offset);
+ }
+ if ((tls_mask & tls_gd) == 0
+ && (tls_gd == 0 || toc_symndx != 0))
+ {
+ /* We changed the symbol. Start over in order
+ to get h, sym, sec etc. right. */
+ rel--;
+ continue;
}
+ }
+ break;
+
+ case R_PPC64_TLSGD:
+ if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+ {
+ unsigned int insn2, insn3;
+ bfd_vma offset = rel->r_offset;
+
+ if ((tls_mask & TLS_TPRELGD) != 0)
+ {
+ /* IE */
+ r_type = R_PPC64_NONE;
+ insn2 = 0x7c636a14; /* add 3,3,13 */
+ }
+ else
+ {
+ /* LE */
+ if (toc_symndx != 0)
+ {
+ r_symndx = toc_symndx;
+ rel->r_addend = toc_addend;
+ }
+ r_type = R_PPC64_TPREL16_LO;
+ rel->r_offset = offset + d_offset;
+ insn2 = 0x38630000; /* addi 3,3,0 */
+ }
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ /* Zap the reloc on the _tls_get_addr call too. */
+ BFD_ASSERT (offset == rel[1].r_offset);
+ rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+ R_PPC64_NONE);
+ insn3 = bfd_get_32 (output_bfd,
+ contents + offset + 4);
if (insn3 == NOP
|| insn3 == CROR_151515 || insn3 == CROR_313131)
{
- insn3 = insn2;
+ rel->r_offset += 4;
+ bfd_put_32 (output_bfd, insn2, contents + offset + 4);
insn2 = NOP;
- rel[1].r_offset += 4;
}
- bfd_put_32 (output_bfd, insn1,
- contents + rel->r_offset - d_offset);
bfd_put_32 (output_bfd, insn2, contents + offset);
- bfd_put_32 (output_bfd, insn3, contents + offset + 4);
- if (tls_gd == 0 || toc_symndx != 0)
+ if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
{
- /* We changed the symbol. Start over in order
- to get h, sym, sec etc. right. */
rel--;
continue;
}
}
break;
+ case R_PPC64_TLSLD:
+ if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+ {
+ unsigned int insn2, insn3;
+ bfd_vma offset = rel->r_offset;
+
+ if (toc_symndx)
+ sec = local_sections[toc_symndx];
+ for (r_symndx = 0;
+ r_symndx < symtab_hdr->sh_info;
+ r_symndx++)
+ if (local_sections[r_symndx] == sec)
+ break;
+ if (r_symndx >= symtab_hdr->sh_info)
+ r_symndx = 0;
+ rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+ if (r_symndx != 0)
+ rel->r_addend -= (local_syms[r_symndx].st_value
+ + sec->output_offset
+ + sec->output_section->vma);
+
+ r_type = R_PPC64_TPREL16_LO;
+ rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+ rel->r_offset = offset + d_offset;
+ /* Zap the reloc on the _tls_get_addr call too. */
+ BFD_ASSERT (offset == rel[1].r_offset);
+ rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+ R_PPC64_NONE);
+ insn2 = 0x38630000; /* addi 3,3,0 */
+ insn3 = bfd_get_32 (output_bfd,
+ contents + offset + 4);
+ if (insn3 == NOP
+ || insn3 == CROR_151515 || insn3 == CROR_313131)
+ {
+ rel->r_offset += 4;
+ bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+ insn2 = NOP;
+ }
+ bfd_put_32 (output_bfd, insn2, contents + offset);
+ rel--;
+ continue;
+ }
+ break;
+
case R_PPC64_DTPMOD64:
if (rel + 1 < relend
&& rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
case R_PPC64_NONE:
case R_PPC64_TLS:
+ case R_PPC64_TLSGD:
+ case R_PPC64_TLSLD:
case R_PPC64_GNU_VTINHERIT:
case R_PPC64_GNU_VTENTRY:
continue;
*offp = off | 1;
if ((info->shared || indx != 0)
- && (h == NULL
+ && (offp == &ppc64_tlsld_got (input_bfd)->offset
+ || h == NULL
|| ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
|| h->elf.root.type != bfd_link_hash_undefweak))
{