This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: powerpc tls
In the same vein as the ppc32 patch.
bfd/
* elf64-ppc.c (ppc64_elf_check_relocs): Don't refcount tlsld_got here..
(ppc64_elf_gc_sweep_hook): ..or here..
(ppc64_elf_tls_optimize): ..or here. Make two passes through the
relocs, ensuring that tls_get_addr calls follow gd and ld relocs.
(allocate_dynrelocs): Refcount tlsld_got here.
(ppc64_elf_size_dynamic_sections): Allocate local got and call
allocate_dynrelocs before allocating tlsld_got.
(ppc64_elf_relocate_section): Remove check that a tls_get_addr
call follows gd and ld relocs.
ld/testsuite/
* ld-powerpc/tlsso.d: Update for changed got alloc order.
* ld-powerpc/tlsso.r: Likewise.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.269
diff -u -p -w -r1.269 elf64-ppc.c
--- bfd/elf64-ppc.c 23 Oct 2007 12:54:17 -0000 1.269
+++ bfd/elf64-ppc.c 6 Nov 2007 11:28:18 -0000
@@ -4480,7 +4480,6 @@ ppc64_elf_check_relocs (bfd *abfd, struc
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
- ppc64_tlsld_got (abfd)->refcount += 1;
tls_type = TLS_TLS | TLS_LD;
goto dogottls;
@@ -5306,7 +5305,6 @@ ppc64_elf_gc_sweep_hook (bfd *abfd, stru
case R_PPC64_GOT_TLSLD16_LO:
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
- ppc64_tlsld_got (abfd)->refcount -= 1;
tls_type = TLS_TLS | TLS_LD;
goto dogot;
@@ -6795,6 +6793,7 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
bfd *ibfd;
asection *sec;
struct ppc_link_hash_table *htab;
+ int pass;
if (info->relocatable || info->shared)
return TRUE;
@@ -6806,19 +6805,17 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
asection *toc = bfd_get_section_by_name (ibfd, ".toc");
unsigned char *toc_ref = NULL;
- /* Look at all the sections for this file, with TOC last. */
- for (sec = (ibfd->sections == toc && toc && toc->next ? toc->next
- : ibfd->sections);
- sec != NULL;
- sec = (sec == toc ? NULL
- : sec->next == NULL ? toc
- : sec->next == toc && toc->next ? toc->next
- : sec->next))
+ /* Look at all the sections for this file. Make two passes over
+ the relocs. On the first pass, mark toc entries involved
+ with tls relocs, and check that tls relocs involved in
+ setting up a tls_get_addr call are indeed followed by such a
+ call. If they are not, exclude them from the optimizations
+ done on the second pass. */
+ for (pass = 0; pass < 2; ++pass)
+ for (sec = ibfd->sections; sec != NULL; sec = sec->next)
if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
{
Elf_Internal_Rela *relstart, *rel, *relend;
- int expecting_tls_get_addr;
- long toc_ref_index = 0;
/* Read the relocations. */
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -6826,7 +6823,6 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
if (relstart == NULL)
return FALSE;
- expecting_tls_get_addr = 0;
relend = relstart + sec->reloc_count;
for (rel = relstart; rel < relend; rel++)
{
@@ -6839,6 +6835,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
char tls_set, tls_clear, tls_type = 0;
bfd_vma value;
bfd_boolean ok_tprel, is_local;
+ long toc_ref_index = 0;
+ int expecting_tls_get_addr = 0;
r_symndx = ELF64_R_SYM (rel->r_info);
if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms,
@@ -6886,12 +6884,14 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
{
case R_PPC64_GOT_TLSLD16:
case R_PPC64_GOT_TLSLD16_LO:
+ expecting_tls_get_addr = 1;
+ /* Fall thru */
+
case R_PPC64_GOT_TLSLD16_HI:
case R_PPC64_GOT_TLSLD16_HA:
/* These relocs should never be against a symbol
defined in a shared lib. Leave them alone if
that turns out to be the case. */
- ppc64_tlsld_got (ibfd)->refcount -= 1;
if (!is_local)
continue;
@@ -6899,11 +6899,13 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
tls_set = 0;
tls_clear = TLS_LD;
tls_type = TLS_TLS | TLS_LD;
- expecting_tls_get_addr = 1;
break;
case R_PPC64_GOT_TLSGD16:
case R_PPC64_GOT_TLSGD16_LO:
+ expecting_tls_get_addr = 1;
+ /* Fall thru */
+
case R_PPC64_GOT_TLSGD16_HI:
case R_PPC64_GOT_TLSGD16_HA:
if (ok_tprel)
@@ -6914,14 +6916,12 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
tls_set = TLS_TLS | TLS_TPRELGD;
tls_clear = TLS_GD;
tls_type = TLS_TLS | TLS_GD;
- expecting_tls_get_addr = 1;
break;
case R_PPC64_GOT_TPREL16_DS:
case R_PPC64_GOT_TPREL16_LO_DS:
case R_PPC64_GOT_TPREL16_HI:
case R_PPC64_GOT_TPREL16_HA:
- expecting_tls_get_addr = 0;
if (ok_tprel)
{
/* IE -> LE */
@@ -6930,61 +6930,14 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
tls_type = TLS_TLS | TLS_TPREL;
break;
}
- else
- continue;
-
- case R_PPC64_REL14:
- case R_PPC64_REL14_BRTAKEN:
- case R_PPC64_REL14_BRNTAKEN:
- case R_PPC64_REL24:
- if (h != NULL
- && (h == &htab->tls_get_addr->elf
- || h == &htab->tls_get_addr_fd->elf))
- {
- if (!expecting_tls_get_addr
- && rel != relstart
- && ((ELF64_R_TYPE (rel[-1].r_info)
- == R_PPC64_TOC16)
- || (ELF64_R_TYPE (rel[-1].r_info)
- == R_PPC64_TOC16_LO)))
- {
- /* Check for toc tls entries. */
- char *toc_tls;
- int retval;
-
- retval = get_tls_mask (&toc_tls, NULL, &locsyms,
- rel - 1, ibfd);
- if (retval == 0)
- goto err_free_rel;
- if (retval > 1 && toc_tls != NULL)
- {
- expecting_tls_get_addr = 1;
- if (toc_ref != NULL)
- toc_ref[toc_ref_index] = 1;
- }
- }
-
- if (expecting_tls_get_addr)
- {
- struct plt_entry *ent;
- for (ent = h->plt.plist; ent; ent = ent->next)
- if (ent->addend == 0)
- {
- if (ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
- break;
- }
- }
- }
- expecting_tls_get_addr = 0;
continue;
case R_PPC64_TOC16:
case R_PPC64_TOC16_LO:
case R_PPC64_TLS:
- expecting_tls_get_addr = 0;
- if (sym_sec == toc && toc != NULL)
- {
+ if (sym_sec == NULL || sym_sec != toc)
+ continue;
+
/* Mark this toc entry as referenced by a TLS
code sequence. We can do that now in the
case of R_PPC64_TLS, and after checking for
@@ -7003,13 +6956,22 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
BFD_ASSERT (value < toc->size && value % 8 == 0);
toc_ref_index = value / 8;
if (r_type == R_PPC64_TLS)
+ {
toc_ref[toc_ref_index] = 1;
+ continue;
}
+
+ if (pass != 0 && toc_ref[toc_ref_index] == 0)
continue;
+ tls_set = 0;
+ tls_clear = 0;
+ expecting_tls_get_addr = 2;
+ break;
+
case R_PPC64_TPREL64:
- expecting_tls_get_addr = 0;
- if (sec != toc
+ if (pass == 0
+ || sec != toc
|| toc_ref == NULL
|| !toc_ref[rel->r_offset / 8])
continue;
@@ -7020,12 +6982,11 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
tls_clear = TLS_TPREL;
break;
}
- else
continue;
case R_PPC64_DTPMOD64:
- expecting_tls_get_addr = 0;
- if (sec != toc
+ if (pass == 0
+ || sec != toc
|| toc_ref == NULL
|| !toc_ref[rel->r_offset / 8])
continue;
@@ -7054,10 +7015,110 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
break;
default:
- expecting_tls_get_addr = 0;
continue;
}
+ if (pass == 0)
+ {
+ if (!expecting_tls_get_addr)
+ continue;
+
+ if (rel + 1 < relend)
+ {
+ 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_tdata (ibfd)->symtab_hdr;
+
+ /* 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))
+ {
+ 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;
+ }
+ }
+ }
+
+ 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
+ the entire section. */
+ sec->has_tls_reloc = 0;
+ break;
+ }
+
+ if (expecting_tls_get_addr)
+ {
+ struct plt_entry *ent;
+ for (ent = htab->tls_get_addr->elf.plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == 0)
+ {
+ if (ent->plt.refcount > 0)
+ {
+ ent->plt.refcount -= 1;
+ expecting_tls_get_addr = 0;
+ }
+ break;
+ }
+ }
+
+ if (expecting_tls_get_addr)
+ {
+ struct plt_entry *ent;
+ for (ent = htab->tls_get_addr_fd->elf.plt.plist;
+ ent != NULL;
+ ent = ent->next)
+ if (ent->addend == 0)
+ {
+ if (ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
+ break;
+ }
+ }
+
+ if (tls_clear == 0)
+ continue;
+
if ((tls_set & TLS_EXPLICIT) == 0)
{
struct got_entry *ent;
@@ -7693,7 +7754,8 @@ allocate_dynrelocs (struct elf_link_hash
if ((gent->tls_type & TLS_LD) != 0
&& !h->def_dynamic)
{
- gent->got.offset = ppc64_tlsld_got (gent->owner)->offset;
+ ppc64_tlsld_got (gent->owner)->refcount += 1;
+ gent->got.offset = (bfd_vma) -1;
continue;
}
@@ -7877,20 +7939,6 @@ ppc64_elf_size_dynamic_sections (bfd *ou
if (!is_ppc64_elf_target (ibfd->xvec))
continue;
- if (ppc64_tlsld_got (ibfd)->refcount > 0)
- {
- s = ppc64_elf_tdata (ibfd)->got;
- ppc64_tlsld_got (ibfd)->offset = s->size;
- s->size += 16;
- if (info->shared)
- {
- srel = ppc64_elf_tdata (ibfd)->relgot;
- srel->size += sizeof (Elf64_External_Rela);
- }
- }
- else
- ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1;
-
for (s = ibfd->sections; s != NULL; s = s->next)
{
struct ppc_dyn_relocs *p;
@@ -7934,14 +7982,8 @@ ppc64_elf_size_dynamic_sections (bfd *ou
{
if ((ent->tls_type & *lgot_masks & TLS_LD) != 0)
{
- if (ppc64_tlsld_got (ibfd)->offset == (bfd_vma) -1)
- {
- ppc64_tlsld_got (ibfd)->offset = s->size;
- s->size += 16;
- if (info->shared)
- srel->size += sizeof (Elf64_External_Rela);
- }
- ent->got.offset = ppc64_tlsld_got (ibfd)->offset;
+ ppc64_tlsld_got (ibfd)->refcount += 1;
+ ent->got.offset = (bfd_vma) -1;
}
else
{
@@ -7969,6 +8011,26 @@ ppc64_elf_size_dynamic_sections (bfd *ou
sym dynamic relocs. */
elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info);
+ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
+ {
+ if (!is_ppc64_elf_target (ibfd->xvec))
+ continue;
+
+ if (ppc64_tlsld_got (ibfd)->refcount > 0)
+ {
+ s = ppc64_elf_tdata (ibfd)->got;
+ ppc64_tlsld_got (ibfd)->offset = s->size;
+ s->size += 16;
+ if (info->shared)
+ {
+ asection *srel = ppc64_elf_tdata (ibfd)->relgot;
+ srel->size += sizeof (Elf64_External_Rela);
+ }
+ }
+ else
+ ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1;
+ }
+
/* We now have determined the sizes of the various dynamic sections.
Allocate memory for them. */
relocs = FALSE;
@@ -10118,12 +10180,12 @@ ppc64_elf_relocate_section (bfd *output_
{
tls_gd = TLS_TPRELGD;
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
- goto tls_get_addr_check;
+ goto tls_ldgd_opt;
}
else if (retval == 3)
{
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
- goto tls_get_addr_check;
+ goto tls_ldgd_opt;
}
}
}
@@ -10236,42 +10298,19 @@ ppc64_elf_relocate_section (bfd *output_
case R_PPC64_GOT_TLSGD16_LO:
tls_gd = TLS_TPRELGD;
if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
- goto tls_get_addr_check;
+ 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)
{
- tls_get_addr_check:
- if (rel + 1 < relend)
- {
- enum elf_ppc64_reloc_type r_type2;
- unsigned long r_symndx2;
- struct elf_link_hash_entry *h2;
bfd_vma insn1, insn2, insn3;
bfd_vma offset;
- /* 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))
- break;
-
- 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))
- break;
-
- /* OK, it checks out. Replace the call. */
+ 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);
@@ -10283,7 +10322,8 @@ ppc64_elf_relocate_section (bfd *output_
insn1 &= (1 << 26) - (1 << 2);
insn1 |= 58 << 26; /* ld */
insn2 = 0x7c636a14; /* add 3,3,13 */
- rel[1].r_info = ELF64_R_INFO (r_symndx2, R_PPC64_NONE);
+ 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);
@@ -10318,7 +10358,8 @@ ppc64_elf_relocate_section (bfd *output_
insn2 = NOP;
rel[1].r_offset += 4;
}
- bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - d_offset);
+ 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)
@@ -10329,7 +10370,6 @@ ppc64_elf_relocate_section (bfd *output_
continue;
}
}
- }
break;
case R_PPC64_DTPMOD64:
Index: ld/testsuite/ld-powerpc/tlsso.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsso.d,v
retrieving revision 1.6
diff -u -p -w -r1.6 tlsso.d
--- ld/testsuite/ld-powerpc/tlsso.d 13 Aug 2007 00:20:59 -0000 1.6
+++ ld/testsuite/ld-powerpc/tlsso.d 6 Nov 2007 07:14:39 -0000
@@ -17,40 +17,40 @@ Disassembly of section \.text:
.* 4e 80 04 20 bctr
.* <_start>:
-.* 38 62 80 30 addi r3,r2,-32720
+.* 38 62 80 20 addi r3,r2,-32736
.* 4b ff ff e5 bl .* <\.__tls_get_addr>
.* e8 41 00 28 ld r2,40\(r1\)
-.* 38 62 80 08 addi r3,r2,-32760
+.* 38 62 80 50 addi r3,r2,-32688
.* 4b ff ff d9 bl .* <\.__tls_get_addr>
.* e8 41 00 28 ld r2,40\(r1\)
-.* 38 62 80 48 addi r3,r2,-32696
+.* 38 62 80 38 addi r3,r2,-32712
.* 4b ff ff cd bl .* <\.__tls_get_addr>
.* e8 41 00 28 ld r2,40\(r1\)
-.* 38 62 80 08 addi r3,r2,-32760
+.* 38 62 80 50 addi r3,r2,-32688
.* 4b ff ff c1 bl .* <\.__tls_get_addr>
.* e8 41 00 28 ld r2,40\(r1\)
.* 39 23 80 40 addi r9,r3,-32704
.* 3d 23 00 00 addis r9,r3,0
.* 81 49 80 48 lwz r10,-32696\(r9\)
-.* e9 22 80 40 ld r9,-32704\(r2\)
+.* e9 22 80 30 ld r9,-32720\(r2\)
.* 7d 49 18 2a ldx r10,r9,r3
-.* e9 22 80 58 ld r9,-32680\(r2\)
+.* e9 22 80 48 ld r9,-32696\(r2\)
.* 7d 49 6a 2e lhzx r10,r9,r13
.* 89 4d 00 00 lbz r10,0\(r13\)
.* 3d 2d 00 00 addis r9,r13,0
.* 99 49 00 00 stb r10,0\(r9\)
-.* 38 62 80 18 addi r3,r2,-32744
+.* 38 62 80 08 addi r3,r2,-32760
.* 4b ff ff 8d bl .* <\.__tls_get_addr>
.* e8 41 00 28 ld r2,40\(r1\)
-.* 38 62 80 08 addi r3,r2,-32760
+.* 38 62 80 50 addi r3,r2,-32688
.* 4b ff ff 81 bl .* <\.__tls_get_addr>
.* e8 41 00 28 ld r2,40\(r1\)
.* f9 43 80 08 std r10,-32760\(r3\)
.* 3d 23 00 00 addis r9,r3,0
.* 91 49 80 10 stw r10,-32752\(r9\)
-.* e9 22 80 28 ld r9,-32728\(r2\)
+.* e9 22 80 18 ld r9,-32744\(r2\)
.* 7d 49 19 2a stdx r10,r9,r3
-.* e9 22 80 58 ld r9,-32680\(r2\)
+.* e9 22 80 48 ld r9,-32696\(r2\)
.* 7d 49 6b 2e sthx r10,r9,r13
.* e9 4d 00 02 lwa r10,0\(r13\)
.* 3d 2d 00 00 addis r9,r13,0
Index: ld/testsuite/ld-powerpc/tlsso.r
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsso.r,v
retrieving revision 1.21
diff -u -p -w -r1.21 tlsso.r
--- ld/testsuite/ld-powerpc/tlsso.r 30 Sep 2007 01:33:15 -0000 1.21
+++ ld/testsuite/ld-powerpc/tlsso.r 6 Nov 2007 07:14:39 -0000
@@ -53,9 +53,9 @@ Relocation section '\.rela\.dyn' at offs
[0-9a-f ]+R_PPC64_TPREL16_HA +0+105f0 \.tdata \+ 30
[0-9a-f ]+R_PPC64_TPREL16_LO +0+105f0 \.tdata \+ 30
[0-9a-f ]+R_PPC64_DTPMOD64 +0+
-[0-9a-f ]+R_PPC64_DTPMOD64 +0+
[0-9a-f ]+R_PPC64_DTPREL64 +0+
[0-9a-f ]+R_PPC64_DTPREL64 +0+18
+[0-9a-f ]+R_PPC64_DTPMOD64 +0+
[0-9a-f ]+R_PPC64_DTPMOD64 +0+ gd \+ 0
[0-9a-f ]+R_PPC64_DTPREL64 +0+ gd \+ 0
[0-9a-f ]+R_PPC64_DTPREL64 +0+50 ld2 \+ 0
--
Alan Modra
Australia Development Lab, IBM