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 linker TLS optimization


This patch fixes a number of powerpc64 linker TLS optimization
problems I noticed when working on a fix for the ABI problem behind
http://sourceware.org/ml/binutils/2007-11/msg00033.html

1) When optimizing PowerOpen syntax TLS sequences, ie. those that use
   the TOC, the linker ignored the fact that the ABI allows an addend
   with the TLS symbol.  Not something likely to affect anyone since
   gcc doesn't use the TOC for TLS sequences and TLS relocs invariably
   have an addend of zero in practice.
2) A GD to LE optimization failed to change the addend on the second
   instruction of the sequence to that of the first reloc.  On
   powerpc64 the addends involved are normally all zero, so again
   this is unlikely to affect anyone.
3) When generating a shared library or pie, a reloc to initialize the
   got entry used by LD TLS could sometimes be omitted.  This bug is
   more likely to be triggered than the first two, but I think the
   chance of it happening is small.  (So small that I've sat on this
   change since 2008-11-20 when I made a similar fix for powerpc32.)
4) ppc64_elf_check_relocs cached the __tls_get_addr and .__tls_get_addr
   hash.  This is too early, since we have not resolved final symbol
   values at this stage.  A later object may provide a versioned
   symbol, relegating the cached hash to an indirect symbol that won't
   match anything in ppc64_elf_check_relocs.  This happens to be of no
   consequence in real code since the has_tls_reloc flag ought to be
   set by the __tls_get_addr arg setup instruction.

Also included in the patch are a number of minor tweaks to avoid
unnecessary work, and extraction of code recognizing __tls_get_addr
relocs to a function.

	* elf64-ppc.c (struct _ppc64_elf_section_data): Delete t_symndx,
	add toc.symndx and toc.add.
	(ppc64_elf_check_relocs): Don't set htab->tls_get_addr here.
	Set up toc.add.
	(get_tls_mask): Add toc_addend param, set from toc.add.  Adjust all
	callers.
	(ppc64_elf_tls_setup): Set htab->tls_get_addr and tls_get_addr_fd.
	(branch_reloc_hash_match): New function, extracted from..
	(ppc64_elf_tls_optimize): ..here.
	(ppc64_elf_relocate_section): Properly set addends when optimizing
	tls sequences.  Avoid unnecessary reading and writing of insns.
	Only redo reloc when symbol changed.  Bypass symbol checks when
	using tlsld_got.
	* elf32-ppc.c (ppc_elf_tls_setup): Correct comment.
	(branch_reloc_hash_match): New function, extracted from..
	(ppc_elf_tls_optimize): ..here.
	(ppc_elf_relocate_section): Avoid unnecessary reading of insns.
	Don't clear addend on zapped __tls_get_addr reloc.

Index: bfd/elf32-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf32-ppc.c,v
retrieving revision 1.250
diff -u -p -r1.250 elf32-ppc.c
--- bfd/elf32-ppc.c	26 Jan 2009 15:27:03 -0000	1.250
+++ bfd/elf32-ppc.c	15 Feb 2009 05:54:01 -0000
@@ -4301,7 +4301,8 @@ ppc_elf_gc_sweep_hook (bfd *abfd,
   return TRUE;
 }
 
-/* Set htab->tls_get_addr and call the generic ELF tls_setup function.  */
+/* Set plt output section type, htab->tls_get_addr, and call the
+   generic ELF tls_setup function.  */
 
 asection *
 ppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info)
@@ -4322,6 +4323,43 @@ ppc_elf_tls_setup (bfd *obfd, struct bfd
   return _bfd_elf_tls_setup (obfd, info);
 }
 
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+   HASH.  */
+
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+			 const Elf_Internal_Rela *rel,
+			 const struct elf_link_hash_entry *hash)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+  enum elf_ppc_reloc_type r_type = ELF32_R_TYPE (rel->r_info);
+  unsigned int r_symndx = ELF32_R_SYM (rel->r_info);
+
+  if (r_symndx >= symtab_hdr->sh_info
+      && (r_type == R_PPC_PLTREL24
+	  || r_type == R_PPC_LOCAL24PC
+	  || r_type == R_PPC_REL14
+	  || r_type == R_PPC_REL14_BRTAKEN
+	  || r_type == R_PPC_REL14_BRNTAKEN
+	  || r_type == R_PPC_REL24
+	  || r_type == R_PPC_ADDR24
+	  || r_type == R_PPC_ADDR14
+	  || r_type == R_PPC_ADDR14_BRTAKEN
+	  || r_type == R_PPC_ADDR14_BRNTAKEN))
+    {
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
+
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+	     || h->root.type == bfd_link_hash_warning)
+	h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      if (h == hash)
+	return TRUE;
+    }
+  return FALSE;
+}
+
 /* Run through all the TLS relocs looking for optimization
    opportunities.  */
 
@@ -4449,35 +4487,10 @@ ppc_elf_tls_optimize (bfd *obfd ATTRIBUT
 		      if (!expecting_tls_get_addr)
 			continue;
 
-		      if (rel + 1 < relend)
-			{
-			  enum elf_ppc_reloc_type r_type2;
-			  unsigned long r_symndx2;
-			  struct elf_link_hash_entry *h2;
-
-			  /* The next instruction should be a call to
-			     __tls_get_addr.  Peek at the reloc to be sure.  */
-			  r_type2 = ELF32_R_TYPE (rel[1].r_info);
-			  r_symndx2 = ELF32_R_SYM (rel[1].r_info);
-			  if (r_symndx2 >= symtab_hdr->sh_info
-			      && (r_type2 == R_PPC_REL14
-				  || r_type2 == R_PPC_REL14_BRTAKEN
-				  || r_type2 == R_PPC_REL14_BRNTAKEN
-				  || r_type2 == R_PPC_REL24
-				  || r_type2 == R_PPC_PLTREL24))
-			    {
-			      struct elf_link_hash_entry **sym_hashes;
-
-			      sym_hashes = elf_sym_hashes (ibfd);
-			      h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
-			      while (h2->root.type == bfd_link_hash_indirect
-				     || h2->root.type == bfd_link_hash_warning)
-				h2 = ((struct elf_link_hash_entry *)
-				      h2->root.u.i.link);
-			      if (h2 == htab->tls_get_addr)
-				continue;
-			    }
-			}
+		      if (rel + 1 < relend
+			  && branch_reloc_hash_match (ibfd, rel + 1,
+						      htab->tls_get_addr))
+			continue;
 
 		      /* Uh oh, we didn't find the expected call.  We
 			 could just mark this symbol to exclude it
@@ -6344,22 +6357,21 @@ ppc_elf_relocate_section (bfd *output_bf
 	case R_PPC_GOT_TLSLD16_LO:
 	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
 	    {
-	      bfd_vma insn1, insn2;
+	      unsigned int insn1, insn2;
 	      bfd_vma offset;
 
 	    tls_ldgd_opt:
 	      offset = rel[1].r_offset;
-	      insn1 = bfd_get_32 (output_bfd,
-				  contents + rel->r_offset - d_offset);
 	      if ((tls_mask & tls_gd) != 0)
 		{
 		  /* IE */
+		  insn1 = bfd_get_32 (output_bfd,
+				      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);
-		  rel[1].r_addend = 0;
 		  r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3)
 			    + R_PPC_GOT_TPREL16);
 		  rel->r_info = ELF32_R_INFO (r_symndx, r_type);
Index: bfd/elf64-ppc.c
===================================================================
RCS file: /cvs/src/src/bfd/elf64-ppc.c,v
retrieving revision 1.290
diff -u -p -r1.290 elf64-ppc.c
--- bfd/elf64-ppc.c	11 Dec 2008 10:14:40 -0000	1.290
+++ bfd/elf64-ppc.c	15 Feb 2009 06:46:00 -0000
@@ -2608,9 +2608,15 @@ struct _ppc64_elf_section_data
       long *adjust;
     } opd;
 
-    /* An array for toc sections, indexed by offset/8.
-       Specifies the relocation symbol index used at a given toc offset.  */
-    unsigned *t_symndx;
+    /* An array for toc sections, indexed by offset/8.  */
+    struct _toc_sec_data
+    {
+      /* Specifies the relocation symbol index used at a given toc offset.  */
+      unsigned *symndx;
+
+      /* And the relocation addend.  */
+      bfd_vma *add;
+    } toc;
   } u;
 
   enum _ppc64_sec_type sec_type:2;
@@ -4578,6 +4584,7 @@ ppc64_elf_check_relocs (bfd *abfd, struc
   const Elf_Internal_Rela *rel_end;
   asection *sreloc;
   asection **opd_sym_map;
+  struct elf_link_hash_entry *tga, *dottga;
 
   if (info->relocatable)
     return TRUE;
@@ -4594,6 +4601,10 @@ ppc64_elf_check_relocs (bfd *abfd, struc
   BFD_ASSERT (is_ppc64_elf (abfd));
 
   htab = ppc_hash_table (info);
+  tga = elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+			      FALSE, FALSE, TRUE);
+  dottga = elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+				 FALSE, FALSE, TRUE);
   symtab_hdr = &elf_symtab_hdr (abfd);
 
   sym_hashes = elf_sym_hashes (abfd);
@@ -4829,25 +4840,8 @@ ppc64_elf_check_relocs (bfd *abfd, struc
 	      if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h,
 				    rel->r_addend))
 		return FALSE;
-	      if (h == &htab->tls_get_addr->elf
-		  || h == &htab->tls_get_addr_fd->elf)
+	      if (h == tga || h == dottga)
 		sec->has_tls_reloc = 1;
-	      else if (htab->tls_get_addr == NULL
-		       && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr")
-		       && (h->root.root.string[15] == 0
-			   || h->root.root.string[15] == '@'))
-		{
-		  htab->tls_get_addr = (struct ppc_link_hash_entry *) h;
-		  sec->has_tls_reloc = 1;
-		}
-	      else if (htab->tls_get_addr_fd == NULL
-		       && CONST_STRNEQ (h->root.root.string, "__tls_get_addr")
-		       && (h->root.root.string[14] == 0
-			   || h->root.root.string[14] == '@'))
-		{
-		  htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h;
-		  sec->has_tls_reloc = 1;
-		}
 	    }
 	  break;
 
@@ -4891,23 +4885,30 @@ ppc64_elf_check_relocs (bfd *abfd, struc
 	  ppc64_sec = ppc64_elf_section_data (sec);
 	  if (ppc64_sec->sec_type != sec_toc)
 	    {
+	      bfd_size_type amt;
+
 	      /* One extra to simplify get_tls_mask.  */
-	      bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1;
-	      ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt);
-	      if (ppc64_sec->u.t_symndx == NULL)
+	      amt = sec->size * sizeof (unsigned) / 8 + sizeof (unsigned);
+	      ppc64_sec->u.toc.symndx = bfd_zalloc (abfd, amt);
+	      if (ppc64_sec->u.toc.symndx == NULL)
+		return FALSE;
+	      amt = sec->size * sizeof (bfd_vma) / 8;
+	      ppc64_sec->u.toc.add = bfd_zalloc (abfd, amt);
+	      if (ppc64_sec->u.toc.add == NULL)
 		return FALSE;
 	      BFD_ASSERT (ppc64_sec->sec_type == sec_normal);
 	      ppc64_sec->sec_type = sec_toc;
 	    }
 	  BFD_ASSERT (rel->r_offset % 8 == 0);
-	  ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx;
+	  ppc64_sec->u.toc.symndx[rel->r_offset / 8] = r_symndx;
+	  ppc64_sec->u.toc.add[rel->r_offset / 8] = rel->r_addend;
 
 	  /* Mark the second slot of a GD or LD entry.
 	     -1 to indicate GD and -2 to indicate LD.  */
 	  if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD))
-	    ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1;
+	    ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -1;
 	  else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD))
-	    ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2;
+	    ppc64_sec->u.toc.symndx[rel->r_offset / 8 + 1] = -2;
 	  goto dodyn;
 
 	case R_PPC64_TPREL16:
@@ -6226,9 +6227,12 @@ get_sym_h (struct elf_link_hash_entry **
    type suitable for optimization, and 1 otherwise.  */
 
 static int
-get_tls_mask (char **tls_maskp, unsigned long *toc_symndx,
+get_tls_mask (char **tls_maskp,
+	      unsigned long *toc_symndx,
+	      bfd_vma *toc_addend,
 	      Elf_Internal_Sym **locsymsp,
-	      const Elf_Internal_Rela *rel, bfd *ibfd)
+	      const Elf_Internal_Rela *rel,
+	      bfd *ibfd)
 {
   unsigned long r_symndx;
   int next_r;
@@ -6256,12 +6260,14 @@ get_tls_mask (char **tls_maskp, unsigned
     off = sym->st_value;
   off += rel->r_addend;
   BFD_ASSERT (off % 8 == 0);
-  r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8];
-  next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1];
-  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
-    return 0;
+  r_symndx = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8];
+  next_r = ppc64_elf_section_data (sec)->u.toc.symndx[off / 8 + 1];
   if (toc_symndx != NULL)
     *toc_symndx = r_symndx;
+  if (toc_addend != NULL)
+    *toc_addend = ppc64_elf_section_data (sec)->u.toc.add[off / 8];
+  if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd))
+    return 0;
   if ((h == NULL
        || ((h->root.type == bfd_link_hash_defined
 	    || h->root.type == bfd_link_hash_defweak)
@@ -6866,36 +6872,49 @@ ppc64_elf_tls_setup (bfd *obfd, struct b
   struct ppc_link_hash_table *htab;
 
   htab = ppc_hash_table (info);
-  if (htab->tls_get_addr != NULL)
-    {
-      struct ppc_link_hash_entry *h = htab->tls_get_addr;
-
-      while (h->elf.root.type == bfd_link_hash_indirect
-	     || h->elf.root.type == bfd_link_hash_warning)
-	h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+  htab->tls_get_addr = ((struct ppc_link_hash_entry *)
+			elf_link_hash_lookup (&htab->elf, ".__tls_get_addr",
+					      FALSE, FALSE, TRUE));
+  htab->tls_get_addr_fd = ((struct ppc_link_hash_entry *)
+			   elf_link_hash_lookup (&htab->elf, "__tls_get_addr",
+						 FALSE, FALSE, TRUE));
+  return _bfd_elf_tls_setup (obfd, info);
+}
 
-      htab->tls_get_addr = h;
+/* Return TRUE iff REL is a branch reloc with a global symbol matching
+   HASH1 or HASH2.  */
 
-      if (htab->tls_get_addr_fd == NULL
-	  && h->oh != NULL
-	  && h->oh->is_func_descriptor
-	  && (h->oh->elf.root.type == bfd_link_hash_defined
-	      || h->oh->elf.root.type == bfd_link_hash_defweak))
-	htab->tls_get_addr_fd = h->oh;
-    }
+static bfd_boolean
+branch_reloc_hash_match (const bfd *ibfd,
+			 const Elf_Internal_Rela *rel,
+			 const struct ppc_link_hash_entry *hash1,
+			 const struct ppc_link_hash_entry *hash2)
+{
+  Elf_Internal_Shdr *symtab_hdr = &elf_symtab_hdr (ibfd);
+  enum elf_ppc64_reloc_type r_type = ELF64_R_TYPE (rel->r_info);
+  unsigned int r_symndx = ELF64_R_SYM (rel->r_info);
 
-  if (htab->tls_get_addr_fd != NULL)
+  if (r_symndx >= symtab_hdr->sh_info
+      && (r_type == R_PPC64_REL24
+	  || r_type == R_PPC64_REL14
+	  || r_type == R_PPC64_REL14_BRTAKEN
+	  || r_type == R_PPC64_REL14_BRNTAKEN
+	  || r_type == R_PPC64_ADDR24
+	  || r_type == R_PPC64_ADDR14
+	  || r_type == R_PPC64_ADDR14_BRTAKEN
+	  || r_type == R_PPC64_ADDR14_BRNTAKEN))
     {
-      struct ppc_link_hash_entry *h = htab->tls_get_addr_fd;
-
-      while (h->elf.root.type == bfd_link_hash_indirect
-	     || h->elf.root.type == bfd_link_hash_warning)
-	h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link;
+      struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd);
+      struct elf_link_hash_entry *h;
 
-      htab->tls_get_addr_fd = h;
+      h = sym_hashes[r_symndx - symtab_hdr->sh_info];
+      while (h->root.type == bfd_link_hash_indirect
+	     || h->root.type == bfd_link_hash_warning)
+	h = (struct elf_link_hash_entry *) h->root.u.i.link;
+      if (h == &hash1->elf || h == &hash2->elf)
+	return TRUE;
     }
-
-  return _bfd_elf_tls_setup (obfd, info);
+  return FALSE;
 }
 
 /* Run through all the TLS relocs looking for optimization
@@ -7141,55 +7160,26 @@ ppc64_elf_tls_optimize (bfd *obfd ATTRIB
 		      if (!expecting_tls_get_addr)
 			continue;
 
-		      if (rel + 1 < relend)
+		      if (rel + 1 < relend
+			  && branch_reloc_hash_match (ibfd, rel + 1,
+						      htab->tls_get_addr,
+						      htab->tls_get_addr_fd))
 			{
-			  Elf_Internal_Shdr *symtab_hdr;
-			  enum elf_ppc64_reloc_type r_type2;
-			  unsigned long r_symndx2;
-			  struct elf_link_hash_entry *h2;
-
-			  symtab_hdr = &elf_symtab_hdr (ibfd);
-
-			  /* The next instruction should be a call to
-			     __tls_get_addr.  Peek at the reloc to be sure.  */
-			  r_type2 = ELF64_R_TYPE (rel[1].r_info);
-			  r_symndx2 = ELF64_R_SYM (rel[1].r_info);
-			  if (r_symndx2 >= symtab_hdr->sh_info
-			      && (r_type2 == R_PPC64_REL14
-				  || r_type2 == R_PPC64_REL14_BRTAKEN
-				  || r_type2 == R_PPC64_REL14_BRNTAKEN
-				  || r_type2 == R_PPC64_REL24))
+			  if (expecting_tls_get_addr == 2)
 			    {
-			      struct elf_link_hash_entry **sym_hashes;
-
-			      sym_hashes = elf_sym_hashes (ibfd);
-
-			      h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info];
-			      while (h2->root.type == bfd_link_hash_indirect
-				     || h2->root.type == bfd_link_hash_warning)
-				h2 = ((struct elf_link_hash_entry *)
-				      h2->root.u.i.link);
-			      if (h2 != NULL
-				  && (h2 == &htab->tls_get_addr->elf
-				      || h2 == &htab->tls_get_addr_fd->elf))
-				{
-				  if (expecting_tls_get_addr == 2)
-				    {
-				      /* Check for toc tls entries.  */
-				      char *toc_tls;
-				      int retval;
-
-				      retval = get_tls_mask (&toc_tls, NULL,
-							     &locsyms,
-							     rel, ibfd);
-				      if (retval == 0)
-					goto err_free_rel;
-				      if (retval > 1 && toc_tls != NULL)
-					toc_ref[toc_ref_index] = 1;
-				    }
-				  continue;
-				}
+			      /* Check for toc tls entries.  */
+			      char *toc_tls;
+			      int retval;
+
+			      retval = get_tls_mask (&toc_tls, NULL, NULL,
+						     &locsyms,
+						     rel, ibfd);
+			      if (retval == 0)
+				goto err_free_rel;
+			      if (retval > 1 && toc_tls != NULL)
+				toc_ref[toc_ref_index] = 1;
 			    }
+			  continue;
 			}
 
 		      if (expecting_tls_get_addr != 1)
@@ -9712,7 +9702,7 @@ ppc64_elf_size_stubs (bfd *output_bfd,
 		      /* Get tls info.  */
 		      char *tls_mask;
 
-		      if (!get_tls_mask (&tls_mask, NULL, &local_syms,
+		      if (!get_tls_mask (&tls_mask, NULL, NULL, &local_syms,
 					 irela - 1, input_bfd))
 			goto error_ret_free_internal;
 		      if (*tls_mask != 0)
@@ -10204,6 +10194,7 @@ ppc64_elf_relocate_section (bfd *output_
       struct ppc_link_hash_entry *fdh;
       const char *sym_name;
       unsigned long r_symndx, toc_symndx;
+      bfd_vma toc_addend;
       char tls_mask, tls_gd, tls_type;
       char sym_type;
       bfd_vma relocation;
@@ -10312,8 +10303,8 @@ ppc64_elf_relocate_section (bfd *output_
 	      /* Check for toc tls entries.  */
 	      char *toc_tls;
 
-	      if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-				 rel, input_bfd))
+	      if (!get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+				 &local_syms, rel, input_bfd))
 		return FALSE;
 
 	      if (toc_tls)
@@ -10375,8 +10366,8 @@ ppc64_elf_relocate_section (bfd *output_
 	    char *toc_tls;
 	    int retval;
 
-	    retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms,
-				   rel, input_bfd);
+	    retval = get_tls_mask (&toc_tls, &toc_symndx, &toc_addend,
+				   &local_syms, rel, input_bfd);
 	    if (retval == 0)
 	      return FALSE;
 
@@ -10424,6 +10415,7 @@ ppc64_elf_relocate_section (bfd *output_
 	      if (toc_symndx != 0)
 		{
 		  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+		  rel->r_addend = toc_addend;
 		  /* We changed the symbol.  Start over in order to
 		     get h, sym, sec etc. right.  */
 		  rel--;
@@ -10477,6 +10469,7 @@ ppc64_elf_relocate_section (bfd *output_
 	      if (toc_symndx != 0)
 		{
 		  rel->r_info = ELF64_R_INFO (toc_symndx, r_type);
+		  rel->r_addend = toc_addend;
 		  /* We changed the symbol.  Start over in order to
 		     get h, sym, sec etc. right.  */
 		  rel--;
@@ -10523,20 +10516,18 @@ ppc64_elf_relocate_section (bfd *output_
 	case R_PPC64_GOT_TLSLD16_LO:
 	  if (tls_mask != 0 && (tls_mask & TLS_LD) == 0)
 	    {
-	      bfd_vma insn1, insn2, insn3;
+	      unsigned int insn1, insn2, insn3;
 	      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;
-	      insn1 = bfd_get_32 (output_bfd,
-				  contents + rel->r_offset - d_offset);
-	      insn3 = bfd_get_32 (output_bfd,
-				  contents + offset + 4);
 	      if ((tls_mask & tls_gd) != 0)
 		{
 		  /* IE */
+		  insn1 = bfd_get_32 (output_bfd,
+				      contents + rel->r_offset - d_offset);
 		  insn1 &= (1 << 26) - (1 << 2);
 		  insn1 |= 58 << 26;	/* ld */
 		  insn2 = 0x7c636a14;	/* add 3,3,13 */
@@ -10571,28 +10562,33 @@ ppc64_elf_relocate_section (bfd *output_
 			rel->r_addend -= (local_syms[r_symndx].st_value
 					  + sec->output_offset
 					  + sec->output_section->vma);
-		      rel[1].r_addend = rel->r_addend;
 		    }
 		  else if (toc_symndx != 0)
-		    r_symndx = toc_symndx;
+		    {
+		      r_symndx = toc_symndx;
+		      rel->r_addend = toc_addend;
+		    }
 		  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;
 		}
+	      bfd_put_32 (output_bfd, insn1,
+			  contents + rel->r_offset - d_offset);
+	      insn3 = bfd_get_32 (output_bfd,
+				  contents + offset + 4);
 	      if (insn3 == NOP
 		  || insn3 == CROR_151515 || insn3 == CROR_313131)
 		{
-		  insn3 = insn2;
-		  insn2 = NOP;
 		  rel[1].r_offset += 4;
+		  bfd_put_32 (output_bfd, insn2, contents + offset + 4);
+		  insn2 = NOP;
 		}
-	      bfd_put_32 (output_bfd, insn1,
-			  contents + rel->r_offset - d_offset);
 	      bfd_put_32 (output_bfd, insn2, contents + offset);
-	      bfd_put_32 (output_bfd, insn3, contents + offset + 4);
-	      if (tls_gd == 0 || toc_symndx != 0)
+	      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.  */
@@ -10969,7 +10965,8 @@ ppc64_elf_relocate_section (bfd *output_
 
 		*offp = off | 1;
 		if ((info->shared || indx != 0)
-		    && (h == NULL
+		    && (offp == &ppc64_tlsld_got (input_bfd)->offset
+			|| h == NULL
 			|| ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT
 			|| h->elf.root.type != bfd_link_hash_undefweak))
 		  {

-- 
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]