* powerpc tls
@ 2007-11-06 4:00 Alan Modra
2007-11-06 13:51 ` Alan Modra
0 siblings, 1 reply; 2+ messages in thread
From: Alan Modra @ 2007-11-06 4:00 UTC (permalink / raw)
To: binutils
Someone sent me an object file generated by gcc-4.1.1 recently with
the following horrible powerpc code. It breaks the linker tls
optimisation assumption that GOT_TLSGD relocs on instructions setting
up __tls_get_addr parameters are followed by the PLTREL24 reloc for
the call itself. I'm not inclined to teach the linker how to analyse
code to stitch together arguments with calls, so for now we'll just
refuse to optimise this mess.
288: 7f c8 02 a6 mflr r30
28c: 38 7e 00 00 addi r3,r30,0
28e: R_PPC_GOT_TLSGD16 blas_cbstate
290: 41 9e 00 2c beq- cr7,2bc <get_allocated_cb+0x54>
294: 38 7e 00 00 addi r3,r30,0
296: R_PPC_GOT_TLSGD16 blas_cbstate
298: 2f 80 00 03 cmpwi cr7,r0,3
29c: 41 9a 00 3c beq- cr6,2d8 <get_allocated_cb+0x70>
2a0: 38 7e 00 00 addi r3,r30,0
2a2: R_PPC_GOT_TLSGD16 blas_cbstate
2a4: 41 9e 00 50 beq- cr7,2f4 <get_allocated_cb+0x8c>
2a8: 80 01 00 24 lwz r0,36(r1)
2ac: 83 c1 00 18 lwz r30,24(r1)
2b0: 38 21 00 20 addi r1,r1,32
2b4: 7c 08 03 a6 mtlr r0
2b8: 4e 80 00 20 blr
2bc: 48 00 00 01 bl 2bc <get_allocated_cb+0x54>
2bc: R_PPC_PLTREL24 __tls_get_addr
2c0: 80 01 00 24 lwz r0,36(r1)
2c4: 80 63 00 00 lwz r3,0(r3)
2c8: 83 c1 00 18 lwz r30,24(r1)
2cc: 7c 08 03 a6 mtlr r0
2d0: 38 21 00 20 addi r1,r1,32
2d4: 4e 80 00 20 blr
2d8: 48 00 00 01 bl 2d8 <get_allocated_cb+0x70>
2d8: R_PPC_PLTREL24 __tls_get_addr
2dc: 80 01 00 24 lwz r0,36(r1)
2e0: 80 63 00 04 lwz r3,4(r3)
2e4: 83 c1 00 18 lwz r30,24(r1)
2e8: 7c 08 03 a6 mtlr r0
2ec: 38 21 00 20 addi r1,r1,32
2f0: 4e 80 00 20 blr
2f4: 48 00 00 01 bl 2f4 <get_allocated_cb+0x8c>
2f4: R_PPC_PLTREL24 __tls_get_addr
2f8: 80 01 00 24 lwz r0,36(r1)
2fc: 80 63 00 08 lwz r3,8(r3)
300: 83 c1 00 18 lwz r30,24(r1)
304: 7c 08 03 a6 mtlr r0
308: 38 21 00 20 addi r1,r1,32
30c: 4e 80 00 20 blr
bfd/
* elf32-ppc.c (ppc_elf_check_relocs): Don't refcount tlsld_got here..
(ppc_elf_gc_sweep_hook): ..or here..
(ppc_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.
(ppc_elf_size_dynamic_sections): Call allocate_dynrelocs before
allocating tlsld_got.
(ppc_elf_relocate_section): Remove check that a tls_get_addr
call follows gd and ld relocs.
ld/testsuite/
* ld-powerpc/tlsso32.d: Update for changed got alloc order.
Note: diff -w to exclude indentation changes.
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.222
diff -u -p -w -r1.222 elf32-ppc.c
--- bfd/elf32-ppc.c 25 Oct 2007 15:20:23 -0000 1.222
+++ bfd/elf32-ppc.c 6 Nov 2007 03:00:10 -0000
@@ -3109,7 +3109,6 @@ ppc_elf_check_relocs (bfd *abfd,
case R_PPC_GOT_TLSLD16_LO:
case R_PPC_GOT_TLSLD16_HI:
case R_PPC_GOT_TLSLD16_HA:
- htab->tlsld_got.refcount += 1;
tls_type = TLS_TLS | TLS_LD;
goto dogottls;
@@ -3957,9 +3956,6 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
case R_PPC_GOT_TLSLD16_LO:
case R_PPC_GOT_TLSLD16_HI:
case R_PPC_GOT_TLSLD16_HA:
- htab->tlsld_got.refcount -= 1;
- /* Fall thru */
-
case R_PPC_GOT_TLSGD16:
case R_PPC_GOT_TLSGD16_LO:
case R_PPC_GOT_TLSGD16_HI:
@@ -4064,11 +4060,17 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
bfd *ibfd;
asection *sec;
struct ppc_elf_link_hash_table *htab;
+ int pass;
if (info->relocatable || info->shared)
return TRUE;
htab = ppc_elf_hash_table (info);
+ /* Make two passes through the relocs. First time 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 (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
Elf_Internal_Sym *locsyms = NULL;
@@ -4078,7 +4080,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section))
{
Elf_Internal_Rela *relstart, *rel, *relend;
- int expecting_tls_get_addr;
/* Read the relocations. */
relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL,
@@ -4086,7 +4087,6 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
if (relstart == NULL)
return FALSE;
- expecting_tls_get_addr = 0;
relend = relstart + sec->reloc_count;
for (rel = relstart; rel < relend; rel++)
{
@@ -4096,6 +4096,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
char *tls_mask;
char tls_set, tls_clear;
bfd_boolean is_local;
+ int expecting_tls_get_addr;
+ bfd_signed_vma *got_count;
r_symndx = ELF32_R_SYM (rel->r_info);
if (r_symndx >= symtab_hdr->sh_info)
@@ -4109,6 +4111,7 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
h = (struct elf_link_hash_entry *) h->root.u.i.link;
}
+ expecting_tls_get_addr = 0;
is_local = FALSE;
if (h == NULL
|| !h->def_dynamic)
@@ -4119,24 +4122,27 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
{
case R_PPC_GOT_TLSLD16:
case R_PPC_GOT_TLSLD16_LO:
+ expecting_tls_get_addr = 1;
+ /* Fall thru */
+
case R_PPC_GOT_TLSLD16_HI:
case R_PPC_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. */
- expecting_tls_get_addr = 0;
- htab->tlsld_got.refcount -= 1;
if (!is_local)
continue;
/* LD -> LE */
tls_set = 0;
tls_clear = TLS_LD;
- expecting_tls_get_addr = 1;
break;
case R_PPC_GOT_TLSGD16:
case R_PPC_GOT_TLSGD16_LO:
+ expecting_tls_get_addr = 1;
+ /* Fall thru */
+
case R_PPC_GOT_TLSGD16_HI:
case R_PPC_GOT_TLSGD16_HA:
if (is_local)
@@ -4146,14 +4152,12 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
/* GD -> IE */
tls_set = TLS_TLS | TLS_TPRELGD;
tls_clear = TLS_GD;
- expecting_tls_get_addr = 1;
break;
case R_PPC_GOT_TPREL16:
case R_PPC_GOT_TPREL16_LO:
case R_PPC_GOT_TPREL16_HI:
case R_PPC_GOT_TPREL16_HA:
- expecting_tls_get_addr = 0;
if (is_local)
{
/* IE -> LE */
@@ -4164,35 +4168,57 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
else
continue;
- case R_PPC_REL14:
- case R_PPC_REL14_BRTAKEN:
- case R_PPC_REL14_BRNTAKEN:
- case R_PPC_REL24:
- if (expecting_tls_get_addr
- && h != NULL
- && h == htab->tls_get_addr)
- {
- struct plt_entry *ent = find_plt_ent (h, NULL, 0);
- if (ent != NULL && ent->plt.refcount > 0)
- ent->plt.refcount -= 1;
+ default:
+ continue;
}
- expecting_tls_get_addr = 0;
+
+ if (pass == 0)
+ {
+ if (!expecting_tls_get_addr)
continue;
- default:
- expecting_tls_get_addr = 0;
+ 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;
}
+ }
+
+ /* 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 (h != NULL)
{
- if (tls_set == 0)
- {
- /* We managed to get rid of a got entry. */
- if (h->got.refcount > 0)
- h->got.refcount -= 1;
- }
tls_mask = &ppc_elf_hash_entry (h)->tls_mask;
+ got_count = &h->got.refcount;
}
else
{
@@ -4218,14 +4244,25 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
lgot_refs = elf_local_got_refcounts (ibfd);
if (lgot_refs == NULL)
abort ();
+ lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info);
+ tls_mask = &lgot_masks[r_symndx];
+ got_count = &lgot_refs[r_symndx];
+ }
+
if (tls_set == 0)
{
/* We managed to get rid of a got entry. */
- if (lgot_refs[r_symndx] > 0)
- lgot_refs[r_symndx] -= 1;
+ if (*got_count > 0)
+ *got_count -= 1;
}
- lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info);
- tls_mask = &lgot_masks[r_symndx];
+
+ if (expecting_tls_get_addr)
+ {
+ struct plt_entry *ent;
+
+ ent = find_plt_ent (htab->tls_get_addr, NULL, 0);
+ if (ent != NULL && ent->plt.refcount > 0)
+ ent->plt.refcount -= 1;
}
*tls_mask |= tls_set;
@@ -4673,8 +4710,11 @@ allocate_dynrelocs (struct elf_link_hash
if (eh->tls_mask == (TLS_TLS | TLS_LD)
&& !eh->elf.def_dynamic)
+ {
/* If just an LD reloc, we'll just use htab->tlsld_got.offset. */
+ htab->tlsld_got.refcount += 1;
eh->elf.got.offset = (bfd_vma) -1;
+ }
else
{
bfd_boolean dyn;
@@ -4949,6 +4989,9 @@ ppc_elf_size_dynamic_sections (bfd *outp
*local_got = (bfd_vma) -1;
}
+ /* Allocate space for global sym dynamic relocs. */
+ elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
+
if (htab->tlsld_got.refcount > 0)
{
htab->tlsld_got.offset = allocate_got (htab, 8);
@@ -4958,9 +5001,6 @@ ppc_elf_size_dynamic_sections (bfd *outp
else
htab->tlsld_got.offset = (bfd_vma) -1;
- /* Allocate space for global sym dynamic relocs. */
- elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info);
-
if (htab->got != NULL && htab->plt_type != PLT_VXWORKS)
{
unsigned int g_o_t = 32768;
@@ -5928,42 +5968,17 @@ ppc_elf_relocate_section (bfd *output_bf
case R_PPC_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_PPC_GOT_TLSLD16:
case R_PPC_GOT_TLSLD16_LO:
if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
{
- tls_get_addr_check:
- if (rel + 1 < relend)
- {
- enum elf_ppc_reloc_type r_type2;
- unsigned long r_symndx2;
- struct elf_link_hash_entry *h2;
bfd_vma insn1, insn2;
bfd_vma offset;
- /* 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))
- 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)
- break;
-
- /* OK, it checks out. Replace the call. */
+ tls_ldgd_opt:
offset = rel[1].r_offset;
insn1 = bfd_get_32 (output_bfd,
contents + rel->r_offset - d_offset);
@@ -5973,7 +5988,8 @@ ppc_elf_relocate_section (bfd *output_bf
insn1 &= (1 << 26) - 1;
insn1 |= 32 << 26; /* lwz */
insn2 = 0x7c631214; /* add 3,3,2 */
- rel[1].r_info = ELF32_R_INFO (r_symndx2, R_PPC_NONE);
+ 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);
@@ -5997,7 +6013,8 @@ ppc_elf_relocate_section (bfd *output_bf
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);
+ bfd_put_32 (output_bfd, insn1,
+ contents + rel->r_offset - d_offset);
bfd_put_32 (output_bfd, insn2, contents + offset);
if (tls_gd == 0)
{
@@ -6007,7 +6024,6 @@ ppc_elf_relocate_section (bfd *output_bf
continue;
}
}
- }
break;
}
Index: ld/testsuite/ld-powerpc/tlsso32.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsso32.d,v
retrieving revision 1.14
diff -u -p -r1.14 tlsso32.d
--- ld/testsuite/ld-powerpc/tlsso32.d 17 Oct 2006 13:41:48 -0000 1.14
+++ ld/testsuite/ld-powerpc/tlsso32.d 5 Nov 2007 01:33:52 -0000
@@ -9,30 +9,30 @@
Disassembly of section \.text:
.* <_start>:
-.*: 38 7f ff e8 addi r3,r31,-24
-.*: 48 00 00 01 bl .*
.*: 38 7f ff e0 addi r3,r31,-32
.*: 48 00 00 01 bl .*
-.*: 38 7f ff f0 addi r3,r31,-16
+.*: 38 7f ff f4 addi r3,r31,-12
+.*: 48 00 00 01 bl .*
+.*: 38 7f ff e8 addi r3,r31,-24
.*: 48 01 01 95 bl .*<__tls_get_addr@plt>
-.*: 38 7f ff e0 addi r3,r31,-32
+.*: 38 7f ff f4 addi r3,r31,-12
.*: 48 01 01 8d bl .*<__tls_get_addr@plt>
.*: 39 23 80 20 addi r9,r3,-32736
.*: 3d 23 00 00 addis r9,r3,0
.*: 81 49 80 24 lwz r10,-32732\(r9\)
-.*: 81 3f ff f8 lwz r9,-8\(r31\)
+.*: 81 3f ff f0 lwz r9,-16\(r31\)
.*: 7d 49 12 2e lhzx r10,r9,r2
.*: 89 42 00 00 lbz r10,0\(r2\)
.*: 3d 22 00 00 addis r9,r2,0
.*: 99 49 00 00 stb r10,0\(r9\)
.*: 38 7e ff d8 addi r3,r30,-40
.*: 48 00 00 01 bl .*
-.*: 38 7e ff e0 addi r3,r30,-32
+.*: 38 7e ff f4 addi r3,r30,-12
.*: 48 00 00 01 bl .*
.*: 91 43 80 04 stw r10,-32764\(r3\)
.*: 3d 23 00 00 addis r9,r3,0
.*: 91 49 80 08 stw r10,-32760\(r9\)
-.*: 81 3e ff f8 lwz r9,-8\(r30\)
+.*: 81 3e ff f0 lwz r9,-16\(r30\)
.*: 7d 49 13 2e sthx r10,r9,r2
.*: a1 42 00 00 lhz r10,0\(r2\)
.*: 3d 22 00 00 addis r9,r2,0
--
Alan Modra
Australia Development Lab, IBM
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: powerpc tls
2007-11-06 4:00 powerpc tls Alan Modra
@ 2007-11-06 13:51 ` Alan Modra
0 siblings, 0 replies; 2+ messages in thread
From: Alan Modra @ 2007-11-06 13:51 UTC (permalink / raw)
To: binutils
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
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2007-11-06 13:51 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-11-06 4:00 powerpc tls Alan Modra
2007-11-06 13:51 ` Alan Modra
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).