powerpc __tls_get_addr call optimization

Alan Modra amodra@bigpond.net.au
Mon Sep 21 11:30:00 GMT 2009


On Mon, Mar 30, 2009 at 06:20:29PM +1030, Alan Modra wrote:
> This patch is the ld support for a PowerPC TLS optimization, inspired
[snip http://sourceware.org/ml/binutils/2009-03/msg00498.html]
> I don't intend to commit this immediately as the patch isn't useful
> until glibc support is available.

Well the glibc patch was totally ignored, but I don't want to miss the
binutils release so I'm committing linker support.  This patch differs
slightly from the previous one in that ld now detects whether glibc
has the necessary support before using the new call stub.

include/elf/
	* ppc.h (DT_PPC_TLSOPT): Define.
	* ppc64.h (DT_PPC64_TLSOPT): Define.
bfd/
	* elf32-ppc.c (TLS_GET_ADDR_GLINK_SIZE): Define.
	(ADD_3_12_2, BEQLR, CMPWI_11_0, LWZ_11_3, LWZ_12_3): Define.
	(MR_0_3, MR_3_0): Define.
	(struct ppc_elf_link_hash_table): Add no_tls_get_addr_opt.
	(ppc_elf_select_plt_layout): Save emit_stub_syms param earlier.
	(ppc_elf_tls_setup): Add no_tls_get_addr_opt param and save to hash
	table.  Check for presense of __tls_get_addr_opt
	(allocate_dynrelocs): Increase glink entry size for __tls_get_addr.
	(ppc_elf_size_dynamic_sections): Add DT_PPC_TLS_OPT tag.
	(write_glink_stub): Add param p.
	(ppc_elf_relocate_section): Adjust write_glink_stub call.
	(ppc_elf_finish_dynamic_symbol): Emit special glink call stub for
	__tls_get_addr.
	* elf32-ppc.h (ppc_elf_tls_setup): Update prototype.
	* elf64-ppc.c (struct ppc_link_hash_table): Add no_tls_get_addr_opt.
	(ppc64_elf_tls_setup): Add no_tls_get_addr_opt param and save to hash
	table.  Check for presense of __tls_get_addr_opt.
	(ppc64_elf_size_dynamic_sections): Add DT_PPC64_TLS_OPT tag.
	(LD_R11_0R3, LD_R12_0R3, MR_R0_R3, CMPDI_R11_0, ADD_R3_R12_R13,
	BEQLR, MR_R3_R0, MFLR_R11, STD_R11_0R1, BCTRL, LD_R11_0R1,
	LD_R2_0R1, MTLR_R11): Define.
	(build_tls_get_addr_stub): New function.
	(ppc_build_one_stub): Call it.
	(ppc_size_one_stub): Add extra size for __tls_get_addr stub.
	(ppc64_elf_relocate_section): Don't change nop to ld 2,40(1) for
	__tls_get_addr plt call.
	* elf64-ppc.h (ppc64_elf_tls_setup): Update prototype.
binutils/
	* readelf.c (get_ppc_dynamic_type): Add TLSOPT.
	(get_ppc64_dynamic_type): Likewise.
ld/
	* emultempl/ppc32elf.em (no_tls_get_addr_opt): New var.
	(ppc_before_allocation): Pass to ppc_elf_tls_setup.
	(OPTION_NO_TLS_GET_ADDR_OPT): Define.  Redefine other options in
	terms of previous option.
	(PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add
	--no-tls-get-addr-optimize.
	(PARSE_AND_LIST_ARGS_CASES): Handle it.
	* emultempl/ppc64elf.em (no_tls_get_addr_opt): New var.
	(ppc_before_allocation): Pass to ppc64_elf_tls_setup.
	(OPTION_NO_TLS_GET_ADDR_OPT): Define.
	(PARSE_AND_LIST_LONGOPTS, PARSE_AND_LIST_OPTIONS): Add
	--no-tls-get-addr-optimize.
	(PARSE_AND_LIST_ARGS_CASES): Handle it.
ld/testsuite/
	* ld-powerpc/tlslib.s: Delete dot-symbol entry syms.  Add
	__tls_get_addr_opt.
	* ld-powerpc/tlslib32.s: Add __tls_get_addr_opt.
	* ld-powerpc/oldtlslib.s: New file, old-abi version of tlslib.s.
	* ld-powerpc/powerpc.exp: Build old-abi library and use it in
	two new link tests.
	* ld-powerpc/tlsexe.d: Update for new __tls_get_addr stub.
	* ld-powerpc/tlsexe.g, * ld-powerpc/tlsexe.r, *ld-powerpc/tlsexe32.d,
	* ld-powerpc/tlsexe32.g, * ld-powerpc/tlsexe32.r, 
	* ld-powerpc/tlsexetoc.d, * ld-powerpc/tlsexetoc.g,
	* ld-powerpc/tlsexetoc.r: Likewise.

Index: include/elf/ppc.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc.h,v
retrieving revision 1.25
diff -u -p -r1.25 ppc.h
--- include/elf/ppc.h	10 Jul 2009 12:19:55 -0000	1.25
+++ include/elf/ppc.h	20 Sep 2009 11:12:19 -0000
@@ -153,7 +153,10 @@ END_RELOC_NUMBERS (R_PPC_max)
   ((R) >= R_PPC_TLS && (R) <= R_PPC_GOT_DTPREL16_HA)
 
 /* Specify the value of _GLOBAL_OFFSET_TABLE_.  */
-#define DT_PPC_GOT		DT_LOPROC
+#define DT_PPC_GOT		(DT_LOPROC)
+
+/* Specify that tls descriptors should be optimized.  */
+#define DT_PPC_TLSOPT		(DT_LOPROC + 1)
 
 /* Processor specific flags for the ELF header e_flags field.  */
 
Index: include/elf/ppc64.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc64.h,v
retrieving revision 1.7
diff -u -p -r1.7 ppc64.h
--- include/elf/ppc64.h	29 Jul 2009 14:55:20 -0000	1.7
+++ include/elf/ppc64.h	20 Sep 2009 11:12:19 -0000
@@ -165,4 +165,7 @@ END_RELOC_NUMBERS (R_PPC64_max)
 #define DT_PPC64_OPD		(DT_LOPROC + 1)
 #define DT_PPC64_OPDSZ		(DT_LOPROC + 2)
 
+/* Specify that tls descriptors should be optimized.  */
+#define DT_PPC64_TLSOPT		(DT_LOPROC + 3)
+
 #endif /* _ELF_PPC64_H */
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.268
diff -u -p -r1.268 elf32-ppc.c
--- bfd/elf32-ppc.c	18 Sep 2009 12:41:52 -0000	1.268
+++ bfd/elf32-ppc.c	20 Sep 2009 11:11:20 -0000
@@ -61,6 +61,7 @@ static bfd_reloc_status_type ppc_elf_unh
 /* For new-style .glink and .plt.  */
 #define GLINK_PLTRESOLVE 16*4
 #define GLINK_ENTRY_SIZE 4*4
+#define TLS_GET_ADDR_GLINK_SIZE 12*4
 
 /* VxWorks uses its own plt layout, filled in by the static linker.  */
 
@@ -135,17 +136,24 @@ static const bfd_vma ppc_elf_vxworks_pic
 #define ADDIS_12_12	0x3d8c0000
 #define ADDI_11_11	0x396b0000
 #define ADD_0_11_11	0x7c0b5a14
+#define ADD_3_12_2	0x7c6c1214
 #define ADD_11_0_11	0x7d605a14
 #define B		0x48000000
 #define BCL_20_31	0x429f0005
 #define BCTR		0x4e800420
+#define BEQLR		0x4d820020
+#define CMPWI_11_0	0x2c0b0000
 #define LIS_11		0x3d600000
 #define LIS_12		0x3d800000
 #define LWZU_0_12	0x840c0000
 #define LWZ_0_12	0x800c0000
+#define LWZ_11_3	0x81630000
 #define LWZ_11_11	0x816b0000
 #define LWZ_11_30	0x817e0000
+#define LWZ_12_3	0x81830000
 #define LWZ_12_12	0x818c0000
+#define MR_0_3		0x7c601b78
+#define MR_3_0		0x7c030378
 #define MFLR_0		0x7c0802a6
 #define MFLR_12		0x7d8802a6
 #define MTCTR_0		0x7c0903a6
@@ -2754,6 +2762,9 @@ struct ppc_elf_link_hash_table
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
+  /* Set if __tls_get_addr optimization should not be done.  */
+  unsigned int no_tls_get_addr_opt:1;
+
   /* True if the target system is VxWorks.  */
   unsigned int is_vxworks:1;
 
@@ -4277,6 +4288,8 @@ ppc_elf_select_plt_layout (bfd *output_b
 
   htab = ppc_elf_hash_table (info);
 
+  htab->emit_stub_syms = emit_stub_syms;
+
   if (htab->plt_type == PLT_UNSET)
     {
       if (plt_style == PLT_OLD)
@@ -4310,8 +4323,6 @@ ppc_elf_select_plt_layout (bfd *output_b
   if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW)
     info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd);
 
-  htab->emit_stub_syms = emit_stub_syms;
-
   BFD_ASSERT (htab->plt_type != PLT_VXWORKS);
 
   if (htab->plt_type == PLT_NEW)
@@ -4539,11 +4550,62 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
    generic ELF tls_setup function.  */
 
 asection *
-ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+ppc_elf_tls_setup (bfd *obfd,
+		   struct bfd_link_info *info,
+		   int no_tls_get_addr_opt)
 {
   struct ppc_elf_link_hash_table *htab;
 
   htab = ppc_elf_hash_table (info);
+  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+					     FALSE, FALSE, TRUE);
+  if (!no_tls_get_addr_opt)
+    {
+      struct elf_link_hash_entry *opt, *tga;
+      opt = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
+				  FALSE, FALSE, TRUE);
+      if (opt != NULL
+	  && (opt->root.type == bfd_link_hash_defined
+	      || opt->root.type == bfd_link_hash_defweak))
+	{
+	  /* If glibc supports an optimized __tls_get_addr call stub,
+	     signalled by the presence of __tls_get_addr_opt, and we'll
+	     be calling __tls_get_addr via a plt call stub, then
+	     make __tls_get_addr point to __tls_get_addr_opt.  */
+	  tga = htab->tls_get_addr;
+	  if (htab->elf.dynamic_sections_created
+	      && tga != NULL
+	      && (tga->type == STT_FUNC
+		  || tga->needs_plt)
+	      && !(SYMBOL_CALLS_LOCAL (info, tga)
+		   || (ELF_ST_VISIBILITY (tga->other) != STV_DEFAULT
+		       && tga->root.type == bfd_link_hash_undefweak)))
+	    {
+	      struct plt_entry *ent;
+	      ent = find_plt_ent (&tga->plt.plist, NULL, 0);
+	      if (ent != NULL
+		  && ent->plt.refcount > 0)
+		{
+		  tga->root.type = bfd_link_hash_indirect;
+		  tga->root.u.i.link = &opt->root;
+		  ppc_elf_copy_indirect_symbol (info, opt, tga);
+		  if (opt->dynindx != -1)
+		    {
+		      /* Use __tls_get_addr_opt in dynamic relocations.  */
+		      opt->dynindx = -1;
+		      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+					      opt->dynstr_index);
+		      if (!bfd_elf_link_record_dynamic_symbol (info, opt))
+			return FALSE;
+		    }
+		  htab->tls_get_addr = opt;
+		}
+	    }
+	}
+      else
+	no_tls_get_addr_opt = TRUE;
+    }
+  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
   if (htab->plt_type == PLT_NEW
       && htab->plt != NULL
       && htab->plt->output_section != NULL)
@@ -4552,8 +4614,6 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd
       elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE;
     }
 
-  htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
-					     FALSE, FALSE, TRUE);
   return _bfd_elf_tls_setup (obfd, info);
 }
 
@@ -5144,6 +5204,9 @@ allocate_dynrelocs (struct elf_link_hash
 		      {
 			glink_offset = s->size;
 			s->size += GLINK_ENTRY_SIZE;
+			if (h == htab->tls_get_addr
+			    && !htab->no_tls_get_addr_opt)
+			  s->size += TLS_GET_ADDR_GLINK_SIZE - GLINK_ENTRY_SIZE;
 		      }
 		    if (!doneone
 			&& !info->shared
@@ -5820,6 +5883,11 @@ ppc_elf_size_dynamic_sections (bfd *outp
 	{
 	  if (!add_dynamic_entry (DT_PPC_GOT, 0))
 	    return FALSE;
+	  if (!htab->no_tls_get_addr_opt
+	      && htab->tls_get_addr != NULL
+	      && htab->tls_get_addr->plt.plist != NULL
+	      && !add_dynamic_entry (DT_PPC_TLSOPT, 0))
+	    return FALSE;
 	}
 
       if (relocs)
@@ -6474,18 +6542,16 @@ elf_finish_pointer_linker_section (bfd *
 #define PPC_HA(v) PPC_HI ((v) + 0x8000)
 
 static void
-write_glink_stub (struct plt_entry *ent, asection *plt_sec,
+write_glink_stub (struct plt_entry *ent, asection *plt_sec, unsigned char *p,
 		  struct bfd_link_info *info)
 {
   struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info);
   bfd *output_bfd = info->output_bfd;
   bfd_vma plt;
-  unsigned char *p;
 
   plt = ((ent->plt.offset & ~1)
 	 + plt_sec->output_section->vma
 	 + plt_sec->output_offset);
-  p = (unsigned char *) htab->glink->contents + ent->glink_offset;
 
   if (info->shared)
     {
@@ -7045,7 +7111,9 @@ ppc_elf_relocate_section (bfd *output_bf
 		}
 	      if (h == NULL && (ent->glink_offset & 1) == 0)
 		{
-		  write_glink_stub (ent, htab->iplt, info);
+		  unsigned char *p = ((unsigned char *) htab->glink->contents
+				      + ent->glink_offset);
+		  write_glink_stub (ent, htab->iplt, p, info);
 		  ent->glink_offset |= 1;
 		}
 
@@ -8274,12 +8342,35 @@ ppc_elf_finish_dynamic_symbol (bfd *outp
 	    || !htab->elf.dynamic_sections_created
 	    || h->dynindx == -1)
 	  {
+	    unsigned char *p;
 	    asection *splt = htab->plt;
 	    if (!htab->elf.dynamic_sections_created
 		|| h->dynindx == -1)
 	      splt = htab->iplt;
 
-	    write_glink_stub (ent, splt, info);
+	    p = (unsigned char *) htab->glink->contents + ent->glink_offset;
+
+	    if (h == htab->tls_get_addr && !htab->no_tls_get_addr_opt)
+	      {
+		bfd_put_32 (output_bfd, LWZ_11_3, p);
+		p += 4;
+		bfd_put_32 (output_bfd, LWZ_12_3 + 4, p);
+		p += 4;
+		bfd_put_32 (output_bfd, MR_0_3, p);
+		p += 4;
+		bfd_put_32 (output_bfd, CMPWI_11_0, p);
+		p += 4;
+		bfd_put_32 (output_bfd, ADD_3_12_2, p);
+		p += 4;
+		bfd_put_32 (output_bfd, BEQLR, p);
+		p += 4;
+		bfd_put_32 (output_bfd, MR_3_0, p);
+		p += 4;
+		bfd_put_32 (output_bfd, NOP, p);
+		p += 4;
+	      }
+
+	    write_glink_stub (ent, splt, p, info);
 
 	    if (!info->shared)
 	      /* We only need one non-PIC glink stub.  */
Index: bfd/elf32-ppc.h
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.h,v
retrieving revision 1.11
diff -u -p -r1.11 elf32-ppc.h
--- bfd/elf32-ppc.h	3 Jul 2007 14:26:41 -0000	1.11
+++ bfd/elf32-ppc.h	20 Sep 2009 11:11:20 -0000
@@ -28,6 +28,6 @@ enum ppc_elf_plt_type
 
 int ppc_elf_select_plt_layout (bfd *, struct bfd_link_info *,
 			       enum ppc_elf_plt_type, int);
-asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *);
+asection *ppc_elf_tls_setup (bfd *, struct bfd_link_info *, int);
 bfd_boolean ppc_elf_tls_optimize (bfd *, struct bfd_link_info *);
 void ppc_elf_set_sdata_syms (bfd *, struct bfd_link_info *);
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.300
diff -u -p -r1.300 elf64-ppc.c
--- bfd/elf64-ppc.c	18 Sep 2009 03:30:33 -0000	1.300
+++ bfd/elf64-ppc.c	20 Sep 2009 11:11:29 -0000
@@ -3771,6 +3771,9 @@ struct ppc_link_hash_table
   /* Set if we should emit symbols for stubs.  */
   unsigned int emit_stub_syms:1;
 
+  /* Set if __tls_get_addr optimization should not be done.  */
+  unsigned int no_tls_get_addr_opt:1;
+
   /* Support for multiple toc sections.  */
   unsigned int no_multi_toc:1;
   unsigned int multi_toc_needed:1;
@@ -7218,7 +7221,9 @@ ppc64_elf_edit_opd (bfd *obfd, struct bf
 /* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
 
 asection *
-ppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
+ppc64_elf_tls_setup (bfd *obfd,
+		     struct bfd_link_info *info,
+		     int no_tls_get_addr_opt)
 {
   struct ppc_link_hash_table *htab;
 
@@ -7226,9 +7231,83 @@ ppc64_elf_tls_setup (bfd *obfd, struct b
   htab->tls_get_addr = ((struct ppc_link_hash_entry *)
 			elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
 					      FALSE, FALSE, TRUE));
+  /* Move dynamic linking info to the function descriptor sym.  */
+  if (htab->tls_get_addr != NULL)
+    func_desc_adjust (&htab->tls_get_addr->elf, info);
   htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
 			   elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
 						 FALSE, FALSE, TRUE));
+  if (!no_tls_get_addr_opt)
+    {
+      struct elf_link_hash_entry *opt, *opt_fd, *tga, *tga_fd;
+
+      opt = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr_opt",
+				  FALSE, FALSE, TRUE);
+      if (opt != NULL)
+	func_desc_adjust (opt, info);
+      opt_fd = elf_link_hash_lookup (&htab->elf, "__tls_get_addr_opt",
+				     FALSE, FALSE, TRUE);
+      if (opt_fd != NULL
+	  && (opt_fd->root.type == bfd_link_hash_defined
+	      || opt_fd->root.type == bfd_link_hash_defweak))
+	{
+	  /* If glibc supports an optimized __tls_get_addr call stub,
+	     signalled by the presence of __tls_get_addr_opt, and we'll
+	     be calling __tls_get_addr via a plt call stub, then
+	     make __tls_get_addr point to __tls_get_addr_opt.  */
+	  tga_fd = &htab->tls_get_addr_fd->elf;
+	  if (htab->elf.dynamic_sections_created
+	      && tga_fd != NULL
+	      && (tga_fd->type == STT_FUNC
+		  || tga_fd->needs_plt)
+	      && !(SYMBOL_CALLS_LOCAL (info, tga_fd)
+		   || (ELF_ST_VISIBILITY (tga_fd->other) != STV_DEFAULT
+		       && tga_fd->root.type == bfd_link_hash_undefweak)))
+	    {
+	      struct plt_entry *ent;
+
+	      for (ent = tga_fd->plt.plist; ent != NULL; ent = ent->next)
+		if (ent->plt.refcount > 0)
+		  break;
+	      if (ent != NULL)
+		{
+		  tga_fd->root.type = bfd_link_hash_indirect;
+		  tga_fd->root.u.i.link = &opt_fd->root;
+		  ppc64_elf_copy_indirect_symbol (info, opt_fd, tga_fd);
+		  if (opt_fd->dynindx != -1)
+		    {
+		      /* Use __tls_get_addr_opt in dynamic relocations.  */
+		      opt_fd->dynindx = -1;
+		      _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr,
+					      opt_fd->dynstr_index);
+		      if (!bfd_elf_link_record_dynamic_symbol (info, opt_fd))
+			return FALSE;
+		    }
+		  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) opt_fd;
+		  tga = &htab->tls_get_addr->elf;
+		  if (opt != NULL && tga != NULL)
+		    {
+		      tga->root.type = bfd_link_hash_indirect;
+		      tga->root.u.i.link = &opt->root;
+		      ppc64_elf_copy_indirect_symbol (info, opt, tga);
+		      _bfd_elf_link_hash_hide_symbol (info, opt,
+						      tga->forced_local);
+		      htab->tls_get_addr = (struct ppc_link_hash_entry *) opt;
+		    }
+		  htab->tls_get_addr_fd->oh = htab->tls_get_addr;
+		  htab->tls_get_addr_fd->is_func_descriptor = 1;
+		  if (htab->tls_get_addr != NULL)
+		    {
+		      htab->tls_get_addr->oh = htab->tls_get_addr_fd;
+		      htab->tls_get_addr->is_func = 1;
+		    }
+		}
+	    }
+	}
+      else
+	no_tls_get_addr_opt = TRUE;
+    }
+  htab->no_tls_get_addr_opt = no_tls_get_addr_opt;
   return _bfd_elf_tls_setup (obfd, info);
 }
 
@@ -8666,6 +8745,12 @@ ppc64_elf_size_dynamic_sections (bfd *ou
 	    return FALSE;
 	}
 
+      if (!htab->no_tls_get_addr_opt
+	  && htab->tls_get_addr_fd != NULL
+	  && htab->tls_get_addr_fd->elf.plt.plist != NULL
+	  && !add_dynamic_entry (DT_PPC64_TLSOPT, 0))
+	return FALSE;
+
       if (relocs)
 	{
 	  if (!add_dynamic_entry (DT_RELA, 0)
@@ -8859,6 +8944,49 @@ build_plt_stub (bfd *obfd, bfd_byte *p, 
   return p;
 }
 
+/* Build a special .plt call stub for __tls_get_addr.  */
+
+#define LD_R11_0R3	0xe9630000
+#define LD_R12_0R3	0xe9830000
+#define MR_R0_R3	0x7c601b78
+#define CMPDI_R11_0	0x2c2b0000
+#define ADD_R3_R12_R13	0x7c6c6a14
+#define BEQLR		0x4d820020
+#define MR_R3_R0	0x7c030378
+#define MFLR_R11	0x7d6802a6
+#define STD_R11_0R1	0xf9610000
+#define BCTRL		0x4e800421
+#define LD_R11_0R1	0xe9610000
+#define LD_R2_0R1	0xe8410000
+#define MTLR_R11	0x7d6803a6
+
+static inline bfd_byte *
+build_tls_get_addr_stub (bfd *obfd, bfd_byte *p, int offset,
+			 Elf_Internal_Rela *r)
+{
+  bfd_put_32 (obfd, LD_R11_0R3 + 0, p),		p += 4;
+  bfd_put_32 (obfd, LD_R12_0R3 + 8, p),		p += 4;
+  bfd_put_32 (obfd, MR_R0_R3, p),		p += 4;
+  bfd_put_32 (obfd, CMPDI_R11_0, p),		p += 4;
+  bfd_put_32 (obfd, ADD_R3_R12_R13, p),		p += 4;
+  bfd_put_32 (obfd, BEQLR, p),			p += 4;
+  bfd_put_32 (obfd, MR_R3_R0, p),		p += 4;
+  bfd_put_32 (obfd, MFLR_R11, p),		p += 4;
+  bfd_put_32 (obfd, STD_R11_0R1 + 32, p),	p += 4;
+
+  if (r != NULL)
+    r[0].r_offset += 9 * 4;
+  p = build_plt_stub (obfd, p, offset, r);
+  bfd_put_32 (obfd, BCTRL, p - 4);
+
+  bfd_put_32 (obfd, LD_R11_0R1 + 32, p),	p += 4;
+  bfd_put_32 (obfd, LD_R2_0R1 + 40, p),		p += 4;
+  bfd_put_32 (obfd, MTLR_R11, p),		p += 4;
+  bfd_put_32 (obfd, BLR, p),			p += 4;
+
+  return p;
+}
+
 static Elf_Internal_Rela *
 get_relocs (asection *sec, int count)
 {
@@ -9227,7 +9355,13 @@ ppc_build_one_stub (struct bfd_hash_entr
 	    r[0].r_offset += 2;
 	  r[0].r_addend = dest;
 	}
-      p = build_plt_stub (htab->stub_bfd, loc, off, r);
+      if (stub_entry->h != NULL
+	  && (stub_entry->h == htab->tls_get_addr_fd
+	      || stub_entry->h == htab->tls_get_addr)
+	  && !htab->no_tls_get_addr_opt)
+	p = build_tls_get_addr_stub (htab->stub_bfd, loc, off, r);
+      else
+	p = build_plt_stub (htab->stub_bfd, loc, off, r);
       size = p - loc;
       break;
 
@@ -9316,6 +9450,11 @@ ppc_size_one_stub (struct bfd_hash_entry
 	size -= 4;
       if (PPC_HA (off + 16) != PPC_HA (off))
 	size += 4;
+      if (stub_entry->h != NULL
+	  && (stub_entry->h == htab->tls_get_addr_fd
+	      || stub_entry->h == htab->tls_get_addr)
+	  && !htab->no_tls_get_addr_opt)
+	size += 13 * 4;
       if (info->emitrelocations)
 	{
 	  stub_entry->stub_sec->reloc_count
@@ -11255,8 +11394,16 @@ ppc64_elf_relocate_section (bfd *output_
 		  if (nop == NOP
 		      || nop == CROR_151515 || nop == CROR_313131)
 		    {
-		      bfd_put_32 (input_bfd, LD_R2_40R1,
-				  contents + rel->r_offset + 4);
+		      if (h != NULL
+			  && (h == htab->tls_get_addr_fd
+			      || h == htab->tls_get_addr)
+			  && !htab->no_tls_get_addr_opt)
+			{
+			  /* Special stub used, leave nop alone.  */
+			}
+		      else
+			bfd_put_32 (input_bfd, LD_R2_40R1,
+				    contents + rel->r_offset + 4);
 		      can_plt_call = TRUE;
 		    }
 		}
Index: bfd/elf64-ppc.h
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.h,v
retrieving revision 1.25
diff -u -p -r1.25 elf64-ppc.h
--- bfd/elf64-ppc.h	15 Jan 2008 07:25:49 -0000	1.25
+++ bfd/elf64-ppc.h	20 Sep 2009 11:11:29 -0000
@@ -24,7 +24,7 @@ void ppc64_elf_init_stub_bfd
 bfd_boolean ppc64_elf_edit_opd
   (bfd *, struct bfd_link_info *, bfd_boolean);
 asection *ppc64_elf_tls_setup
-  (bfd *, struct bfd_link_info *);
+(bfd *, struct bfd_link_info *, int);
 bfd_boolean ppc64_elf_tls_optimize
   (bfd *, struct bfd_link_info *);
 bfd_boolean ppc64_elf_edit_toc
Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.459
diff -u -p -r1.459 readelf.c
--- binutils/readelf.c	14 Sep 2009 12:29:50 -0000	1.459
+++ binutils/readelf.c	21 Sep 2009 03:12:04 -0000
@@ -1470,7 +1470,8 @@ get_ppc_dynamic_type (unsigned long type
 {
   switch (type)
     {
-    case DT_PPC_GOT: return "PPC_GOT";
+    case DT_PPC_GOT:    return "PPC_GOT";
+    case DT_PPC_TLSOPT: return "PPC_TLSOPT";
     default:
       return NULL;
     }
@@ -1481,9 +1482,10 @@ get_ppc64_dynamic_type (unsigned long ty
 {
   switch (type)
     {
-    case DT_PPC64_GLINK: return "PPC64_GLINK";
-    case DT_PPC64_OPD:   return "PPC64_OPD";
-    case DT_PPC64_OPDSZ: return "PPC64_OPDSZ";
+    case DT_PPC64_GLINK:  return "PPC64_GLINK";
+    case DT_PPC64_OPD:    return "PPC64_OPD";
+    case DT_PPC64_OPDSZ:  return "PPC64_OPDSZ";
+    case DT_PPC64_TLSOPT: return "PPC64_TLSOPT";
     default:
       return NULL;
     }
Index: ld/emultempl/ppc32elf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/ppc32elf.em,v
retrieving revision 1.21
diff -u -p -r1.21 ppc32elf.em
--- ld/emultempl/ppc32elf.em	2 Sep 2009 07:25:35 -0000	1.21
+++ ld/emultempl/ppc32elf.em	20 Sep 2009 11:12:26 -0000
@@ -33,6 +33,7 @@ fragment <<EOF
 
 /* Whether to run tls optimization.  */
 static int notlsopt = 0;
+static int no_tls_get_addr_opt = 0;
 
 /* Whether to emit symbols for stubs.  */
 static int emit_stub_syms = 0;
@@ -103,7 +104,9 @@ ppc_before_allocation (void)
 {
   if (is_ppc_elf (link_info.output_bfd))
     {
-      if (ppc_elf_tls_setup (link_info.output_bfd, &link_info) && !notlsopt)
+      if (ppc_elf_tls_setup (link_info.output_bfd, &link_info,
+			     no_tls_get_addr_opt)
+	  && !notlsopt)
 	{
 	  if (!ppc_elf_tls_optimize (link_info.output_bfd, &link_info))
 	    {
@@ -174,15 +177,17 @@ fi
 #
 PARSE_AND_LIST_PROLOGUE='
 #define OPTION_NO_TLS_OPT		301
-#define OPTION_NEW_PLT			302
-#define OPTION_OLD_PLT			303
-#define OPTION_OLD_GOT			304
-#define OPTION_STUBSYMS			305
+#define OPTION_NO_TLS_GET_ADDR_OPT	(OPTION_NO_TLS_OPT + 1)
+#define OPTION_NEW_PLT			(OPTION_NO_TLS_GET_ADDR_OPT + 1)
+#define OPTION_OLD_PLT			(OPTION_NEW_PLT + 1)
+#define OPTION_OLD_GOT			(OPTION_OLD_PLT + 1)
+#define OPTION_STUBSYMS			(OPTION_OLD_GOT + 1)
 '
 
 PARSE_AND_LIST_LONGOPTS='
   { "emit-stub-syms", no_argument, NULL, OPTION_STUBSYMS },
   { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT },
+  { "no-tls-get-addr-optimize", no_argument, NULL, OPTION_NO_TLS_GET_ADDR_OPT },
   { "secure-plt", no_argument, NULL, OPTION_NEW_PLT },
   { "bss-plt", no_argument, NULL, OPTION_OLD_PLT },
   { "sdata-got", no_argument, NULL, OPTION_OLD_GOT },
@@ -192,6 +197,7 @@ PARSE_AND_LIST_OPTIONS='
   fprintf (file, _("\
   --emit-stub-syms            Label linker stubs with a symbol.\n\
   --no-tls-optimize           Don'\''t try to optimize TLS accesses.\n\
+  --no-tls-get-addr-optimize  Don'\''t use a special __tls_get_addr call.\n\
   --secure-plt                Use new-style PLT if possible.\n\
   --bss-plt                   Force old-style BSS PLT.\n\
   --sdata-got                 Force GOT location just before .sdata.\n"
@@ -207,6 +213,10 @@ PARSE_AND_LIST_ARGS_CASES='
       notlsopt = 1;
       break;
 
+    case OPTION_NO_TLS_GET_ADDR_OPT:
+      no_tls_get_addr_opt = 1;
+      break;
+
     case OPTION_NEW_PLT:
       plt_style = PLT_NEW;
       break;
Index: ld/emultempl/ppc64elf.em
===================================================================
RCS file: /cvs/src/src/ld/emultempl/ppc64elf.em,v
retrieving revision 1.63
diff -u -p -r1.63 ppc64elf.em
--- ld/emultempl/ppc64elf.em	2 Sep 2009 07:25:35 -0000	1.63
+++ ld/emultempl/ppc64elf.em	20 Sep 2009 11:12:26 -0000
@@ -47,6 +47,7 @@ static int dotsyms = 1;
 
 /* Whether to run tls optimization.  */
 static int no_tls_opt = 0;
+static int no_tls_get_addr_opt = 0;
 
 /* Whether to run opd optimization.  */
 static int no_opd_opt = 0;
@@ -106,7 +107,8 @@ ppc_before_allocation (void)
 				  non_overlapping_opd))
 	einfo ("%X%P: can not edit %s %E\n", "opd");
 
-      if (ppc64_elf_tls_setup (link_info.output_bfd, &link_info)
+      if (ppc64_elf_tls_setup (link_info.output_bfd, &link_info,
+			       no_tls_get_addr_opt)
 	  && !no_tls_opt)
 	{
 	  /* Size the sections.  This is premature, but we want to know the
@@ -488,7 +490,8 @@ PARSE_AND_LIST_PROLOGUE='
 #define OPTION_DOTSYMS			(OPTION_STUBSYMS + 1)
 #define OPTION_NO_DOTSYMS		(OPTION_DOTSYMS + 1)
 #define OPTION_NO_TLS_OPT		(OPTION_NO_DOTSYMS + 1)
-#define OPTION_NO_OPD_OPT		(OPTION_NO_TLS_OPT + 1)
+#define OPTION_NO_TLS_GET_ADDR_OPT	(OPTION_NO_TLS_OPT + 1)
+#define OPTION_NO_OPD_OPT		(OPTION_NO_TLS_GET_ADDR_OPT + 1)
 #define OPTION_NO_TOC_OPT		(OPTION_NO_OPD_OPT + 1)
 #define OPTION_NO_MULTI_TOC		(OPTION_NO_TOC_OPT + 1)
 #define OPTION_NON_OVERLAPPING_OPD	(OPTION_NO_MULTI_TOC + 1)
@@ -500,6 +503,7 @@ PARSE_AND_LIST_LONGOPTS='
   { "dotsyms", no_argument, NULL, OPTION_DOTSYMS },
   { "no-dotsyms", no_argument, NULL, OPTION_NO_DOTSYMS },
   { "no-tls-optimize", no_argument, NULL, OPTION_NO_TLS_OPT },
+  { "no-tls-get-addr-optimize", no_argument, NULL, OPTION_NO_TLS_GET_ADDR_OPT },
   { "no-opd-optimize", no_argument, NULL, OPTION_NO_OPD_OPT },
   { "no-toc-optimize", no_argument, NULL, OPTION_NO_TOC_OPT },
   { "no-multi-toc", no_argument, NULL, OPTION_NO_MULTI_TOC },
@@ -533,6 +537,9 @@ PARSE_AND_LIST_OPTIONS='
   --no-tls-optimize           Don'\''t try to optimize TLS accesses.\n"
 		   ));
   fprintf (file, _("\
+  --no-tls-get-addr-optimize  Don'\''t use a special __tls_get_addr call.\n"
+		   ));
+  fprintf (file, _("\
   --no-opd-optimize           Don'\''t optimize the OPD section.\n"
 		   ));
   fprintf (file, _("\
@@ -573,6 +580,10 @@ PARSE_AND_LIST_ARGS_CASES='
       no_tls_opt = 1;
       break;
 
+    case OPTION_NO_TLS_GET_ADDR_OPT:
+      no_tls_get_addr_opt = 1;
+      break;
+
     case OPTION_NO_OPD_OPT:
       no_opd_opt = 1;
       break;
Index: ld/testsuite/ld-powerpc/powerpc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/powerpc.exp,v
retrieving revision 1.28
diff -u -p -r1.28 powerpc.exp
--- ld/testsuite/ld-powerpc/powerpc.exp	23 Aug 2009 14:38:31 -0000	1.28
+++ ld/testsuite/ld-powerpc/powerpc.exp	20 Sep 2009 11:12:29 -0000
@@ -138,10 +138,16 @@ set ppc64elftests {
       "tls"}
     {"TLS helper shared library" "-shared -melf64ppc tmpdir/tlslib.o" "" {}
      {} "libtlslib.so"}
+    {"TLS helper old shared lib" "-shared -melf64ppc" "-a64" {oldtlslib.s}
+     {} "liboldlib.so"}
     {"TLS dynamic exec" "-melf64ppc tmpdir/tls.o tmpdir/libtlslib.so" "" {}
      {{readelf -WSsrl tlsexe.r} {objdump -dr tlsexe.d}
       {objdump -sj.got tlsexe.g} {objdump -sj.tdata tlsexe.t}}
       "tlsexe"}
+    {"TLS dynamic old" "-melf64ppc tmpdir/tls.o tmpdir/liboldlib.so" "" {}
+     {{readelf -WSsrl tlsexe.r} {objdump -dr tlsexe.d}
+      {objdump -sj.got tlsexe.g} {objdump -sj.tdata tlsexe.t}}
+      "tlsexeold"}
     {"TLS shared" "-shared -melf64ppc tmpdir/tls.o" "" {}
      {{readelf -WSsrl tlsso.r} {objdump -dr tlsso.d}
       {objdump -sj.got tlsso.g} {objdump -sj.tdata tlsso.t}}
@@ -155,6 +161,11 @@ set ppc64elftests {
      {{readelf -WSsrl tlsexetoc.r} {objdump -dr tlsexetoc.d}
       {objdump -sj.got tlsexetoc.g} {objdump -sj.tdata tlsexetoc.t}}
       "tlsexetoc"}
+    {"TLSTOC dynamic old" "-melf64ppc tmpdir/tlstoc.o tmpdir/liboldlib.so"
+     "" {}
+     {{readelf -WSsrl tlsexetoc.r} {objdump -dr tlsexetoc.d}
+      {objdump -sj.got tlsexetoc.g} {objdump -sj.tdata tlsexetoc.t}}
+      "tlsexetocold"}
     {"TLSTOC shared" "-shared -melf64ppc tmpdir/tlstoc.o" "" {}
      {{readelf -WSsrl tlstocso.r} {objdump -dr tlstocso.d}
       {objdump -sj.got tlstocso.g} {objdump -sj.tdata tlstocso.t}}
Index: ld/testsuite/ld-powerpc/tlsexe.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexe.d,v
retrieving revision 1.7
diff -u -p -r1.7 tlsexe.d
--- ld/testsuite/ld-powerpc/tlsexe.d	13 Aug 2007 00:20:59 -0000	1.7
+++ ld/testsuite/ld-powerpc/tlsexe.d	20 Sep 2009 11:12:29 -0000
@@ -8,21 +8,34 @@
 
 Disassembly of section \.text:
 
-.* <_start-0x18>:
+.* <_start-0x4c>:
+.*	e9 63 00 00 	ld      r11,0\(r3\)
+.*	e9 83 00 08 	ld      r12,8\(r3\)
+.*	7c 60 1b 78 	mr      r0,r3
+.*	2c 2b 00 00 	cmpdi   r11,0
+.*	7c 6c 6a 14 	add     r3,r12,r13
+.*	4d 82 00 20 	beqlr   
+.*	7c 03 03 78 	mr      r3,r0
+.*	7d 68 02 a6 	mflr    r11
+.*	f9 61 00 20 	std     r11,32\(r1\)
 .*	f8 41 00 28 	std     r2,40\(r1\)
 .*	e9 62 80 48 	ld      r11,-32696\(r2\)
 .*	7d 69 03 a6 	mtctr   r11
 .*	e9 62 80 58 	ld      r11,-32680\(r2\)
 .*	e8 42 80 50 	ld      r2,-32688\(r2\)
-.*	4e 80 04 20 	bctr
+.*	4e 80 04 21 	bctrl
+.*	e9 61 00 20 	ld      r11,32\(r1\)
+.*	e8 41 00 28 	ld      r2,40\(r1\)
+.*	7d 68 03 a6 	mtlr    r11
+.*	4e 80 00 20 	blr
 
 .* <_start>:
 .*	e8 62 80 10 	ld      r3,-32752\(r2\)
 .*	60 00 00 00 	nop
 .*	7c 63 6a 14 	add     r3,r3,r13
 .*	38 62 80 18 	addi    r3,r2,-32744
-.*	4b ff ff d9 	bl      .*
-.*	e8 41 00 28 	ld      r2,40\(r1\)
+.*	4b ff ff a5 	bl      .*
+.*	60 00 00 00 	nop
 .*	3c 6d 00 00 	addis   r3,r13,0
 .*	60 00 00 00 	nop
 .*	38 63 90 38 	addi    r3,r3,-28616
@@ -55,8 +68,9 @@ Disassembly of section \.text:
 .*	e9 4d 90 2a 	lwa     r10,-28632\(r13\)
 .*	3d 2d 00 00 	addis   r9,r13,0
 .*	a9 49 90 30 	lha     r10,-28624\(r9\)
+.*	60 00 00 00 	nop
 .*	00 00 00 00 .*
-.*	00 01 01 f0 .*
+.*	00 01 02 00 .*
 .*	7d 88 02 a6 	mflr    r12
 .*	42 9f 00 05 	bcl-    20,4\*cr7\+so,.*
 .*	7d 68 02 a6 	mflr    r11
Index: ld/testsuite/ld-powerpc/tlsexe.g
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexe.g,v
retrieving revision 1.7
diff -u -p -r1.7 tlsexe.g
--- ld/testsuite/ld-powerpc/tlsexe.g	13 Aug 2007 00:20:59 -0000	1.7
+++ ld/testsuite/ld-powerpc/tlsexe.g	20 Sep 2009 11:12:29 -0000
@@ -7,6 +7,6 @@
 .*: +file format elf64-powerpc
 
 Contents of section \.got:
-.* 00000000 100185c8 ffffffff ffff8018  .*
+.* 00000000 10018618 ffffffff ffff8018  .*
 .* 00000000 00000000 00000000 00000000  .*
 .* 00000000 00000000 00000000 00000000  .*
Index: ld/testsuite/ld-powerpc/tlsexe.r
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexe.r,v
retrieving revision 1.21
diff -u -p -r1.21 tlsexe.r
--- ld/testsuite/ld-powerpc/tlsexe.r	30 Sep 2007 01:33:15 -0000	1.21
+++ ld/testsuite/ld-powerpc/tlsexe.r	20 Sep 2009 11:12:29 -0000
@@ -16,10 +16,10 @@ Section Headers:
  +\[[ 0-9]+\] \.dynstr +.*
  +\[[ 0-9]+\] \.rela\.dyn +.*
  +\[[ 0-9]+\] \.rela\.plt +.*
- +\[[ 0-9]+\] \.text +PROGBITS .* 0+f8 0+ +AX +0 +0 +8
+ +\[[ 0-9]+\] \.text +PROGBITS .* 0+130 0+ +AX +0 +0 +8
  +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8
- +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+150 10 +WA +4 +0 +8
+ +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8
  +\[[ 0-9]+\] \.branch_lt + PROGBITS .* 0+ 0+ +WA +0 +0 +8
  +\[[ 0-9]+\] \.got +PROGBITS .* 0+30 08 +WA +0 +0 +8
  +\[[ 0-9]+\] \.plt +.*
@@ -59,16 +59,16 @@ Relocation section '\.rela\.dyn' at offs
 
 Relocation section '\.rela\.plt' at offset .* contains 1 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
-[0-9a-f ]+R_PPC64_JMP_SLOT +0+ __tls_get_addr \+ 0
+[0-9a-f ]+R_PPC64_JMP_SLOT +0+ __tls_get_addr_opt \+ 0
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size Type +Bind +Vis +Ndx Name
 .* NOTYPE +LOCAL +DEFAULT +UND 
 .* TLS +GLOBAL DEFAULT +UND gd
-.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL DEFAULT +UND ld
 .* TLS +GLOBAL DEFAULT +9 ld2
 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt
 .* NOTYPE +GLOBAL DEFAULT +ABS _edata
 .* NOTYPE +GLOBAL DEFAULT +ABS _end
 
@@ -96,10 +96,9 @@ Symbol table '\.symtab' contains [0-9]+ 
 .* TLS +LOCAL +DEFAULT +8 le4
 .* TLS +LOCAL +DEFAULT +8 le5
 .* OBJECT +LOCAL +HIDDEN +10 _DYNAMIC
-.* FUNC +LOCAL +DEFAULT +UND \.__tls_get_addr
+.* (FUNC|NOTYPE) +LOCAL +DEFAULT +UND \.__tls_get_addr(|_opt)
 .* GLOBAL DEFAULT +UND gd
 .* GLOBAL DEFAULT +9 le0
-.* GLOBAL DEFAULT +UND __tls_get_addr
 .* GLOBAL DEFAULT +9 ld0
 .* GLOBAL DEFAULT +9 le1
 .* GLOBAL DEFAULT +UND ld
@@ -107,6 +106,7 @@ Symbol table '\.symtab' contains [0-9]+ 
 .* TLS +GLOBAL DEFAULT +9 ld2
 .* TLS +GLOBAL DEFAULT +9 ld1
 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+.* FUNC +GLOBAL +DEFAULT +UND __tls_get_addr_opt
 .* NOTYPE +GLOBAL DEFAULT +ABS _edata
 .* NOTYPE +GLOBAL DEFAULT +ABS _end
 .* TLS +GLOBAL DEFAULT +9 gd0
Index: ld/testsuite/ld-powerpc/tlsexe32.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexe32.d,v
retrieving revision 1.9
diff -u -p -r1.9 tlsexe32.d
--- ld/testsuite/ld-powerpc/tlsexe32.d	15 Aug 2005 15:39:47 -0000	1.9
+++ ld/testsuite/ld-powerpc/tlsexe32.d	20 Sep 2009 11:12:29 -0000
@@ -12,7 +12,7 @@ Disassembly of section \.text:
 .*:	80 7f ff f0 	lwz     r3,-16\(r31\)
 .*:	7c 63 12 14 	add     r3,r3,r2
 .*:	38 7f ff f4 	addi    r3,r31,-12
-.*:	48 01 01 85 	bl      .*<__tls_get_addr@plt>
+.*:	48 01 01 85 	bl      .*<__tls_get_addr_opt@plt>
 .*:	3c 62 00 00 	addis   r3,r2,0
 .*:	38 63 90 1c 	addi    r3,r3,-28644
 .*:	3c 62 00 00 	addis   r3,r2,0
@@ -44,4 +44,4 @@ Disassembly of section \.got:
 .*:	4e 80 00 21 	blrl
 
 .* <_GLOBAL_OFFSET_TABLE_>:
-.*:	01 81 02 b4 00 00 00 00 00 00 00 00  .*
+.*:	01 81 02 b8 00 00 00 00 00 00 00 00  .*
Index: ld/testsuite/ld-powerpc/tlsexe32.g
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexe32.g,v
retrieving revision 1.5
diff -u -p -r1.5 tlsexe32.g
--- ld/testsuite/ld-powerpc/tlsexe32.g	15 Aug 2005 15:39:47 -0000	1.5
+++ ld/testsuite/ld-powerpc/tlsexe32.g	20 Sep 2009 11:12:29 -0000
@@ -8,4 +8,4 @@
 
 Contents of section \.got:
 .* 00000000 00000000 00000000 4e800021  .*
-.* 018102b4 00000000 00000000           .*
+.* 018102b8 00000000 00000000           .*
Index: ld/testsuite/ld-powerpc/tlsexe32.r
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexe32.r,v
retrieving revision 1.15
diff -u -p -r1.15 tlsexe32.r
--- ld/testsuite/ld-powerpc/tlsexe32.r	30 Sep 2007 01:33:15 -0000	1.15
+++ ld/testsuite/ld-powerpc/tlsexe32.r	20 Sep 2009 11:12:29 -0000
@@ -57,16 +57,16 @@ Relocation section '\.rela\.dyn' at offs
 
 Relocation section '\.rela\.plt' at offset .* contains 1 entries:
  Offset +Info +Type +Sym\. Value +Symbol's Name \+ Addend
-[0-9a-f ]+R_PPC_JMP_SLOT[0-9a-f ]+__tls_get_addr \+ 0
+[0-9a-f ]+R_PPC_JMP_SLOT[0-9a-f ]+__tls_get_addr_opt \+ 0
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size Type +Bind +Vis +Ndx Name
 .* NOTYPE +LOCAL +DEFAULT +UND 
 .* TLS +GLOBAL DEFAULT +UND gd
-.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL DEFAULT +UND ld
 .* NOTYPE +GLOBAL DEFAULT +ABS __end
 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt
 .* NOTYPE +GLOBAL DEFAULT +ABS _edata
 .* NOTYPE +GLOBAL DEFAULT +ABS _end
 
@@ -96,7 +96,6 @@ Symbol table '\.symtab' contains [0-9]+ 
 .* OBJECT +LOCAL +HIDDEN +11 _GLOBAL_OFFSET_TABLE_
 .* TLS +GLOBAL DEFAULT +UND gd
 .* TLS +GLOBAL DEFAULT +9 le0
-.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL DEFAULT +9 ld0
 .* TLS +GLOBAL DEFAULT +9 le1
 .* TLS +GLOBAL DEFAULT +UND ld
@@ -105,6 +104,7 @@ Symbol table '\.symtab' contains [0-9]+ 
 .* TLS +GLOBAL DEFAULT +9 ld2
 .* TLS +GLOBAL DEFAULT +9 ld1
 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt
 .* NOTYPE +GLOBAL DEFAULT +ABS _edata
 .* NOTYPE +GLOBAL DEFAULT +ABS _end
 .* TLS +GLOBAL DEFAULT +9 gd0
Index: ld/testsuite/ld-powerpc/tlsexetoc.d
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexetoc.d,v
retrieving revision 1.8
diff -u -p -r1.8 tlsexetoc.d
--- ld/testsuite/ld-powerpc/tlsexetoc.d	13 Aug 2007 00:20:59 -0000	1.8
+++ ld/testsuite/ld-powerpc/tlsexetoc.d	20 Sep 2009 11:12:29 -0000
@@ -8,21 +8,34 @@
 
 Disassembly of section \.text:
 
-.* <_start-0x18>:
+.* <_start-0x4c>:
+.*	e9 63 00 00 	ld      r11,0\(r3\)
+.*	e9 83 00 08 	ld      r12,8\(r3\)
+.*	7c 60 1b 78 	mr      r0,r3
+.*	2c 2b 00 00 	cmpdi   r11,0
+.*	7c 6c 6a 14 	add     r3,r12,r13
+.*	4d 82 00 20 	beqlr   
+.*	7c 03 03 78 	mr      r3,r0
+.*	7d 68 02 a6 	mflr    r11
+.*	f9 61 00 20 	std     r11,32\(r1\)
 .*	f8 41 00 28 	std     r2,40\(r1\)
 .*	e9 62 80 70 	ld      r11,-32656\(r2\)
 .*	7d 69 03 a6 	mtctr   r11
 .*	e9 62 80 80 	ld      r11,-32640\(r2\)
 .*	e8 42 80 78 	ld      r2,-32648\(r2\)
-.*	4e 80 04 20 	bctr
+.*	4e 80 04 21 	bctrl
+.*	e9 61 00 20 	ld      r11,32\(r1\)
+.*	e8 41 00 28 	ld      r2,40\(r1\)
+.*	7d 68 03 a6 	mtlr    r11
+.*	4e 80 00 20 	blr
 
 .* <_start>:
 .*	38 62 80 08 	addi    r3,r2,-32760
-.*	4b ff ff e5 	bl      .*
-.*	e8 41 00 28 	ld      r2,40\(r1\)
+.*	4b ff ff b1 	bl      .*
+.*	60 00 00 00 	nop
 .*	38 62 80 18 	addi    r3,r2,-32744
-.*	4b ff ff d9 	bl      .*
-.*	e8 41 00 28 	ld      r2,40\(r1\)
+.*	4b ff ff a5 	bl      .*
+.*	60 00 00 00 	nop
 .*	3c 6d 00 00 	addis   r3,r13,0
 .*	60 00 00 00 	nop
 .*	38 63 90 38 	addi    r3,r3,-28616
@@ -39,8 +52,9 @@ Disassembly of section \.text:
 .*	89 4d 90 60 	lbz     r10,-28576\(r13\)
 .*	3d 2d 00 00 	addis   r9,r13,0
 .*	99 49 90 68 	stb     r10,-28568\(r9\)
+.*	60 00 00 00 	nop
 .*	00 00 00 00 .*
-.*	00 01 02 18 .*
+.*	00 01 02 28 .*
 .*	7d 88 02 a6 	mflr    r12
 .*	42 9f 00 05 	bcl-    20,4\*cr7\+so,.*
 .*	7d 68 02 a6 	mflr    r11
Index: ld/testsuite/ld-powerpc/tlsexetoc.g
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlsexetoc.g,v
retrieving revision 1.7
diff -u -p -r1.7 tlsexetoc.g
--- ld/testsuite/ld-powerpc/tlsexetoc.g	13 Aug 2007 00:20:59 -0000	1.7
+++ ld/testsuite/ld-powerpc/tlsexetoc.g	20 Sep 2009 11:12:29 -0000
@@ -7,7 +7,7 @@
 .*: +file format elf64-powerpc
 
 Contents of section \.got:
-.* 00000000 10018568 00000000 00000000  .*
+.* 00000000 100185b0 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.22
diff -u -p -r1.22 tlsexetoc.r
--- ld/testsuite/ld-powerpc/tlsexetoc.r	30 Sep 2007 01:33:15 -0000	1.22
+++ ld/testsuite/ld-powerpc/tlsexetoc.r	20 Sep 2009 11:12:29 -0000
@@ -16,10 +16,10 @@ Section Headers:
  +\[[ 0-9]+\] \.dynstr +.*
  +\[[ 0-9]+\] \.rela\.dyn +.*
  +\[[ 0-9]+\] \.rela\.plt +.*
- +\[[ 0-9]+\] \.text +PROGBITS .* 0+b8 0+ +AX +0 +0 +8
+ +\[[ 0-9]+\] \.text +PROGBITS .* 0+f0 0+ +AX +0 +0 +8
  +\[[ 0-9]+\] \.tdata +PROGBITS .* 0+38 0+ WAT +0 +0 +8
  +\[[ 0-9]+\] \.tbss +NOBITS .* 0+38 0+ WAT +0 +0 +8
- +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+150 10 +WA +4 +0 +8
+ +\[[ 0-9]+\] \.dynamic +DYNAMIC .* 0+160 10 +WA +4 +0 +8
  +\[[ 0-9]+\] \.branch_lt +PROGBITS .* 0+ 0+ +WA +0 +0 +8
  +\[[ 0-9]+\] \.got +PROGBITS .* 0+58 08 +WA +0 +0 +8
  +\[[ 0-9]+\] \.plt +.*
@@ -59,15 +59,15 @@ Relocation section '\.rela\.dyn' at offs
 
 Relocation section '\.rela\.plt' at offset .* contains 1 entries:
  +Offset +Info +Type +Symbol's Value +Symbol's Name \+ Addend
-[0-9a-f ]+R_PPC64_JMP_SLOT +0+ __tls_get_addr \+ 0
+[0-9a-f ]+R_PPC64_JMP_SLOT +0+ __tls_get_addr_opt \+ 0
 
 Symbol table '\.dynsym' contains [0-9]+ entries:
  +Num: +Value +Size Type +Bind +Vis +Ndx Name
 .* NOTYPE +LOCAL +DEFAULT +UND 
 .* TLS +GLOBAL DEFAULT +UND gd
-.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL DEFAULT +UND ld
 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt
 .* NOTYPE +GLOBAL DEFAULT +ABS _edata
 .* NOTYPE +GLOBAL DEFAULT +ABS _end
 
@@ -96,10 +96,9 @@ Symbol table '\.symtab' contains [0-9]+ 
 .* TLS +LOCAL +DEFAULT +8 le5
 .* NOTYPE +LOCAL +DEFAULT +12 \.Lie0
 .* OBJECT +LOCAL +HIDDEN +10 _DYNAMIC
-.* FUNC +LOCAL +DEFAULT +UND \.__tls_get_addr
+.* (FUNC|NOTYPE) +LOCAL +DEFAULT +UND \.__tls_get_addr(|_opt)
 .* TLS +GLOBAL DEFAULT +UND gd
 .* TLS +GLOBAL DEFAULT +9 le0
-.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr
 .* TLS +GLOBAL DEFAULT +9 ld0
 .* TLS +GLOBAL DEFAULT +9 le1
 .* TLS +GLOBAL DEFAULT +UND ld
@@ -107,6 +106,7 @@ Symbol table '\.symtab' contains [0-9]+ 
 .* TLS +GLOBAL DEFAULT +9 ld2
 .* TLS +GLOBAL DEFAULT +9 ld1
 .* NOTYPE +GLOBAL DEFAULT +ABS __bss_start
+.* FUNC +GLOBAL DEFAULT +UND __tls_get_addr_opt
 .* NOTYPE +GLOBAL DEFAULT +ABS _edata
 .* NOTYPE +GLOBAL DEFAULT +ABS _end
 .* TLS +GLOBAL DEFAULT +9 gd0
Index: ld/testsuite/ld-powerpc/tlslib.s
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlslib.s,v
retrieving revision 1.2
diff -u -p -r1.2 tlslib.s
--- ld/testsuite/ld-powerpc/tlslib.s	9 Feb 2003 04:37:04 -0000	1.2
+++ ld/testsuite/ld-powerpc/tlslib.s	20 Sep 2009 11:12:29 -0000
@@ -1,10 +1,12 @@
-	.global .__tls_get_addr,__tls_get_addr,gd,ld
-	.type .__tls_get_addr,@function
+	.global __tls_get_addr,__tls_get_addr_opt,gd,ld
+	.type __tls_get_addr,@function
+	.type __tls_get_addr_opt,@function
 
 	.section ".opd","aw",@progbits
 __tls_get_addr:
+__tls_get_addr_opt:
 	.align 3
-	.quad	.__tls_get_addr
+	.quad	.L.__tls_get_addr
 	.quad	.TOC.@tocbase
 	.quad	0
 
@@ -17,5 +19,6 @@ gd:	.space 8
 ld:	.long 0xc0ffee
 
 	.text
-.__tls_get_addr:
+.L.__tls_get_addr:
 	blr
+	.size __tls_get_addr,. - .L.__tls_get_addr
Index: ld/testsuite/ld-powerpc/tlslib32.s
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/tlslib32.s,v
retrieving revision 1.1
diff -u -p -r1.1 tlslib32.s
--- ld/testsuite/ld-powerpc/tlslib32.s	18 Feb 2003 06:11:32 -0000	1.1
+++ ld/testsuite/ld-powerpc/tlslib32.s	20 Sep 2009 11:12:29 -0000
@@ -1,5 +1,6 @@
-	.global __tls_get_addr,gd,ld
+	.global __tls_get_addr,__tls_get_addr_opt,gd,ld
 	.type __tls_get_addr,@function
+	.type __tls_get_addr_opt,@function
 
 	.section ".tbss","awT",@nobits
 	.align 2
@@ -11,4 +12,5 @@ ld:	.long 0xc0ffee
 
 	.text
 __tls_get_addr:
+__tls_get_addr_opt:
 	blr
Index: ld/testsuite/ld-powerpc/oldtlslib.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/oldtlslib.s
diff -N ld/testsuite/ld-powerpc/oldtlslib.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/oldtlslib.s	21 Sep 2009 00:52:55 -0000
@@ -0,0 +1,29 @@
+	.global __tls_get_addr,__tls_get_addr_opt,gd,ld
+	.global .__tls_get_addr,.__tls_get_addr_opt
+	.type .__tls_get_addr,@function
+	.type .__tls_get_addr_opt,@function
+
+	.section ".opd","aw",@progbits
+__tls_get_addr:
+__tls_get_addr_opt:
+	.align 3
+	.quad	.__tls_get_addr
+	.quad	.TOC.@tocbase
+	.quad	0
+	.size __tls_get_addr,24
+	.size __tls_get_addr_opt,24
+
+	.section ".tbss","awT",@nobits
+	.align 3
+gd:	.space 8
+
+	.section ".tdata","awT",@progbits
+	.align 2
+ld:	.long 0xc0ffee
+
+	.text
+.__tls_get_addr:
+.__tls_get_addr_opt:
+	blr
+	.size .__tls_get_addr,. - .__tls_get_addr
+	.size .__tls_get_addr_opt,. - .__tls_get_addr_opt

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list