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]

PowerPC TLS ABI


The current ppc32 and ppc64 TLS ABI's have a deficiency:  In an object
file there is no tie between the instruction used to set up the
argument for a __tls_get_addr call and the call instruction itself.
This means that the compiler must keep the instructions together,
which might not be ideal scheduling, as otherwise the linker can not
properly associate the instructions for tls optimization without
expensive code analysis.

One way to tie the instructions is to emit a new relocation on the
__tls_get_addr call, somehow specifying the arg instruction.  For
instance, the new reloc could specify the offset to the arg
instruction in its addend, or its addend could specify the index of
the reloc on the arg instruction.  Both of these ideas are quite
workable for the linker, but the relocations would be quite different
from the usual ones we find in ELF object files, and may prove
difficult for the assembler to produce.  Instead, if we mark the call
with a new relocation having the same symbol as the arg setup
instruction, that will allow the linker to find all the instructions
involved in a given symbol's global dynamic and local dynamic tls
sequences.  In fact if we use two different marker relocs then we can
partition the instructions into those used for global dynamic and
those used for local dynamic tls.  This is sufficient because every
occurrence of global dynamic code for a given symbol will be subject
to the same optimization, and likewise for local dynamic.  The linker
doesn't need to know exactly which sequence a given __tls_get_addr
call belong to, just that it belongs with a given symbol.

It would be possible to do this with one relocation on the call, but I
chose not to because of the number of new relocs this would require
for all the variations of ppc32 calls.  Instead, we keep the existing
call reloc referencing __tls_get_addr, and add one of two new marker
relocs at the same offset.  The new reloc is always emitted before the
branch REL24 reloc.


A typical ppc32 global dynamic call will now look like:

Assembler			Reloc			Sym+addend
 addi 3,31,x@got@tlsgd		R_PPC_GOT_TLSGD16	x
 bl __tls_get_addr(x@tlsgd)	R_PPC_TLSGD		x
				R_PPC_REL24		__tls_get_addr

Note the addition of "(x@tlsgd)" to the assembler syntax, and the
new relocation this string generates.

Other examples of call syntax for global dynamic

-fpic
 bl __tls_get_addr(x@tlsgd)@plt

-fPIC -msecure-plt
 bl __tls_get_addr+32768(x@tlsgd)@plt


A local dynamic call:

 addi 3,31,x1@got@tlsld		R_PPC_GOT_TLSLD16	x1
 bl __tls_get_addr(x1@tlsld)	R_PPC_TLSLD		x1
				R_PPC_REL24		__tls_get_addr


ppc64 global dynamic call using @got

 addi 3,2,x@got@tlsgd		R_PPC64_GOT_TLSGD16	x
 bl __tls_get_addr(x@tlsgd)	R_PPC64_TLSGD		x
				R_PPC64_REL24		__tls_get_addr
 nop


ppc64 global dynamic call using Power Open syntax

 addi 3,2,.LC0@toc		R_PPC64_TOC16		.toc + offset
 bl __tls_get_addr(.LC0@tlsgd)	R_PPC64_TLSGD		.toc + offset
				R_PPC64_REL24		__tls_get_addr
 nop
..
 .section .toc,"aw"
.LC0:
 .quad x@dtpmod			R_PPC64_DTPMOD64	x
 .quad x@dtprel			R_PPC64_DTPREL64	x


The new ppc64 local dynamic syntax similarly extends the old syntax.
The following patch implements binutils support for this change.
Comments welcome.


include/elf/
	* ppc.h (R_PPC_TLSGD, R_PPC_TLSLD): Add new relocs.
	* ppc64.h (R_PPC64_TLSGD, R_PPC64_TLSLD): Add new relocs.
bfd/
	* reloc.c (BFD_RELOC_PPC_TLSGD, BFD_RELOC_PPC_TLSLD): New.
	* section.c (struct bfd_section): Add has_tls_get_addr_call.
	(BFD_FAKE_SECTION): Init new flag.
	* ecoff.c (bfd_debug_section): Likewise.
	* bfd-in2.h: Regenerate.
	* libbfd.h: Regenerate.
	* elf32-ppc.c (ppc_elf_howto_raw): Add R_PPC_TLSGD and R_PPC_TLSLD.
	(ppc_elf_reloc_type_lookup): Handle new relocs.
	(ppc_elf_check_relocs): Set has_tls_get_addr_call on finding such
	without marker relocs.
	(ppc_elf_tls_optimize): Allow out-of-order __tls_get_addr relocs
	if section has no old-style calls.
	(ppc_elf_relocate_section): Set tls_mask for non-tls relocs too.
	Don't try to optimize new-style __tls_get_addr call when handling
	arg setup relocs.  Instead do so for R_PPC_TLSGD and R_PPC_TLSLD
	relocs.
	* elf64-ppc.c (ppc64_elf_howto_raw): Add R_PPC64_TLSGD, R_PPC64_TLSLD.
	(ppc64_elf_reloc_type_lookup): Handle new relocs.
	(ppc64_elf_check_relocs): Set has_tls_get_addr_call on finding such
	without marker relocs.
	(ppc64_elf_tls_optimize): Allow out-of-order __tls_get_addr relocs
	if section has no old-style calls.  Set toc_ref for new relocs as
	appropriate.
	(ppc64_elf_relocate_section): Set tls_mask for non-tls relocs too.
	Don't try to optimize new-style __tls_get_addr call when handling
	arg setup relocs.  Instead do so for R_PPC_TLSGD and R_PPC_TLSLD
	relocs.
gas/
	* config/tc-ppc.c (ppc_elf_suffix): Error if ppc32 tls got relocs
	have non-zero addend.
	(md_assemble): Parse args of __tls_get_addr calls.
	(md_apply_fix): Handle BFD_RELOC_PPC_TLSGD and BFD_RELOC_PPC_TLSLD.
ld/testsuite/
	* ld-powerpc/tlsmark.s, * ld-powerpc/tlsmark.d: New test.
	* ld-powerpc/tlsmark32.s, * ld-powerpc/tlsmark32.d: New test.
	* ld-powerpc/powerpc.exp: Run them.

Index: include/elf/ppc.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc.h,v
retrieving revision 1.22
diff -u -p -r1.22 ppc.h
--- include/elf/ppc.h	10 Oct 2008 20:55:36 -0000	1.22
+++ include/elf/ppc.h	20 Feb 2009 04:38:29 -0000
@@ -100,6 +100,8 @@ START_RELOC_NUMBERS (elf_ppc_reloc_type)
   RELOC_NUMBER (R_PPC_GOT_DTPREL16_LO,	 92)
   RELOC_NUMBER (R_PPC_GOT_DTPREL16_HI,	 93)
   RELOC_NUMBER (R_PPC_GOT_DTPREL16_HA,	 94)
+  RELOC_NUMBER (R_PPC_TLSGD,		 95)
+  RELOC_NUMBER (R_PPC_TLSLD,		 96)
 
 /* The remaining relocs are from the Embedded ELF ABI, and are not
    in the SVR4 ELF ABI.  */
Index: include/elf/ppc64.h
===================================================================
RCS file: /cvs/src/src/include/elf/ppc64.h,v
retrieving revision 1.4
diff -u -p -r1.4 ppc64.h
--- include/elf/ppc64.h	10 May 2005 10:21:10 -0000	1.4
+++ include/elf/ppc64.h	20 Feb 2009 04:38:29 -0000
@@ -136,6 +136,8 @@ START_RELOC_NUMBERS (elf_ppc64_reloc_typ
   RELOC_NUMBER (R_PPC64_DTPREL16_HIGHERA,  104)
   RELOC_NUMBER (R_PPC64_DTPREL16_HIGHEST,  105)
   RELOC_NUMBER (R_PPC64_DTPREL16_HIGHESTA, 106)
+  RELOC_NUMBER (R_PPC64_TLSGD,		   107)
+  RELOC_NUMBER (R_PPC64_TLSLD,		   108)
 
   /* These are GNU extensions to enable C++ vtable garbage collection.  */
   RELOC_NUMBER (R_PPC64_GNU_VTINHERIT,	   253)
Index: bfd/ecoff.c
===================================================================
RCS file: /cvs/src/src/bfd/ecoff.c,v
retrieving revision 1.62
diff -u -p -r1.62 ecoff.c
--- bfd/ecoff.c	18 Feb 2009 18:23:06 -0000	1.62
+++ bfd/ecoff.c	20 Feb 2009 04:38:01 -0000
@@ -1,6 +1,7 @@
 /* Generic ECOFF (Extended-COFF) routines.
    Copyright 1990, 1991, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Original version by Per Bothner.
    Full support added by Ian Lance Taylor, ian@cygnus.com.
 
@@ -59,10 +60,10 @@ static asection bfd_debug_section =
      0,           0,                1,
   /* segment_mark, sec_info_type, use_rela_p, has_tls_reloc,       */
      0,            0,             0,          0,
-  /* has_gp_reloc, need_finalize_relax, reloc_done,                */
-     0,            0,                   0,
-  /* vma, lma, size, rawsize,                                      */
-     0,   0,   0,    0,
+  /* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax,     */
+     0,                     0,            0,
+  /* reloc_done, vma, lma, size, rawsize,                          */
+     0,          0,   0,   0,    0,
   /* output_offset, output_section, alignment_power,               */
      0,             NULL,           0,
   /* relocation, orelocation, reloc_count, filepos, rel_filepos,   */
Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.251
diff -u -p -r1.251 elf32-ppc.c
--- bfd/elf32-ppc.c	15 Feb 2009 12:14:14 -0000	1.251
+++ bfd/elf32-ppc.c	20 Feb 2009 04:38:02 -0000
@@ -753,7 +753,7 @@ static reloc_howto_type ppc_elf_howto_ra
 	 0xffff,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC_TLS,
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -768,6 +768,34 @@ static reloc_howto_type ppc_elf_howto_ra
 	 0,			/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  HOWTO (R_PPC_TLSGD,
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_PPC_TLSGD",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_PPC_TLSLD,
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc, /* special_function */
+	 "R_PPC_TLSLD",		/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC_DTPMOD32,
@@ -1531,6 +1559,8 @@ ppc_elf_reloc_type_lookup (bfd *abfd ATT
     case BFD_RELOC_CTOR:		r = R_PPC_ADDR32;		break;
     case BFD_RELOC_PPC_TOC16:		r = R_PPC_TOC16;		break;
     case BFD_RELOC_PPC_TLS:		r = R_PPC_TLS;			break;
+    case BFD_RELOC_PPC_TLSGD:		r = R_PPC_TLSGD;		break;
+    case BFD_RELOC_PPC_TLSLD:		r = R_PPC_TLSLD;		break;
     case BFD_RELOC_PPC_DTPMOD:		r = R_PPC_DTPMOD32;		break;
     case BFD_RELOC_PPC_TPREL16:		r = R_PPC_TPREL16;		break;
     case BFD_RELOC_PPC_TPREL16_LO:	r = R_PPC_TPREL16_LO;		break;
@@ -3288,6 +3318,7 @@ ppc_elf_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rel;
   const Elf_Internal_Rela *rel_end;
   asection *got2, *sreloc;
+  struct elf_link_hash_entry *tga;
 
   if (info->relocatable)
     return TRUE;
@@ -3313,6 +3344,8 @@ ppc_elf_check_relocs (bfd *abfd,
     ppc_elf_howto_init ();
 
   htab = ppc_elf_hash_table (info);
+  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+			      FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
   sym_hashes = elf_sym_hashes (abfd);
   got2 = bfd_get_section_by_name (abfd, ".got2");
@@ -3324,7 +3357,7 @@ ppc_elf_check_relocs (bfd *abfd,
       unsigned long r_symndx;
       enum elf_ppc_reloc_type r_type;
       struct elf_link_hash_entry *h;
-      int tls_type = 0;
+      int tls_type;
 
       r_symndx = ELF32_R_SYM (rel->r_info);
       if (r_symndx < symtab_hdr->sh_info)
@@ -3351,9 +3384,44 @@ ppc_elf_check_relocs (bfd *abfd,
 	  BFD_ASSERT (h == htab->elf.hgot);
 	}
 
+      tls_type = 0;
       r_type = ELF32_R_TYPE (rel->r_info);
+      if (h != NULL && h == tga)
+	switch (r_type)
+	  {
+	  default:
+	    break;
+
+	  case R_PPC_PLTREL24:
+	  case R_PPC_LOCAL24PC:
+	  case R_PPC_REL24:
+	  case R_PPC_REL14:
+	  case R_PPC_REL14_BRTAKEN:
+	  case R_PPC_REL14_BRNTAKEN:
+	  case R_PPC_ADDR24:
+	  case R_PPC_ADDR14:
+	  case R_PPC_ADDR14_BRTAKEN:
+	  case R_PPC_ADDR14_BRNTAKEN:
+	    if (rel != relocs
+		&& (ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSGD
+		    || ELF32_R_TYPE (rel[-1].r_info) == R_PPC_TLSLD))
+	      /* We have a new-style __tls_get_addr call with a marker
+		 reloc.  */
+	      ;
+	    else
+	      /* Mark this section as having an old-style call.  */
+	      sec->has_tls_get_addr_call = 1;
+	    break;
+	  }
+
       switch (r_type)
 	{
+	case R_PPC_TLSGD:
+	case R_PPC_TLSLD:
+	  /* These special tls relocs tie a call to __tls_get_addr with
+	     its parameter symbol.  */
+	  break;
+
 	case R_PPC_GOT_TLSLD16:
 	case R_PPC_GOT_TLSLD16_LO:
 	case R_PPC_GOT_TLSLD16_HI:
@@ -3607,7 +3675,7 @@ ppc_elf_check_relocs (bfd *abfd,
 
 	  /* This refers only to functions defined in the shared library.  */
 	case R_PPC_LOCAL24PC:
-	  if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
+	  if (h != NULL && h == htab->elf.hgot && htab->plt_type == PLT_UNSET)
 	    {
 	      htab->plt_type = PLT_OLD;
 	      htab->old_bfd = abfd;
@@ -4484,7 +4552,8 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
 
 		  if (pass == 0)
 		    {
-		      if (!expecting_tls_get_addr)
+		      if (!expecting_tls_get_addr
+			  || !sec->has_tls_get_addr_call)
 			continue;
 
 		      if (rel + 1 < relend
@@ -6234,16 +6303,13 @@ ppc_elf_relocate_section (bfd *output_bf
 	 for the final instruction stream.  */
       tls_mask = 0;
       tls_gd = 0;
-      if (IS_PPC_TLS_RELOC (r_type))
-	{
-	  if (h != NULL)
-	    tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
-	  else if (local_got_offsets != NULL)
-	    {
-	      char *lgot_masks;
-	      lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
-	      tls_mask = lgot_masks[r_symndx];
-	    }
+      if (h != NULL)
+	tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask;
+      else if (local_got_offsets != NULL)
+	{
+	  char *lgot_masks;
+	  lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info);
+	  tls_mask = lgot_masks[r_symndx];
 	}
 
       /* Ensure reloc mapping code below stays sane.  */
@@ -6361,7 +6427,17 @@ ppc_elf_relocate_section (bfd *output_bf
 	      bfd_vma offset;
 
 	    tls_ldgd_opt:
-	      offset = rel[1].r_offset;
+	      offset = (bfd_vma) -1;
+	      /* If not using the newer R_PPC_TLSGD/LD to mark
+		 __tls_get_addr calls, we must trust that the call
+		 stays with its arg setup insns, ie. that the next
+		 reloc is the __tls_get_addr call associated with
+		 the current reloc.  Edit both insns.  */
+	      if (input_section->has_tls_get_addr_call
+		  && rel + 1 < relend
+		  && branch_reloc_hash_match (input_bfd, rel + 1,
+					      htab->tls_get_addr))
+		offset = rel[1].r_offset;
 	      if ((tls_mask & tls_gd) != 0)
 		{
 		  /* IE */
@@ -6369,9 +6445,14 @@ ppc_elf_relocate_section (bfd *output_bf
 				      contents + rel->r_offset - d_offset);
 		  insn1 &= (1 << 26) - 1;
 		  insn1 |= 32 << 26;	/* lwz */
-		  insn2 = 0x7c631214;	/* add 3,3,2 */
-		  rel[1].r_info
-		    = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info), R_PPC_NONE);
+		  if (offset != (bfd_vma) -1)
+		    {
+		      rel[1].r_info
+			= ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+					R_PPC_NONE);
+		      insn2 = 0x7c631214;	/* add 3,3,2 */
+		      bfd_put_32 (output_bfd, insn2, contents + offset);
+		    }
 		  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
 			    + R_PPC_GOT_TPREL16);
 		  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
@@ -6380,7 +6461,6 @@ ppc_elf_relocate_section (bfd *output_bf
 		{
 		  /* LE */
 		  insn1 = 0x3c620000;	/* addis 3,2,0 */
-		  insn2 = 0x38630000;	/* addi 3,3,0 */
 		  if (tls_gd == 0)
 		    {
 		      /* Was an LD reloc.  */
@@ -6399,14 +6479,17 @@ ppc_elf_relocate_section (bfd *output_bf
 		    }
 		  r_type = R_PPC_TPREL16_HA;
 		  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
-		  rel[1].r_info = ELF32_R_INFO (r_symndx,
-						R_PPC_TPREL16_LO);
-		  rel[1].r_offset += d_offset;
-		  rel[1].r_addend = rel->r_addend;
+		  if (offset != (bfd_vma) -1)
+		    {
+		      rel[1].r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
+		      rel[1].r_offset = offset + d_offset;
+		      rel[1].r_addend = rel->r_addend;
+		      insn2 = 0x38630000;	/* addi 3,3,0 */
+		      bfd_put_32 (output_bfd, insn2, contents + 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)
 		{
 		  /* We changed the symbol on an LD reloc.  Start over
@@ -6416,6 +6499,66 @@ ppc_elf_relocate_section (bfd *output_bf
 		}
 	    }
 	  break;
+
+	case R_PPC_TLSGD:
+	  if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+	    {
+	      unsigned int insn2;
+	      bfd_vma offset = rel->r_offset;
+
+	      if ((tls_mask & TLS_TPRELGD) != 0)
+		{
+		  /* IE */
+		  r_type = R_PPC_NONE;
+		  insn2 = 0x7c631214;	/* add 3,3,2 */
+		}
+	      else
+		{
+		  /* LE */
+		  r_type = R_PPC_TPREL16_LO;
+		  rel->r_offset += d_offset;
+		  insn2 = 0x38630000;	/* addi 3,3,0 */
+		}
+	      rel->r_info = ELF32_R_INFO (r_symndx, r_type);
+	      bfd_put_32 (output_bfd, insn2, contents + offset);
+	      /* Zap the reloc on the _tls_get_addr call too.  */
+	      BFD_ASSERT (offset == rel[1].r_offset);
+	      rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+					    R_PPC_NONE);
+	    }
+	  break;
+
+	case R_PPC_TLSLD:
+	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+	    {
+	      unsigned int insn2;
+
+	      for (r_symndx = 0;
+		   r_symndx < symtab_hdr->sh_info;
+		   r_symndx++)
+		if (local_sections[r_symndx] == sec)
+		  break;
+	      if (r_symndx >= symtab_hdr->sh_info)
+		r_symndx = 0;
+	      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+	      if (r_symndx != 0)
+		rel->r_addend -= (local_syms[r_symndx].st_value
+				  + sec->output_offset
+				  + sec->output_section->vma);
+
+	      rel->r_info = ELF32_R_INFO (r_symndx, R_PPC_TPREL16_LO);
+	      rel->r_offset += d_offset;
+	      insn2 = 0x38630000;	/* addi 3,3,0 */
+	      bfd_put_32 (output_bfd, insn2,
+			  contents + rel->r_offset - d_offset);
+	      /* Zap the reloc on the _tls_get_addr call too.  */
+	      BFD_ASSERT (rel->r_offset - d_offset == rel[1].r_offset);
+	      rel[1].r_info = ELF32_R_INFO (ELF32_R_SYM (rel[1].r_info),
+					    R_PPC_NONE);
+	      rel--;
+	      continue;
+	    }
+	  break;
 	}
 
       /* Handle other relocations that tweak non-addend part of insn.  */
@@ -6509,6 +6652,7 @@ ppc_elf_relocate_section (bfd *output_bf
 	case R_PPC_GOT16_LO:
 	case R_PPC_GOT16_HI:
 	case R_PPC_GOT16_HA:
+	  tls_mask = 0;
 	dogot:
 	  {
 	    /* Relocation is to the entry for this symbol in the global
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.291
diff -u -p -r1.291 elf64-ppc.c
--- bfd/elf64-ppc.c	15 Feb 2009 12:14:14 -0000	1.291
+++ bfd/elf64-ppc.c	20 Feb 2009 04:38:08 -0000
@@ -1235,7 +1235,7 @@ static reloc_howto_type ppc64_elf_howto_
 	 0xfffc,		/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
-  /* Marker reloc for TLS.  */
+  /* Marker relocs for TLS.  */
   HOWTO (R_PPC64_TLS,
 	 0,			/* rightshift */
 	 2,			/* size (0 = byte, 1 = short, 2 = long) */
@@ -1250,6 +1250,34 @@ static reloc_howto_type ppc64_elf_howto_
 	 0,			/* dst_mask */
 	 FALSE),		/* pcrel_offset */
 
+  HOWTO (R_PPC64_TLSGD,
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC64_TLSGD",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
+  HOWTO (R_PPC64_TLSLD,
+	 0,			/* rightshift */
+	 2,			/* size (0 = byte, 1 = short, 2 = long) */
+	 32,			/* bitsize */
+	 FALSE,			/* pc_relative */
+	 0,			/* bitpos */
+	 complain_overflow_dont, /* complain_on_overflow */
+	 bfd_elf_generic_reloc,	/* special_function */
+	 "R_PPC64_TLSLD",	/* name */
+	 FALSE,			/* partial_inplace */
+	 0,			/* src_mask */
+	 0,			/* dst_mask */
+	 FALSE),		/* pcrel_offset */
+
   /* Computes the load module index of the load module that contains the
      definition of its TLS sym.  */
   HOWTO (R_PPC64_DTPMOD64,
@@ -2031,6 +2059,10 @@ ppc64_elf_reloc_type_lookup (bfd *abfd A
       break;
     case BFD_RELOC_PPC_TLS:			r = R_PPC64_TLS;
       break;
+    case BFD_RELOC_PPC_TLSGD:			r = R_PPC64_TLSGD;
+      break;
+    case BFD_RELOC_PPC_TLSLD:			r = R_PPC64_TLSLD;
+      break;
     case BFD_RELOC_PPC_DTPMOD:			r = R_PPC64_DTPMOD64;
       break;
     case BFD_RELOC_PPC_TPREL16:			r = R_PPC64_TPREL16;
@@ -4644,7 +4676,7 @@ ppc64_elf_check_relocs (bfd *abfd, struc
       unsigned long r_symndx;
       struct elf_link_hash_entry *h;
       enum elf_ppc64_reloc_type r_type;
-      int tls_type = 0;
+      int tls_type;
       struct _ppc64_elf_section_data *ppc64_sec;
 
       r_symndx = ELF64_R_SYM (rel->r_info);
@@ -4658,9 +4690,42 @@ ppc64_elf_check_relocs (bfd *abfd, struc
 	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
 	}
 
+      tls_type = 0;
       r_type = ELF64_R_TYPE (rel->r_info);
+      if (h != NULL && (h == tga || h == dottga))
+	switch (r_type)
+	  {
+	  default:
+	    break;
+
+	  case R_PPC64_REL24:
+	  case R_PPC64_REL14:
+	  case R_PPC64_REL14_BRTAKEN:
+	  case R_PPC64_REL14_BRNTAKEN:
+	  case R_PPC64_ADDR24:
+	  case R_PPC64_ADDR14:
+	  case R_PPC64_ADDR14_BRTAKEN:
+	  case R_PPC64_ADDR14_BRNTAKEN:
+	    if (rel != relocs
+		&& (ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSGD
+		    || ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_TLSLD))
+	      /* We have a new-style __tls_get_addr call with a marker
+		 reloc.  */
+	      ;
+	    else
+	      /* Mark this section as having an old-style call.  */
+	      sec->has_tls_get_addr_call = 1;
+	    break;
+	  }
+
       switch (r_type)
 	{
+	case R_PPC64_TLSGD:
+	case R_PPC64_TLSLD:
+	  /* These special tls relocs tie a call to __tls_get_addr with
+	     its parameter symbol.  */
+	  break;
+
 	case R_PPC64_GOT_TLSLD16:
 	case R_PPC64_GOT_TLSLD16_LO:
 	case R_PPC64_GOT_TLSLD16_HI:
@@ -7072,6 +7137,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
 		    case R_PPC64_TOC16:
 		    case R_PPC64_TOC16_LO:
 		    case R_PPC64_TLS:
+		    case R_PPC64_TLSGD:
+		    case R_PPC64_TLSLD:
 		      if (sym_sec == NULL || sym_sec != toc)
 			continue;
 
@@ -7092,7 +7159,9 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
 		      value += rel->r_addend;
 		      BFD_ASSERT (value < toc->size && value % 8 == 0);
 		      toc_ref_index = value / 8;
-		      if (r_type == R_PPC64_TLS)
+		      if (r_type == R_PPC64_TLS
+			  || r_type == R_PPC64_TLSGD
+			  || r_type == R_PPC64_TLSLD)
 			{
 			  toc_ref[toc_ref_index] = 1;
 			  continue;
@@ -7157,7 +7226,8 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
 
 		  if (pass == 0)
 		    {
-		      if (!expecting_tls_get_addr)
+		      if (!expecting_tls_get_addr
+			  || !sec->has_tls_get_addr_call)
 			continue;
 
 		      if (rel + 1 < relend
@@ -7276,18 +7346,18 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
 		free (relstart);
 	    }
 
-	if (toc_ref != NULL)
-	  free (toc_ref);
+      if (toc_ref != NULL)
+	free (toc_ref);
 
-	if (locsyms != NULL
-	    && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
-	  {
-	    if (!info->keep_memory)
-	      free (locsyms);
-	    else
-	      elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
-	  }
-      }
+      if (locsyms != NULL
+	  && (elf_symtab_hdr (ibfd).contents != (unsigned char *) locsyms))
+	{
+	  if (!info->keep_memory)
+	    free (locsyms);
+	  else
+	    elf_symtab_hdr (ibfd).contents = (unsigned char *) locsyms;
+	}
+    }
   return TRUE;
 }
 
@@ -10288,28 +10358,28 @@ ppc64_elf_relocate_section (bfd *output_
       tls_mask = 0;
       tls_gd = 0;
       toc_symndx = 0;
-      if (IS_PPC64_TLS_RELOC (r_type))
+      if (h != NULL)
+	tls_mask = h->tls_mask;
+      else if (local_got_ents != NULL)
 	{
-	  if (h != NULL)
-	    tls_mask = h->tls_mask;
-	  else if (local_got_ents != NULL)
-	    {
-	      char *lgot_masks;
-	      lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
-	      tls_mask = lgot_masks[r_symndx];
-	    }
-	  if (tls_mask == 0 && r_type == R_PPC64_TLS)
-	    {
-	      /* Check for toc tls entries.  */
-	      char *toc_tls;
+	  char *lgot_masks;
+	  lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info);
+	  tls_mask = lgot_masks[r_symndx];
+	}
+      if (tls_mask == 0
+	  && (r_type == R_PPC64_TLS
+	      || r_type == R_PPC64_TLSGD
+	      || r_type == R_PPC64_TLSLD))
+	{
+	  /* Check for toc tls entries.  */
+	  char *toc_tls;
 
-	      if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
-				 &local_syms, rel, input_bfd))
-		return FALSE;
+	  if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+			     &local_syms, rel, input_bfd))
+	    return FALSE;
 
-	      if (toc_tls)
-		tls_mask = *toc_tls;
-	    }
+	  if (toc_tls)
+	    tls_mask = *toc_tls;
 	}
 
       /* Check that tls relocs are used with tls syms, and non-tls
@@ -10324,7 +10394,10 @@ ppc64_elf_relocate_section (bfd *output_
 		  || (sym_type == STT_SECTION
 		      && (sec->flags & SEC_THREAD_LOCAL) != 0))))
 	{
-	  if (r_type == R_PPC64_TLS && tls_mask != 0)
+	  if (tls_mask != 0
+	      && (r_type == R_PPC64_TLS
+		  || r_type == R_PPC64_TLSGD
+		  || r_type == R_PPC64_TLSLD))
 	    /* R_PPC64_TLS is OK against a symbol in the TOC.  */
 	    ;
 	  else
@@ -10520,9 +10593,18 @@ ppc64_elf_relocate_section (bfd *output_
 	      bfd_vma offset;
 
 	    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;
+	      offset = (bfd_vma) -1;
+	      /* If not using the newer R_PPC64_TLSGD/LD to mark
+		 __tls_get_addr calls, we must trust that the call
+		 stays with its arg setup insns, ie. that the next
+		 reloc is the __tls_get_addr call associated with
+		 the current reloc.  Edit both insns.  */
+	      if (input_section->has_tls_get_addr_call
+		  && rel + 1 < relend
+		  && branch_reloc_hash_match (input_bfd, rel + 1,
+					      htab->tls_get_addr,
+					      htab->tls_get_addr_fd))
+		offset = rel[1].r_offset;
 	      if ((tls_mask & tls_gd) != 0)
 		{
 		  /* IE */
@@ -10531,8 +10613,9 @@ 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 (ELF64_R_SYM (rel[1].r_info),
-						R_PPC64_NONE);
+		  if (offset != (bfd_vma) -1)
+		    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);
@@ -10570,34 +10653,131 @@ ppc64_elf_relocate_section (bfd *output_
 		    }
 		  r_type = R_PPC64_TPREL16_HA;
 		  rel->r_info = ELF64_R_INFO (r_symndx, r_type);
-		  rel[1].r_info = ELF64_R_INFO (r_symndx,
-						R_PPC64_TPREL16_LO);
-		  rel[1].r_offset += d_offset;
-		  rel[1].r_addend = rel->r_addend;
+		  if (offset != (bfd_vma) -1)
+		    {
+		      rel[1].r_info = ELF64_R_INFO (r_symndx,
+						    R_PPC64_TPREL16_LO);
+		      rel[1].r_offset = offset + d_offset;
+		      rel[1].r_addend = rel->r_addend;
+		    }
 		}
 	      bfd_put_32 (output_bfd, insn1,
 			  contents + rel->r_offset - d_offset);
+	      if (offset != (bfd_vma) -1)
+		{
+		  insn3 = bfd_get_32 (output_bfd,
+				      contents + offset + 4);
+		  if (insn3 == NOP
+		      || insn3 == CROR_151515 || insn3 == CROR_313131)
+		    {
+		      rel[1].r_offset += 4;
+		      bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+		      insn2 = NOP;
+		    }
+		  bfd_put_32 (output_bfd, insn2, contents + offset);
+		}
+	      if ((tls_mask & tls_gd) == 0
+		  && (tls_gd == 0 || toc_symndx != 0))
+		{
+		  /* We changed the symbol.  Start over in order
+		     to get h, sym, sec etc. right.  */
+		  rel--;
+		  continue;
+		}
+	    }
+	  break;
+
+	case R_PPC64_TLSGD:
+	  if (tls_mask != 0 && (tls_mask & TLS_GD) == 0)
+	    {
+	      unsigned int insn2, insn3;
+	      bfd_vma offset = rel->r_offset;
+
+	      if ((tls_mask & TLS_TPRELGD) != 0)
+		{
+		  /* IE */
+		  r_type = R_PPC64_NONE;
+		  insn2 = 0x7c636a14;	/* add 3,3,13 */
+		}
+	      else
+		{
+		  /* LE */
+		  if (toc_symndx != 0)
+		    {
+		      r_symndx = toc_symndx;
+		      rel->r_addend = toc_addend;
+		    }
+		  r_type = R_PPC64_TPREL16_LO;
+		  rel->r_offset = offset + d_offset;
+		  insn2 = 0x38630000;	/* addi 3,3,0 */
+		}
+	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      /* Zap the reloc on the _tls_get_addr call too.  */
+	      BFD_ASSERT (offset == rel[1].r_offset);
+	      rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+					    R_PPC64_NONE);
 	      insn3 = bfd_get_32 (output_bfd,
 				  contents + offset + 4);
 	      if (insn3 == NOP
 		  || insn3 == CROR_151515 || insn3 == CROR_313131)
 		{
-		  rel[1].r_offset += 4;
+		  rel->r_offset += 4;
 		  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
 		  insn2 = NOP;
 		}
 	      bfd_put_32 (output_bfd, insn2, contents + offset);
-	      if ((tls_mask & tls_gd) == 0
-		  && (tls_gd == 0 || toc_symndx != 0))
+	      if ((tls_mask & TLS_TPRELGD) == 0 && toc_symndx != 0)
 		{
-		  /* We changed the symbol.  Start over in order
-		     to get h, sym, sec etc. right.  */
 		  rel--;
 		  continue;
 		}
 	    }
 	  break;
 
+	case R_PPC64_TLSLD:
+	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
+	    {
+	      unsigned int insn2, insn3;
+	      bfd_vma offset = rel->r_offset;
+
+	      if (toc_symndx)
+		sec = local_sections[toc_symndx];
+	      for (r_symndx = 0;
+		   r_symndx < symtab_hdr->sh_info;
+		   r_symndx++)
+		if (local_sections[r_symndx] == sec)
+		  break;
+	      if (r_symndx >= symtab_hdr->sh_info)
+		r_symndx = 0;
+	      rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET;
+	      if (r_symndx != 0)
+		rel->r_addend -= (local_syms[r_symndx].st_value
+				  + sec->output_offset
+				  + sec->output_section->vma);
+
+	      r_type = R_PPC64_TPREL16_LO;
+	      rel->r_info = ELF64_R_INFO (r_symndx, r_type);
+	      rel->r_offset = offset + d_offset;
+	      /* Zap the reloc on the _tls_get_addr call too.  */
+	      BFD_ASSERT (offset == rel[1].r_offset);
+	      rel[1].r_info = ELF64_R_INFO (ELF64_R_SYM (rel[1].r_info),
+					    R_PPC64_NONE);
+	      insn2 = 0x38630000;	/* addi 3,3,0 */
+	      insn3 = bfd_get_32 (output_bfd,
+				  contents + offset + 4);
+	      if (insn3 == NOP
+		  || insn3 == CROR_151515 || insn3 == CROR_313131)
+		{
+		  rel->r_offset += 4;
+		  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+		  insn2 = NOP;
+		}
+	      bfd_put_32 (output_bfd, insn2, contents + offset);
+	      rel--;
+	      continue;
+	    }
+	  break;
+
 	case R_PPC64_DTPMOD64:
 	  if (rel + 1 < relend
 	      && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)
@@ -10851,6 +11031,8 @@ ppc64_elf_relocate_section (bfd *output_
 
 	case R_PPC64_NONE:
 	case R_PPC64_TLS:
+	case R_PPC64_TLSGD:
+	case R_PPC64_TLSLD:
 	case R_PPC64_GNU_VTINHERIT:
 	case R_PPC64_GNU_VTENTRY:
 	  continue;
Index: bfd/reloc.c
===================================================================
RCS file: /cvs/src/src/bfd/reloc.c,v
retrieving revision 1.182
diff -u -p -r1.182 reloc.c
--- bfd/reloc.c	3 Feb 2009 14:36:46 -0000	1.182
+++ bfd/reloc.c	20 Feb 2009 04:38:10 -0000
@@ -2687,6 +2687,10 @@ ENUMDOC
 ENUM
   BFD_RELOC_PPC_TLS
 ENUMX
+  BFD_RELOC_PPC_TLSGD
+ENUMX
+  BFD_RELOC_PPC_TLSLD
+ENUMX
   BFD_RELOC_PPC_DTPMOD
 ENUMX
   BFD_RELOC_PPC_TPREL16
Index: bfd/section.c
===================================================================
RCS file: /cvs/src/src/bfd/section.c,v
retrieving revision 1.99
diff -u -p -r1.99 section.c
--- bfd/section.c	15 Feb 2008 10:35:46 -0000	1.99
+++ bfd/section.c	20 Feb 2009 04:38:11 -0000
@@ -1,6 +1,6 @@
 /* Object file "section" support for the BFD library.
    Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    Free Software Foundation, Inc.
    Written by Cygnus Support.
 
@@ -382,6 +382,9 @@ CODE_FRAGMENT
 .  {* Nonzero if this section has TLS related relocations.  *}
 .  unsigned int has_tls_reloc:1;
 .
+.  {* Nonzero if this section has a call to __tls_get_addr.  *}
+.  unsigned int has_tls_get_addr_call:1;
+.
 .  {* Nonzero if this section has a gp reloc.  *}
 .  unsigned int has_gp_reloc:1;
 .
@@ -642,11 +645,11 @@ CODE_FRAGMENT
 .  {* segment_mark, sec_info_type, use_rela_p, has_tls_reloc,       *}	\
 .     0,            0,             0,          0,			\
 .									\
-.  {* has_gp_reloc, need_finalize_relax, reloc_done,                *}	\
-.     0,            0,                   0,				\
+.  {* has_tls_get_addr_call, has_gp_reloc, need_finalize_relax,     *}	\
+.     0,                     0,            0,				\
 .									\
-.  {* vma, lma, size, rawsize                                       *}	\
-.     0,   0,   0,    0,						\
+.  {* reloc_done, vma, lma, size, rawsize                           *}	\
+.     0,          0,   0,   0,    0,					\
 .									\
 .  {* output_offset, output_section,              alignment_power,  *}	\
 .     0,             (struct bfd_section *) &SEC, 0,			\
Index: gas/config/tc-ppc.c
===================================================================
RCS file: /cvs/src/src/gas/config/tc-ppc.c,v
retrieving revision 1.146
diff -u -p -w -r1.146 tc-ppc.c
--- gas/config/tc-ppc.c	10 Feb 2009 08:07:31 -0000	1.146
+++ gas/config/tc-ppc.c	20 Feb 2009 04:46:24 -0000
@@ -1777,13 +1777,38 @@ ppc_elf_suffix (char **str_p, expression
       {
 	int reloc = ptr->reloc;
 
-	if (!ppc_obj64)
-	  if (exp_p->X_add_number != 0
-	      && (reloc == (int) BFD_RELOC_16_GOTOFF
-		  || reloc == (int) BFD_RELOC_LO16_GOTOFF
-		  || reloc == (int) BFD_RELOC_HI16_GOTOFF
-		  || reloc == (int) BFD_RELOC_HI16_S_GOTOFF))
-	    as_warn (_("identifier+constant@got means identifier@got+constant"));
+	if (!ppc_obj64 && exp_p->X_add_number != 0)
+	  {
+	    switch (reloc)
+	      {
+	      case BFD_RELOC_16_GOTOFF:
+	      case BFD_RELOC_LO16_GOTOFF:
+	      case BFD_RELOC_HI16_GOTOFF:
+	      case BFD_RELOC_HI16_S_GOTOFF:
+		as_warn (_("identifier+constant@got means "
+			   "identifier@got+constant"));
+		break;
+
+	      case BFD_RELOC_PPC_GOT_TLSGD16:
+	      case BFD_RELOC_PPC_GOT_TLSGD16_LO:
+	      case BFD_RELOC_PPC_GOT_TLSGD16_HI:
+	      case BFD_RELOC_PPC_GOT_TLSGD16_HA:
+	      case BFD_RELOC_PPC_GOT_TLSLD16:
+	      case BFD_RELOC_PPC_GOT_TLSLD16_LO:
+	      case BFD_RELOC_PPC_GOT_TLSLD16_HI:
+	      case BFD_RELOC_PPC_GOT_TLSLD16_HA:
+	      case BFD_RELOC_PPC_GOT_DTPREL16:
+	      case BFD_RELOC_PPC_GOT_DTPREL16_LO:
+	      case BFD_RELOC_PPC_GOT_DTPREL16_HI:
+	      case BFD_RELOC_PPC_GOT_DTPREL16_HA:
+	      case BFD_RELOC_PPC_GOT_TPREL16:
+	      case BFD_RELOC_PPC_GOT_TPREL16_LO:
+	      case BFD_RELOC_PPC_GOT_TPREL16_HI:
+	      case BFD_RELOC_PPC_GOT_TPREL16_HA:
+		as_bad (_("symbol+offset not supported for got tls"));
+		break;
+	      }
+	  }
 
 	/* Now check for identifier@suffix+constant.  */
 	if (*str == '-' || *str == '+')
@@ -2600,17 +2625,64 @@ md_assemble (char *str)
 				     ppc_cpu, (char *) NULL, 0);
 	}
 #ifdef OBJ_ELF
-      else if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
+      else
+	{
+	  if (ex.X_op == O_symbol && str[0] == '(')
+	    {
+	      const char *sym_name = S_GET_NAME (ex.X_add_symbol);
+	      if (sym_name[0] == '.')
+		++sym_name;
+
+	      if (strcasecmp (sym_name, "__tls_get_addr") == 0)
+		{
+		  expressionS tls_exp;
+
+		  hold = input_line_pointer;
+		  input_line_pointer = str + 1;
+		  expression (&tls_exp);
+		  if (tls_exp.X_op == O_symbol)
+		    {
+		      reloc = BFD_RELOC_UNUSED;
+		      if (strncasecmp (input_line_pointer, "@tlsgd)", 7) == 0)
+			{
+			  reloc = BFD_RELOC_PPC_TLSGD;
+			  input_line_pointer += 7;
+			}
+		      else if (strncasecmp (input_line_pointer, "@tlsld)", 7) == 0)
+			{
+			  reloc = BFD_RELOC_PPC_TLSLD;
+			  input_line_pointer += 7;
+			}
+		      if (reloc != BFD_RELOC_UNUSED)
+			{
+			  SKIP_WHITESPACE ();
+			  str = input_line_pointer;
+
+			  if (fc >= MAX_INSN_FIXUPS)
+			    as_fatal (_("too many fixups"));
+			  fixups[fc].exp = tls_exp;
+			  fixups[fc].opindex = *opindex_ptr;
+			  fixups[fc].reloc = reloc;
+			  ++fc;
+			}
+		    }
+		  input_line_pointer = hold;
+		}
+	    }
+
+	  if ((reloc = ppc_elf_suffix (&str, &ex)) != BFD_RELOC_UNUSED)
 	{
 	  /* Some TLS tweaks.  */
 	  switch (reloc)
 	    {
 	    default:
 	      break;
+
 	    case BFD_RELOC_PPC_TLS:
 	      insn = ppc_insert_operand (insn, operand, ppc_obj64 ? 13 : 2,
 					 ppc_cpu, (char *) NULL, 0);
 	      break;
+
 	  /* We'll only use the 32 (or 64) bit form of these relocations
 	     in constants.  Instructions get the 16 bit form.  */
 	    case BFD_RELOC_PPC_DTPREL:
@@ -2704,17 +2776,17 @@ md_assemble (char *str)
 		  break;
 		}
 	    }
+	    }
 
 	  /* We need to generate a fixup for this expression.  */
 	  if (fc >= MAX_INSN_FIXUPS)
 	    as_fatal (_("too many fixups"));
 	  fixups[fc].exp = ex;
-	  fixups[fc].opindex = 0;
+	  fixups[fc].opindex = *opindex_ptr;
 	  fixups[fc].reloc = reloc;
 	  ++fc;
 	}
-#endif /* OBJ_ELF */
-
+#else /* OBJ_ELF */
       else
 	{
 	  /* We need to generate a fixup for this expression.  */
@@ -2725,6 +2797,7 @@ md_assemble (char *str)
 	  fixups[fc].reloc = BFD_RELOC_UNUSED;
 	  ++fc;
 	}
+#endif /* OBJ_ELF */
 
       if (need_paren)
 	{
@@ -2812,9 +2885,6 @@ md_assemble (char *str)
      md_apply_fix.  */
   for (i = 0; i < fc; i++)
     {
-      const struct powerpc_operand *operand;
-
-      operand = &powerpc_operands[fixups[i].opindex];
       if (fixups[i].reloc != BFD_RELOC_UNUSED)
 	{
 	  reloc_howto_type *reloc_howto;
@@ -2861,6 +2931,10 @@ md_assemble (char *str)
 	    }
 	}
       else
+	{
+	  const struct powerpc_operand *operand;
+
+	  operand = &powerpc_operands[fixups[i].opindex];
 	fix_new_exp (frag_now,
 		     f - frag_now->fr_literal,
 		     4,
@@ -2870,6 +2944,7 @@ md_assemble (char *str)
 		      (fixups[i].opindex + (int) BFD_RELOC_UNUSED)));
     }
 }
+}
 
 /* Handle a macro.  Gather all the operands, transform them as
    described by the macro, and call md_assemble recursively.  All the
@@ -5961,6 +6036,8 @@ md_apply_fix (fixS *fixP, valueT *valP, 
 	  break;
 
 	case BFD_RELOC_PPC_TLS:
+	case BFD_RELOC_PPC_TLSGD:
+	case BFD_RELOC_PPC_TLSLD:
 	  break;
 
 	case BFD_RELOC_PPC_DTPMOD:
Index: ld/testsuite/ld-powerpc/powerpc.exp
===================================================================
RCS file: /cvs/src/src/ld/testsuite/ld-powerpc/powerpc.exp,v
retrieving revision 1.24
diff -u -p -r1.24 powerpc.exp
--- ld/testsuite/ld-powerpc/powerpc.exp	26 Jan 2009 15:27:04 -0000	1.24
+++ ld/testsuite/ld-powerpc/powerpc.exp	20 Feb 2009 04:38:31 -0000
@@ -1,5 +1,5 @@
 # Expect script for ld-powerpc tests
-#   Copyright 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation
+#   Copyright 2002, 2003, 2005, 2006, 2007, 2008, 2009 Free Software Foundation
 #
 # This file is part of the GNU Binutils.
 #
@@ -112,6 +112,9 @@ set ppcelftests {
      {{readelf -WSsrl tlsso32.r} {objdump -dr tlsso32.d}
       {objdump -sj.got tlsso32.g} {objdump -sj.tdata tlsso32.t}}
       "tls32.so"}
+    {"TLS32 markers" "-melf32ppc" "-a32"  {tlsmark32.s tlslib32.s}
+     {{objdump -dr tlsmark32.d}}
+      "tlsmark32"}
     {"Shared library with global symbol" "-shared -melf32ppc" "-a32" {sdalib.s}
      {} "sdalib.so"}
     {"Dynamic application with SDA" "-melf32ppc tmpdir/sdalib.so" "-a32" {sdadyn.s}
@@ -145,6 +148,9 @@ set ppc64elftests {
      {{readelf -WSsrl tlstocso.r} {objdump -dr tlstocso.d}
       {objdump -sj.got tlstocso.g} {objdump -sj.tdata tlstocso.t}}
       "tlstoc.so"}
+    {"TLS markers" "-melf64ppc" "-a64"  {tlsmark.s tlslib.s}
+     {{objdump -dr tlsmark.d}}
+      "tlsmark"}
     {"sym@tocbase" "-shared -melf64ppc" "-a64" {symtocbase-1.s symtocbase-2.s}
 	{{objdump -dj.data symtocbase.d}} "symtocbase.so"}
 }
Index: ld/testsuite/ld-powerpc/tlsmark.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsmark.d
diff -N ld/testsuite/ld-powerpc/tlsmark.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsmark.d	20 Feb 2009 04:38:31 -0000
@@ -0,0 +1,42 @@
+#source: tlsmark.s
+#source: tlslib.s
+#as: -a64
+#ld: -melf64ppc
+#objdump: -dr
+#target: powerpc64*-*-*
+
+.*: +file format elf64-powerpc
+
+Disassembly of section \.text:
+
+0+100000e8 <_start>:
+    100000e8:	48 00 00 18 	b       10000100 <_start\+0x18>
+    100000ec:	60 00 00 00 	nop
+    100000f0:	38 63 90 00 	addi    r3,r3,-28672
+    100000f4:	e8 83 00 00 	ld      r4,0\(r3\)
+    100000f8:	3c 6d 00 00 	addis   r3,r13,0
+    100000fc:	48 00 00 0c 	b       10000108 <_start\+0x20>
+    10000100:	3c 6d 00 00 	addis   r3,r13,0
+    10000104:	4b ff ff e8 	b       100000ec <_start\+0x4>
+    10000108:	60 00 00 00 	nop
+    1000010c:	38 63 10 00 	addi    r3,r3,4096
+    10000110:	e8 83 80 00 	ld      r4,-32768\(r3\)
+    10000114:	3c 6d 00 00 	addis   r3,r13,0
+    10000118:	48 00 00 0c 	b       10000124 <_start\+0x3c>
+    1000011c:	3c 6d 00 00 	addis   r3,r13,0
+    10000120:	48 00 00 14 	b       10000134 <_start\+0x4c>
+    10000124:	60 00 00 00 	nop
+    10000128:	38 63 90 04 	addi    r3,r3,-28668
+    1000012c:	e8 a3 00 00 	ld      r5,0\(r3\)
+    10000130:	4b ff ff ec 	b       1000011c <_start\+0x34>
+    10000134:	60 00 00 00 	nop
+    10000138:	38 63 10 00 	addi    r3,r3,4096
+    1000013c:	e8 a3 80 04 	ld      r5,-32764\(r3\)
+    10000140:	38 62 80 28 	addi    r3,r2,-32728
+    10000144:	3f a0 10 01 	lis     r29,4097
+    10000148:	3b bd 01 68 	addi    r29,r29,360
+    1000014c:	48 00 00 09 	bl      10000154 <\.__tls_get_addr>
+    10000150:	60 00 00 00 	nop
+
+0+10000154 <\.__tls_get_addr>:
+    10000154:	4e 80 00 20 	blr
Index: ld/testsuite/ld-powerpc/tlsmark.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsmark.s
diff -N ld/testsuite/ld-powerpc/tlsmark.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsmark.s	20 Feb 2009 04:38:31 -0000
@@ -0,0 +1,55 @@
+	.section ".tdata","awT",@progbits
+x:	.int 1
+y:	.int 2
+
+	.section ".toc","aw",@progbits
+	.p2align 3
+.LC0:
+	.quad y@dtpmod
+	.quad y@dtprel
+.LC1:
+	.quad y@dtpmod
+	.quad 0
+
+	.text
+	.global _start
+_start:
+	b .L2
+
+.L1:
+	bl __tls_get_addr(x@tlsgd)
+	nop
+	ld 4,0(3)
+	addi 3,2,x@got@tlsld
+	b .L3
+.L2:
+	addi 3,2,x@got@tlsgd
+	b .L1
+.L3:
+	bl __tls_get_addr(x@tlsld)
+	nop
+	ld 4,x@dtprel(3)
+
+	addi 3,2,.LC0@toc
+	b .L5
+.L4:
+	addi 3,2,.LC1@toc
+	b .L6
+.L5:
+	bl .__tls_get_addr(.LC0@tlsgd)
+	nop
+	ld 5,0(3)
+	b .L4
+.L6:
+	bl .__tls_get_addr(.LC1@tlsld)
+	nop
+	ld 5,y@dtprel(3)
+
+
+	.section ".text.no","ax",@progbits
+	.p2align 2
+	addi 3,2,gd@got@tlsgd
+	lis 29,__tls_get_addr@ha
+	addi 29,29,__tls_get_addr@l
+	bl __tls_get_addr
+	nop
Index: ld/testsuite/ld-powerpc/tlsmark32.d
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsmark32.d
diff -N ld/testsuite/ld-powerpc/tlsmark32.d
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsmark32.d	20 Feb 2009 04:38:31 -0000
@@ -0,0 +1,29 @@
+#source: tlsmark32.s
+#source: tlslib32.s
+#as: -a32
+#ld: -melf32ppc
+#objdump: -dr
+#target: powerpc*-*-*
+
+.*:     file format elf32-powerpc
+
+Disassembly of section \.text:
+
+0+1800094 <_start>:
+ 1800094:	48 00 00 14 	b       18000a8 <_start\+0x14>
+ 1800098:	38 63 90 00 	addi    r3,r3,-28672
+ 180009c:	80 83 00 00 	lwz     r4,0\(r3\)
+ 18000a0:	3c 62 00 00 	addis   r3,r2,0
+ 18000a4:	48 00 00 0c 	b       18000b0 <_start\+0x1c>
+ 18000a8:	3c 62 00 00 	addis   r3,r2,0
+ 18000ac:	4b ff ff ec 	b       1800098 <_start\+0x4>
+ 18000b0:	38 63 10 00 	addi    r3,r3,4096
+ 18000b4:	80 83 80 00 	lwz     r4,-32768\(r3\)
+ 18000b8:	38 7f ff f4 	addi    r3,r31,-12
+ 18000bc:	3f a0 01 80 	lis     r29,384
+ 18000c0:	3b bd 00 c8 	addi    r29,r29,200
+ 18000c4:	48 00 00 05 	bl      18000c8 <__tls_get_addr>
+
+0+18000c8 <__tls_get_addr>:
+ 18000c8:	4e 80 00 20 	blr
+#pass
\ No newline at end of file
Index: ld/testsuite/ld-powerpc/tlsmark32.s
===================================================================
RCS file: ld/testsuite/ld-powerpc/tlsmark32.s
diff -N ld/testsuite/ld-powerpc/tlsmark32.s
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ ld/testsuite/ld-powerpc/tlsmark32.s	20 Feb 2009 04:38:31 -0000
@@ -0,0 +1,27 @@
+	.section ".tdata","awT",@progbits
+x:	.int 1
+
+	.text
+	.global _start
+_start:
+	b .L2
+
+.L1:
+	bl __tls_get_addr(x@tlsgd)
+	lwz 4,0(3)
+	addi 3,31,x@got@tlsld
+	b .L3
+.L2:
+	addi 3,31,x@got@tlsgd
+	b .L1
+.L3:
+	bl __tls_get_addr(x@tlsld)
+	lwz 4,x@dtprel(3)
+
+
+	.section ".text.no","ax",@progbits
+	.p2align 2
+	addi 3,31,gd@got@tlsgd
+	lis 29,__tls_get_addr@ha
+	addi 29,29,__tls_get_addr@l
+	bl __tls_get_addr

-- 
Alan Modra
Australia Development Lab, IBM


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