This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
PowerPC64 TLS optimisation problem
- From: Alan Modra <amodra at bigpond dot net dot au>
- To: binutils at sourceware dot org
- Cc: Paul Mackerras <paulus at samba dot org>
- Date: Fri, 5 May 2006 22:36:35 +0930
- Subject: PowerPC64 TLS optimisation problem
This fixes a problem found by a certain kernel hacker who was using TLS
in assembly for kernel per_cpu data. The linker incorrectly assumed
that any R_PPC64_TPREL64 reloc was part of a PowerOpen syntax
Initial-exec model TLS sequence, and thus might be able to be optimized
to a Local-exec model TLS. eg.
Code sequence Reloc Sym
ld 9,.LC0@toc(2) R_PPC64_TOC16_DS .LC0
add 9,9,.LC0@tls R_PPC64_TLS .LC0
..
.section .toc,"aw"
.LC0:
.quad x@tprel R_PPC64_TPREL64 x
is replaced by
addis 9,13,x@tprel@ha R_PPC64_TPREL16_HA x
addi 9,9,x@tprel@l R_PPC64_TPREL16_LO x
..
.section .toc,"aw"
.LC0:
.quad 0
Note that powerpc64 gcc does not use the PowerOpen scheme (compiler
managed TOC) for TLS, instead it uses a linker generated GOT. So this
linker bug will not affect gcc TLS code.
Anyway, fixed by checking that R_PPC64_TPREL64 relocs are in fact in the
TOC, and referenced by an R_PPC64_TLS in code before assuming they can
be optimized away. I added a similar check for R_PPC64_DTPMOD64 which
suffers from the same problem, and discovered a bug in the ld
testsuite.
bfd/
* elf64-ppc.c (ppc64_elf_tls_optimize): Only optimize
R_PPC64_TPREL64 and R_PPC64_DTPMOD64 relocs when they are in
the .toc and referenced by a TLS code sequence.
(ppc64_elf_edit_toc): Cater for the unlikely situation that
.toc is the first section in a file.
ld/testsuite
* ld-powerpc/tlsexetoc.r: Update for correction to tls optimization.
* ld-powerpc/tlsexetoc.g: Likewise.
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.236
diff -u -p -r1.236 elf64-ppc.c
--- bfd/elf64-ppc.c 3 May 2006 14:26:40 -0000 1.236
+++ bfd/elf64-ppc.c 5 May 2006 12:23:27 -0000
@@ -6699,12 +6699,22 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
{
Elf_Internal_Sym *locsyms = NULL;
+ asection *toc = bfd_get_section_by_name (ibfd, ".toc");
+ unsigned char *toc_ref = NULL;
- for (sec = ibfd->sections; sec != NULL; sec = sec->next)
+ /* 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))
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,
@@ -6733,6 +6743,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
err_free_rel:
if (elf_section_data (sec)->relocs != relstart)
free (relstart);
+ if (toc_ref != NULL)
+ free (toc_ref);
if (locsyms != NULL
&& (elf_tdata (ibfd)->symtab_hdr.contents
!= (unsigned char *) locsyms))
@@ -6840,8 +6852,12 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
rel - 1, ibfd);
if (retval == 0)
goto err_free_rel;
- if (toc_tls != NULL)
- expecting_tls_get_addr = retval > 1;
+ 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)
@@ -6859,8 +6875,40 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
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)
+ {
+ /* 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
+ tls_get_addr for the TOC16 relocs. */
+ if (toc_ref == NULL)
+ {
+ toc_ref = bfd_zmalloc (toc->size / 8);
+ if (toc_ref == NULL)
+ goto err_free_rel;
+ }
+ if (h != NULL)
+ value = h->root.u.def.value;
+ else
+ value = sym->st_value;
+ value += rel->r_addend;
+ 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;
+
case R_PPC64_TPREL64:
expecting_tls_get_addr = 0;
+ if (sec != toc
+ || toc_ref == NULL
+ || !toc_ref[rel->r_offset / 8])
+ continue;
if (ok_tprel)
{
/* IE -> LE */
@@ -6873,6 +6921,10 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
case R_PPC64_DTPMOD64:
expecting_tls_get_addr = 0;
+ if (sec != toc
+ || toc_ref == NULL
+ || !toc_ref[rel->r_offset / 8])
+ continue;
if (rel + 1 < relend
&& (rel[1].r_info
== ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64))
@@ -6951,6 +7003,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
free (relstart);
}
+ if (toc_ref != NULL)
+ free (toc_ref);
+
if (locsyms != NULL
&& (elf_tdata (ibfd)->symtab_hdr.contents
!= (unsigned char *) locsyms))
@@ -7146,13 +7201,14 @@ ppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_
return FALSE;
}
- /* Now check all kept sections that might reference the toc. */
- for (sec = ibfd->sections;
+ /* Now check all kept sections that might reference the toc.
+ Check the toc itself last. */
+ for (sec = (ibfd->sections == toc && toc->next ? toc->next
+ : ibfd->sections);
sec != NULL;
- /* Check the toc itself last. */
sec = (sec == toc ? NULL
- : sec->next == toc && sec->next->next ? sec->next->next
: sec->next == NULL ? toc
+ : sec->next == toc && toc->next ? toc->next
: sec->next))
{
int repeat;
Index: ld/testsuite/ld-powerpc/tlsexetoc.g
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexetoc.g,v
retrieving revision 1.5
diff -u -p -r1.5 tlsexetoc.g
--- ld/testsuite/ld-powerpc/tlsexetoc.g 15 Aug 2005 15:39:47 -0000 1.5
+++ ld/testsuite/ld-powerpc/tlsexetoc.g 5 May 2006 12:53:50 -0000
@@ -7,7 +7,7 @@
.*: +file format elf64-powerpc
Contents of section \.got:
-.* 00000000 10018558 00000000 00000000 .*
+.* 00000000 10018570 00000000 00000000 .*
.* 00000000 00000000 00000000 00000000 .*
.* 00000000 00000000 00000000 00000001 .*
.* 00000000 00000000 00000000 00000001 .*
Index: ld/testsuite/ld-powerpc/tlsexetoc.r
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexetoc.r,v
retrieving revision 1.16
diff -u -p -r1.16 tlsexetoc.r
--- ld/testsuite/ld-powerpc/tlsexetoc.r 2 Feb 2006 22:53:46 -0000 1.16
+++ ld/testsuite/ld-powerpc/tlsexetoc.r 5 May 2006 12:53:50 -0000
@@ -51,9 +51,10 @@ Program Headers:
+04 +\.dynamic
+05 +\.tdata \.tbss
-Relocation section '\.rela\.dyn' at offset .* contains 2 entries:
+Relocation section '\.rela\.dyn' at offset .* contains 3 entries:
+Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
-[0-9a-f ]+R_PPC64_TPREL64 +0+ gd \+ 0
+[0-9a-f ]+R_PPC64_DTPMOD64 +0+ gd \+ 0
+[0-9a-f ]+R_PPC64_DTPREL64 +0+ gd \+ 0
[0-9a-f ]+R_PPC64_DTPMOD64 +0+ ld \+ 0
Relocation section '\.rela\.plt' at offset .* contains 1 entries:
--
Alan Modra
IBM OzLabs - Linux Technology Centre