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]

[patch 2/2, m68k] Fix bugs in the handling of TLS relocations


Good day again,

This second patch rewrites initialization of GOT entries and output of dynamic relocations. In the course of that it also fixes several bugs in the said processes.

Unfortunately, I didn't get this work right the first time, so I have spent quite some time debugging relocation bugs in GLIBC. But now, with this brand new shiny patch everything seems to work as expected.

Any comments? OK to check in?

Thanks,

--
Maxim K.
CodeSourcery
2009-08-25  Maxim Kuvyrkov  <maxim@codesourcery.com>

	* elf32-m68k.c: Rewrite initialization of GOT entries for TLS
	relocations.  Rewrite output of dynamic TLS relocations.
	(DTP_OFFSET, TP_OFFSET): New constants.
	(dtpoff_base): Update.
	(tpoff): Rename to tpoff_base, update.
	(elf_m68k_init_got_entry_static, elf_m68k_init_got_entry_local_shared):
	New functions.  Move code from elf_m68k_relocate_section here.
	(elf_m68k_relocate_section): Update.
	(elf_m68k_finish_dynamic_symbol): Fix handling of local TLS symbols.
Index: elf32-m68k.c
===================================================================
RCS file: /scratch/gcc/repos/src/src/bfd/elf32-m68k.c,v
retrieving revision 1.112
diff -u -p -r1.112 elf32-m68k.c
--- elf32-m68k.c	18 Jun 2009 14:18:29 -0000	1.112
+++ elf32-m68k.c	24 Aug 2009 21:30:16 -0000
@@ -3422,9 +3446,11 @@ elf_m68k_install_rela (bfd *output_bfd,
   bfd_elf32_swap_reloca_out (output_bfd, rela, loc);
 }
 
-/* Return the base VMA address which should be subtracted from real addresses
-   when resolving @dtpoff relocation.
-   This is PT_TLS segment p_vaddr.  */
+/* Find the base offsets for thread-local storage in this object,
+   for GD/LD and IE/LE respectively.  */
+
+#define DTP_OFFSET 0x8000
+#define TP_OFFSET  0x7000
 
 static bfd_vma
 dtpoff_base (struct bfd_link_info *info)
@@ -3432,23 +3458,116 @@ dtpoff_base (struct bfd_link_info *info)
   /* If tls_sec is NULL, we should have signalled an error already.  */
   if (elf_hash_table (info)->tls_sec == NULL)
     return 0;
-  return elf_hash_table (info)->tls_sec->vma;
+  return elf_hash_table (info)->tls_sec->vma + DTP_OFFSET;
 }
 
-/* Return the relocation value for @tpoff relocation
-   if STT_TLS virtual address is ADDRESS.  */
-
 static bfd_vma
-tpoff (struct bfd_link_info *info, bfd_vma address)
+tpoff_base (struct bfd_link_info *info)
 {
-  struct elf_link_hash_table *htab = elf_hash_table (info);
-  bfd_vma base;
-
   /* If tls_sec is NULL, we should have signalled an error already.  */
-  if (htab->tls_sec == NULL)
+  if (elf_hash_table (info)->tls_sec == NULL)
     return 0;
-  base = align_power ((bfd_vma) 8, htab->tls_sec->alignment_power);
-  return address - htab->tls_sec->vma + base;
+  return elf_hash_table (info)->tls_sec->vma + TP_OFFSET;
+}
+
+/* Output necessary relocation to handle a symbol during static link.
+   This function is called from elf_m68k_relocate_section.  */
+
+static void
+elf_m68k_init_got_entry_static (struct bfd_link_info *info,
+				bfd *output_bfd,
+				enum elf_m68k_reloc_type r_type,
+				asection *sgot,
+				bfd_vma got_entry_offset,
+				bfd_vma relocation)
+{
+  switch (elf_m68k_reloc_got_type (r_type))
+    {
+    case R_68K_GOT32O:
+      bfd_put_32 (output_bfd, relocation, sgot->contents + got_entry_offset);
+      break;
+
+    case R_68K_TLS_GD32:
+      /* We know the offset within the module,
+	 put it into the second GOT slot.  */
+      bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+		  sgot->contents + got_entry_offset + 4);
+      /* FALLTHRU */
+
+    case R_68K_TLS_LDM32:
+      /* Mark it as belonging to module 1, the executable.  */
+      bfd_put_32 (output_bfd, 1, sgot->contents + got_entry_offset);
+      break;
+
+    case R_68K_TLS_IE32:
+      bfd_put_32 (output_bfd, relocation - tpoff_base (info),
+		  sgot->contents + got_entry_offset);
+      break;
+
+    default:
+      BFD_ASSERT (FALSE);
+    }
+}
+
+/* Output necessary relocation to handle a local symbol
+   during dynamic link.
+   This function is called either from elf_m68k_relocate_section
+   or from elf_m68k_finish_dynamic_symbol.  */
+
+static void
+elf_m68k_init_got_entry_local_shared (struct bfd_link_info *info,
+				      bfd *output_bfd,
+				      enum elf_m68k_reloc_type r_type,
+				      asection *sgot,
+				      bfd_vma got_entry_offset,
+				      bfd_vma relocation,
+				      asection *srela)
+{
+  Elf_Internal_Rela outrel;
+
+  switch (elf_m68k_reloc_got_type (r_type))
+    {
+    case R_68K_GOT32O:
+      /* Emit RELATIVE relocation to initialize GOT slot
+	 at run-time.  */
+      outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+      outrel.r_addend = relocation;
+      break;
+
+    case R_68K_TLS_GD32:
+      /* We know the offset within the module,
+	 put it into the second GOT slot.  */
+      bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+		  sgot->contents + got_entry_offset + 4);
+      /* FALLTHRU */
+
+    case R_68K_TLS_LDM32:
+      /* We don't know the module number,
+	 create a relocation for it.  */
+      outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
+      outrel.r_addend = 0;
+      break;
+
+    case R_68K_TLS_IE32:
+      /* Emit TPREL relocation to initialize GOT slot
+	 at run-time.  */
+      outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32);
+      outrel.r_addend = relocation - elf_hash_table (info)->tls_sec->vma;
+      break;
+
+    default:
+      BFD_ASSERT (FALSE);
+    }
+
+  /* Offset of the GOT entry.  */
+  outrel.r_offset = (sgot->output_section->vma
+		     + sgot->output_offset
+		     + got_entry_offset);
+
+  /* Install one of the above relocations.  */
+  elf_m68k_install_rela (output_bfd, srela, &outrel);
+
+  bfd_put_32 (output_bfd, outrel.r_addend, sgot->contents + got_entry_offset);
 }
 
 /* Relocate an M68K ELF section.  */
@@ -3471,6 +3590,7 @@ elf_m68k_relocate_section (output_bfd, i
   asection *sgot;
   asection *splt;
   asection *sreloc;
+  asection *srela;
   struct elf_m68k_got *got;
   Elf_Internal_Rela *rel;
   Elf_Internal_Rela *relend;
@@ -3482,6 +3602,7 @@ elf_m68k_relocate_section (output_bfd, i
   sgot = NULL;
   splt = NULL;
   sreloc = NULL;
+  srela = NULL;
 
   got = NULL;
 
@@ -3680,7 +3801,7 @@ elf_m68k_relocate_section (output_bfd, i
 			/* This is actually a static link, or it is a
 			   -Bsymbolic link and the symbol is defined
 			   locally, or the symbol was forced to be local
-			   because of a version file..  We must initialize
+			   because of a version file.  We must initialize
 			   this entry in the global offset table.  Since
 			   the offset must always be a multiple of 4, we
 			   use the least significant bit to record whether
@@ -3690,26 +3811,12 @@ elf_m68k_relocate_section (output_bfd, i
 			   relocation entry to initialize the value.  This
 			   is done in the finish_dynamic_symbol routine.  */
 
-			if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O)
-			  bfd_put_32 (output_bfd, relocation,
-				      sgot->contents + off);
-			else if (elf_m68k_reloc_got_type (r_type)
-				 == R_68K_TLS_GD32)
-			  /* Mark it as belonging to module 1,
-			     the executable.  */
-			  {
-			    bfd_put_32 (output_bfd, 1,
-					sgot->contents + off);
-			    bfd_put_32 (output_bfd, (relocation
-						     - dtpoff_base (info)),
-					sgot->contents + off + 4);
-			  }
-			else if (elf_m68k_reloc_got_type (r_type)
-				 == R_68K_TLS_IE32)
-			  bfd_put_32 (output_bfd, tpoff (info, relocation),
-				      sgot->contents + off);
-			else
-			  BFD_ASSERT (FALSE);
+			elf_m68k_init_got_entry_static (info,
+							output_bfd,
+							r_type,
+							sgot,
+							off,
+							relocation);
 
 			*off_ptr |= 1;
 		      }
@@ -3717,103 +3824,32 @@ elf_m68k_relocate_section (output_bfd, i
 		      unresolved_reloc = FALSE;
 		  }
 		else if (info->shared) /* && h == NULL */
+		  /* Process local symbol during dynamic link.  */
 		  {
-		    asection *srela;
-		    Elf_Internal_Rela outrel;
-
-		    srela = bfd_get_section_by_name (dynobj, ".rela.got");
-		    BFD_ASSERT (srela != NULL);
-
-		    if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O)
-		      {
-			/* Emit RELATIVE relocation to initialize GOT slot
-			   at run-time.  */
-			outrel.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
-			outrel.r_addend = relocation;
-			outrel.r_offset = (sgot->output_section->vma
-					   + sgot->output_offset
-					   + off);
-
-			elf_m68k_install_rela (output_bfd, srela, &outrel);
-		      }
-		    else if (elf_m68k_reloc_got_type (r_type)
-			     == R_68K_TLS_LDM32)
-		      {
-			/* If we don't know the module number, create
-			   a relocation for it.  */
-			outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
-			outrel.r_addend = 0;
-			outrel.r_offset = (sgot->output_section->vma
-					   + sgot->output_offset
-					   + off);
-
-			elf_m68k_install_rela (output_bfd, srela, &outrel);
-		      }
-		    else if (elf_m68k_reloc_got_type (r_type)
-			     == R_68K_TLS_GD32)
-		      {
-			/* If we don't know the module number, create
-			   a relocation for it.  */
-			outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
-			outrel.r_addend = 0;
-			outrel.r_offset = (sgot->output_section->vma
-					   + sgot->output_offset
-					   + off);
-
-			elf_m68k_install_rela (output_bfd, srela, &outrel);
-
-			bfd_put_32 (output_bfd, (relocation
-						 - dtpoff_base (info)),
-				    sgot->contents + off + 4);
-		      }
-		    else if (elf_m68k_reloc_got_type (r_type)
-			     == R_68K_TLS_IE32)
+		    if (srela == NULL)
 		      {
-			outrel.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32);
-			outrel.r_addend = relocation - dtpoff_base (info);
-			outrel.r_offset = (sgot->output_section->vma
-					   + sgot->output_offset
-					   + off);
-
-			elf_m68k_install_rela (output_bfd, srela, &outrel);
+			srela = bfd_get_section_by_name (dynobj, ".rela.got");
+			BFD_ASSERT (srela != NULL);
 		      }
-		    else
-		      BFD_ASSERT (FALSE);
 
-		    bfd_put_32 (output_bfd, outrel.r_addend,
-				sgot->contents + off);
+		    elf_m68k_init_got_entry_local_shared (info,
+							  output_bfd,
+							  r_type,
+							  sgot,
+							  off,
+							  relocation,
+							  srela);
 
 		    *off_ptr |= 1;
 		  }
 		else /* h == NULL && !info->shared */
 		  {
-		    if (elf_m68k_reloc_got_type (r_type) == R_68K_GOT32O)
-		      bfd_put_32 (output_bfd, relocation,
-				  sgot->contents + off);
-		    else if (elf_m68k_reloc_got_type (r_type)
-			     == R_68K_TLS_LDM32)
-		      /* If this is a static link, put the number of the
-			 only module in the GOT slot.  */
-		      bfd_put_32 (output_bfd, 1, sgot->contents + off);
-		    else if (elf_m68k_reloc_got_type (r_type)
-			     == R_68K_TLS_GD32)
-		      {
-			/* If we are not emitting relocations for a
-			   general dynamic reference, then we must be in a
-			   static link or an executable link with the
-			   symbol binding locally.  Mark it as belonging
-			   to module 1, the executable.  */
-			bfd_put_32 (output_bfd, 1, sgot->contents + off);
-			bfd_put_32 (output_bfd, (relocation
-						 - dtpoff_base (info)),
-				    sgot->contents + off + 4);
-		      }
-		    else if (elf_m68k_reloc_got_type (r_type)
-			     == R_68K_TLS_IE32)
-		      bfd_put_32 (output_bfd, tpoff (info, relocation),
-				  sgot->contents + off);
-		    else
-		      BFD_ASSERT (FALSE);
+		    elf_m68k_init_got_entry_static (info,
+						    output_bfd,
+						    r_type,
+						    sgot,
+						    off,
+						    relocation);
 
 		    *off_ptr |= 1;
 		  }
@@ -3843,7 +3879,6 @@ elf_m68k_relocate_section (output_bfd, i
 		  }
 
 		/* This relocation does not use the addend.  */
-		BFD_ASSERT (rel->r_addend == 0);
 		rel->r_addend = 0;
 	      }
 	    else
@@ -3871,7 +3906,7 @@ elf_m68k_relocate_section (output_bfd, i
 	      return FALSE;
 	    }
 	  else
-	    relocation = tpoff (info, relocation);
+	    relocation -= tpoff_base (info);
 
 	  break;
 
@@ -4270,15 +4305,12 @@ elf_m68k_finish_dynamic_symbol (output_b
 
       while (got_entry != NULL)
 	{
-	  Elf_Internal_Rela rela;
+	  enum elf_m68k_reloc_type r_type;
 	  bfd_vma got_entry_offset;
 
+	  r_type = got_entry->key_.type;
 	  got_entry_offset = got_entry->u.s2.offset &~ (bfd_vma) 1;
 
-	  rela.r_offset = (sgot->output_section->vma
-			   + sgot->output_offset
-			   + got_entry_offset);
-
 	  /* If this is a -Bsymbolic link, and the symbol is defined
 	     locally, we just want to emit a RELATIVE reloc.  Likewise if
 	     the symbol was forced to be local because of a version file.
@@ -4287,33 +4319,43 @@ elf_m68k_finish_dynamic_symbol (output_b
 	  if (info->shared
 	      && SYMBOL_REFERENCES_LOCAL (info, h))
 	    {
-	      rela.r_addend = bfd_get_signed_32 (output_bfd,
-						 (sgot->contents
-						  + got_entry_offset));
+	      bfd_vma relocation;
+
+	      relocation = bfd_get_signed_32 (output_bfd,
+					      (sgot->contents
+					       + got_entry_offset));
 
-	      switch (elf_m68k_reloc_got_type (got_entry->key_.type))
+	      /* Undo TP bias.  */
+	      switch (elf_m68k_reloc_got_type (r_type))
 		{
 		case R_68K_GOT32O:
-		  rela.r_info = ELF32_R_INFO (0, R_68K_RELATIVE);
+		case R_68K_TLS_LDM32:
 		  break;
 
 		case R_68K_TLS_GD32:
-		  rela.r_info = ELF32_R_INFO (0, R_68K_TLS_DTPMOD32);
+		  relocation += dtpoff_base (info);
 		  break;
 
 		case R_68K_TLS_IE32:
-		  rela.r_info = ELF32_R_INFO (0, R_68K_TLS_TPREL32);
+		  relocation += tpoff_base (info);
 		  break;
 
 		default:
 		  BFD_ASSERT (FALSE);
-		  break;
 		}
 
-		elf_m68k_install_rela (output_bfd, srela, &rela);
+	      elf_m68k_init_got_entry_local_shared (info,
+						    output_bfd,
+						    r_type,
+						    sgot,
+						    got_entry_offset,
+						    relocation,
+						    srela);
 	    }
 	  else
 	    {
+	      Elf_Internal_Rela rela;
+
 	      /* Put zeros to GOT slots that will be initialized
 		 at run-time.  */
 	      {
@@ -4327,8 +4369,11 @@ elf_m68k_finish_dynamic_symbol (output_b
 	      }
 
 	      rela.r_addend = 0;
+	      rela.r_offset = (sgot->output_section->vma
+			       + sgot->output_offset
+			       + got_entry_offset);
 
-	      switch (elf_m68k_reloc_got_type (got_entry->key_.type))
+	      switch (elf_m68k_reloc_got_type (r_type))
 		{
 		case R_68K_GOT32O:
 		  rela.r_info = ELF32_R_INFO (h->dynindx, R_68K_GLOB_DAT);

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