This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
powerpc64 linker TLS optimization
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Date: Sun, 15 Feb 2009 22:45:27 +1030
- Subject: powerpc64 linker TLS optimization
This patch fixes a number of powerpc64 linker TLS optimization
problems I noticed when working on a fix for the ABI problem behind
http://sourceware.org/ml/binutils/2007-11/msg00033.html
1) When optimizing PowerOpen syntax TLS sequences, ie. those that use
the TOC, the linker ignored the fact that the ABI allows an addend
with the TLS symbol. Not something likely to affect anyone since
gcc doesn't use the TOC for TLS sequences and TLS relocs invariably
have an addend of zero in practice.
2) A GD to LE optimization failed to change the addend on the second
instruction of the sequence to that of the first reloc. On
powerpc64 the addends involved are normally all zero, so again
this is unlikely to affect anyone.
3) When generating a shared library or pie, a reloc to initialize the
got entry used by LD TLS could sometimes be omitted. This bug is
more likely to be triggered than the first two, but I think the
chance of it happening is small. (So small that I've sat on this
change since 2008-11-20 when I made a similar fix for powerpc32.)
4) ppc64_elf_check_relocs cached the __tls_get_addr and .__tls_get_addr
hash. This is too early, since we have not resolved final symbol
values at this stage. A later object may provide a versioned
symbol, relegating the cached hash to an indirect symbol that won't
match anything in ppc64_elf_check_relocs. This happens to be of no
consequence in real code since the has_tls_reloc flag ought to be
set by the __tls_get_addr arg setup instruction.
Also included in the patch are a number of minor tweaks to avoid
unnecessary work, and extraction of code recognizing __tls_get_addr
relocs to a function.
* elf64-ppc.c (struct _ppc64_elf_section_data): Delete t_symndx,
add toc.symndx and toc.add.
(ppc64_elf_check_relocs): Don't set htab->tls_get_addr here.
Set up toc.add.
(get_tls_mask): Add toc_addend param, set from toc.add. Adjust all
callers.
(ppc64_elf_tls_setup): Set htab->tls_get_addr and tls_get_addr_fd.
(branch_reloc_hash_match): New function, extracted from..
(ppc64_elf_tls_optimize): ..here.
(ppc64_elf_relocate_section): Properly set addends when optimizing
tls sequences. Avoid unnecessary reading and writing of insns.
Only redo reloc when symbol changed. Bypass symbol checks when
using tlsld_got.
* elf32-ppc.c (ppc_elf_tls_setup): Correct comment.
(branch_reloc_hash_match): New function, extracted from..
(ppc_elf_tls_optimize): ..here.
(ppc_elf_relocate_section): Avoid unnecessary reading of insns.
Don't clear addend on zapped __tls_get_addr reloc.
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.250
diff -u -p -r1.250 elf32-ppc.c
--- bfd/elf32-ppc.c 26 Jan 2009 15:27:03 -0000 1.250
+++ bfd/elf32-ppc.c 15 Feb 2009 05:54:01 -0000
@@ -4301,7 +4301,8 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
return TRUE;
}
-/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */
+/* Set plt output section type, htab->tls_get_addr, and call the
+ generic ELF tls_setup function. */
asection *
ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
@@ -4322,6 +4323,43 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd
return _bfd_elf_tls_setup (obfd, info);
}
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+ HASH. */
+
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+ const Elf_Internal_Rela *rel,
+ const struct elf_link_hash_entry *hash)
+{
+ Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+ enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
+ unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
+
+ if (r_symndx >= symtab_hdr->sh_info
+ && (r_type == R_PPC_PLTREL24
+ || r_type == R_PPC_LOCAL24PC
+ || r_type == R_PPC_REL14
+ || r_type == R_PPC_REL14_BRTAKEN
+ || r_type == R_PPC_REL14_BRNTAKEN
+ || r_type == R_PPC_REL24
+ || r_type == R_PPC_ADDR24
+ || r_type == R_PPC_ADDR14
+ || r_type == R_PPC_ADDR14_BRTAKEN
+ || r_type == R_PPC_ADDR14_BRNTAKEN))
+ {
+ struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+ struct elf_link_hash_entry *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 == hash)
+ return TRUE;
+ }
+ return FALSE;
+}
+
/* Run through all the TLS relocs looking for optimization
opportunities. */
@@ -4449,35 +4487,10 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
if (!expecting_tls_get_addr)
continue;
- if (rel + 1 < relend)
- {
- enum elf_ppc_reloc_type r_type2;
- unsigned long r_symndx2;
- struct elf_link_hash_entry *h2;
-
- /* The next instruction should be a call to
- __tls_get_addr. Peek at the reloc to be sure. */
- r_type2 = ELF32_R_TYPE (rel[1].r_info);
- r_symndx2 = ELF32_R_SYM (rel[1].r_info);
- if (r_symndx2 >= symtab_hdr->sh_info
- && (r_type2 == R_PPC_REL14
- || r_type2 == R_PPC_REL14_BRTAKEN
- || r_type2 == R_PPC_REL14_BRNTAKEN
- || r_type2 == R_PPC_REL24
- || r_type2 == R_PPC_PLTREL24))
- {
- 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 == htab->tls_get_addr)
- continue;
- }
- }
+ if (rel + 1 < relend
+ && branch_reloc_hash_match (ibfd, rel + 1,
+ htab->tls_get_addr))
+ continue;
/* Uh oh, we didn't find the expected call. We
could just mark this symbol to exclude it
@@ -6344,22 +6357,21 @@ ppc_elf_relocate_section (bfd *output_bf
case R_PPC_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
{
- bfd_vma insn1, insn2;
+ unsigned int insn1, insn2;
bfd_vma offset;
tls_ldgd_opt:
offset = rel[1].r_offset;
- insn1 = bfd_get_32 (output_bfd,
- contents + rel->r_offset - d_offset);
if ((tls_mask & tls_gd) != 0)
{
/* IE */
+ insn1 = bfd_get_32 (output_bfd,
+ contents + rel->r_offset - d_offset);
insn1 &= (1 << 26) - 1;
insn1 |= 32 << 26; /* lwz */
insn2 = 0x7c631214; /* add 3,3,2 */
rel[1].r_info
= ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE);
- rel[1].r_addend = 0;
r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
+ R_PPC_GOT_TPREL16);
rel->r_info = ELF32_R_INFO (r_symndx, r_type);
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.290
diff -u -p -r1.290 elf64-ppc.c
--- bfd/elf64-ppc.c 11 Dec 2008 10:14:40 -0000 1.290
+++ bfd/elf64-ppc.c 15 Feb 2009 06:46:00 -0000
@@ -2608,9 +2608,15 @@ struct _ppc64_elf_section_data
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;
@@ -4578,6 +4584,7 @@ ppc64_elf_check_relocs (bfd *abfd, struc
const Elf_Internal_Rela *rel_end;
asection *sreloc;
asection **opd_sym_map;
+ struct elf_link_hash_entry *tga, *dottga;
if (info->relocatable)
return TRUE;
@@ -4594,6 +4601,10 @@ ppc64_elf_check_relocs (bfd *abfd, struc
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);
@@ -4829,25 +4840,8 @@ ppc64_elf_check_relocs (bfd *abfd, struc
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;
@@ -4891,23 +4885,30 @@ ppc64_elf_check_relocs (bfd *abfd, struc
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:
@@ -6226,9 +6227,12 @@ get_sym_h (struct elf_link_hash_entry **
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;
@@ -6256,12 +6260,14 @@ get_tls_mask (char **tls_maskp, unsigned
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)
@@ -6866,36 +6872,49 @@ ppc64_elf_tls_setup (bfd *obfd, struct b
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;
- }
+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 (htab->tls_get_addr_fd != NULL)
+ 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
@@ -7141,55 +7160,26 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
if (!expecting_tls_get_addr)
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)
@@ -9712,7 +9702,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
/* 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)
@@ -10204,6 +10194,7 @@ ppc64_elf_relocate_section (bfd *output_
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;
@@ -10312,8 +10303,8 @@ ppc64_elf_relocate_section (bfd *output_
/* Check for toc tls entries. */
char *toc_tls;
- if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
- rel, input_bfd))
+ if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+ &local_syms, rel, input_bfd))
return FALSE;
if (toc_tls)
@@ -10375,8 +10366,8 @@ ppc64_elf_relocate_section (bfd *output_
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;
@@ -10424,6 +10415,7 @@ ppc64_elf_relocate_section (bfd *output_
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--;
@@ -10477,6 +10469,7 @@ ppc64_elf_relocate_section (bfd *output_
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--;
@@ -10523,20 +10516,18 @@ ppc64_elf_relocate_section (bfd *output_
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);
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 */
@@ -10571,28 +10562,33 @@ ppc64_elf_relocate_section (bfd *output_
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;
+ rel[1].r_addend = rel->r_addend;
}
+ bfd_put_32 (output_bfd, insn1,
+ contents + rel->r_offset - d_offset);
+ insn3 = bfd_get_32 (output_bfd,
+ contents + offset + 4);
if (insn3 == NOP
|| insn3 == CROR_151515 || insn3 == CROR_313131)
{
- insn3 = insn2;
- insn2 = NOP;
rel[1].r_offset += 4;
+ bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+ insn2 = NOP;
}
- 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_gd) == 0
+ && (tls_gd == 0 || toc_symndx != 0))
{
/* We changed the symbol. Start over in order
to get h, sym, sec etc. right. */
@@ -10969,7 +10965,8 @@ ppc64_elf_relocate_section (bfd *output_
*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))
{
--
Alan Modra
Australia Development Lab, IBM