This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]