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]

hppa-linux TLS relocs


This patch fixes various problems with TLS relocations.

1) Report an error if a symbol has both TLS and normal GOT entries.
2) The GOT entry size calculation was obscure and made use of the fact
   that a symbol shouldn't have both normal and TLS GOT entries.
3) The second word of a GD GOT entry sometimes omitted a dynamic
   reloc, which was fine except that doing so makes it impossible for
   ld.so to differentiate GD and LD entries.  Also, a NONE reloc was
   emitted.
4) Unnecessary relocs were emitted for GOT entries.
5) GOT relocs didn't take note of UNDEFWEAK_NO_DYNAMIC_RELOC.

Point (4) caused FAIL: Build pr22263-1

	* elf32-hppa.c (enum _tls_type): Move.
	(struct elf32_hppa_link_hash_entry): Make tls_type a bitfield.
	(elf32_hppa_check_relocs): Set DF_STATIC_TLS only for shared libraries.
	Tidy tls_type handling.  Set symbol tls_type for GOT_TLS_LDM too.
	(got_entries_needed, got_relocs_needed): New functions.
	(allocate_dynrelocs): Use them.
	(elf32_hppa_size_dynamic_sections): Likewise.
	(elf32_hppa_relocate_section): Delete bogus FIXME.  Formatting.
	Correct code emitting relocs on GD/IE got entries.  Report an
	error when a symbol has both normal and TLS GOT relocs.

diff --git a/bfd/elf32-hppa.c b/bfd/elf32-hppa.c
index acc96af..f9629e4 100644
--- a/bfd/elf32-hppa.c
+++ b/bfd/elf32-hppa.c
@@ -206,6 +206,15 @@ struct elf32_hppa_stub_hash_entry
   asection *id_sec;
 };
 
+enum _tls_type
+  {
+    GOT_UNKNOWN = 0,
+    GOT_NORMAL = 1,
+    GOT_TLS_GD = 2,
+    GOT_TLS_LDM = 4,
+    GOT_TLS_IE = 8
+  };
+
 struct elf32_hppa_link_hash_entry
 {
   struct elf_link_hash_entry eh;
@@ -233,10 +242,7 @@ struct elf32_hppa_link_hash_entry
 #endif
   } *dyn_relocs;
 
-  enum
-  {
-    GOT_UNKNOWN = 0, GOT_NORMAL = 1, GOT_TLS_GD = 2, GOT_TLS_LDM = 4, GOT_TLS_IE = 8
-  } tls_type;
+  ENUM_BITFIELD (_tls_type) tls_type : 8;
 
   /* Set if this symbol is used by a plabel reloc.  */
   unsigned int plabel:1;
@@ -1132,7 +1138,6 @@ elf32_hppa_check_relocs (bfd *abfd,
   const Elf_Internal_Rela *rela_end;
   struct elf32_hppa_link_hash_table *htab;
   asection *sreloc;
-  int tls_type = GOT_UNKNOWN, old_tls_type = GOT_UNKNOWN;
 
   if (bfd_link_relocatable (info))
     return TRUE;
@@ -1312,7 +1317,7 @@ elf32_hppa_check_relocs (bfd *abfd,
 
 	case R_PARISC_TLS_IE21L:
 	case R_PARISC_TLS_IE14R:
-	  if (bfd_link_pic (info))
+	  if (bfd_link_dll (info))
             info->flags |= DF_STATIC_TLS;
 	  need_entry = NEED_GOT;
 	  break;
@@ -1324,22 +1329,23 @@ elf32_hppa_check_relocs (bfd *abfd,
       /* Now carry out our orders.  */
       if (need_entry & NEED_GOT)
 	{
+	  int tls_type = GOT_NORMAL;
+
 	  switch (r_type)
 	    {
 	    default:
-	      tls_type = GOT_NORMAL;
 	      break;
 	    case R_PARISC_TLS_GD21L:
 	    case R_PARISC_TLS_GD14R:
-	      tls_type |= GOT_TLS_GD;
+	      tls_type = GOT_TLS_GD;
 	      break;
 	    case R_PARISC_TLS_LDM21L:
 	    case R_PARISC_TLS_LDM14R:
-	      tls_type |= GOT_TLS_LDM;
+	      tls_type = GOT_TLS_LDM;
 	      break;
 	    case R_PARISC_TLS_IE21L:
 	    case R_PARISC_TLS_IE14R:
-	      tls_type |= GOT_TLS_IE;
+	      tls_type = GOT_TLS_IE;
 	      break;
 	    }
 
@@ -1351,39 +1357,28 @@ elf32_hppa_check_relocs (bfd *abfd,
 		return FALSE;
 	    }
 
-	  if (r_type == R_PARISC_TLS_LDM21L
-	      || r_type == R_PARISC_TLS_LDM14R)
-	    htab->tls_ldm_got.refcount += 1;
-	  else
+	  if (hh != NULL)
 	    {
-	      if (hh != NULL)
-	        {
-	          hh->eh.got.refcount += 1;
-	          old_tls_type = hh->tls_type;
-	        }
+	      if (tls_type == GOT_TLS_LDM)
+		htab->tls_ldm_got.refcount += 1;
 	      else
-	        {
-	          bfd_signed_vma *local_got_refcounts;
-
-	          /* This is a global offset table entry for a local symbol.  */
-	          local_got_refcounts = hppa32_elf_local_refcounts (abfd);
-	          if (local_got_refcounts == NULL)
-		    return FALSE;
-	          local_got_refcounts[r_symndx] += 1;
-
-	          old_tls_type = hppa_elf_local_got_tls_type (abfd) [r_symndx];
-	        }
-
-	      tls_type |= old_tls_type;
+		hh->eh.got.refcount += 1;
+	      hh->tls_type |= tls_type;
+	    }
+	  else
+	    {
+	      bfd_signed_vma *local_got_refcounts;
 
-	      if (old_tls_type != tls_type)
-	        {
-	          if (hh != NULL)
-		    hh->tls_type = tls_type;
-	          else
-		    hppa_elf_local_got_tls_type (abfd) [r_symndx] = tls_type;
-	        }
+	      /* This is a global offset table entry for a local symbol.  */
+	      local_got_refcounts = hppa32_elf_local_refcounts (abfd);
+	      if (local_got_refcounts == NULL)
+		return FALSE;
+	      if (tls_type == GOT_TLS_LDM)
+		htab->tls_ldm_got.refcount += 1;
+	      else
+		local_got_refcounts[r_symndx] += 1;
 
+	      hppa_elf_local_got_tls_type (abfd) [r_symndx] |= tls_type;
 	    }
 	}
 
@@ -1916,6 +1911,39 @@ allocate_plt_static (struct elf_link_hash_entry *eh, void *inf)
   return TRUE;
 }
 
+/* Calculate size of GOT entries for symbol given its TLS_TYPE.  */
+
+static inline unsigned int
+got_entries_needed (int tls_type)
+{
+  unsigned int need = 0;
+
+  if ((tls_type & GOT_NORMAL) != 0)
+    need += GOT_ENTRY_SIZE;
+  if ((tls_type & GOT_TLS_GD) != 0)
+    need += GOT_ENTRY_SIZE * 2;
+  if ((tls_type & GOT_TLS_IE) != 0)
+    need += GOT_ENTRY_SIZE;
+  return need;
+}
+
+/* Calculate size of relocs needed for symbol given its TLS_TYPE and
+   NEEDed GOT entries.  KNOWN says a TPREL offset can be calculated
+   at link time.  */
+
+static inline unsigned int
+got_relocs_needed (int tls_type, unsigned int need, bfd_boolean known)
+{
+  /* All the entries we allocated need relocs.
+     Except IE in executable with a local symbol.  We could also omit
+     the DTPOFF reloc on the second word of a GD entry under the same
+     condition as that for IE, but ld.so might want to differentiate
+     LD and GD entries at some stage.  */
+  if ((tls_type & GOT_TLS_IE) != 0 && known)
+    need -= GOT_ENTRY_SIZE;
+  return need * sizeof (Elf32_External_Rela) / GOT_ENTRY_SIZE;
+}
+
 /* Allocate space in .plt, .got and associated reloc sections for
    global syms.  */
 
@@ -1955,28 +1983,25 @@ allocate_dynrelocs (struct elf_link_hash_entry *eh, void *inf)
 
   if (eh->got.refcount > 0)
     {
+      unsigned int need;
+
       if (!ensure_undef_dynamic (info, eh))
 	return FALSE;
 
       sec = htab->etab.sgot;
       eh->got.offset = sec->size;
-      sec->size += GOT_ENTRY_SIZE;
-      /* R_PARISC_TLS_GD* needs two GOT entries */
-      if ((hh->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
-      	sec->size += GOT_ENTRY_SIZE * 2;
-      else if ((hh->tls_type & GOT_TLS_GD) == GOT_TLS_GD)
-      	sec->size += GOT_ENTRY_SIZE;
+      need = got_entries_needed (hh->tls_type);
+      sec->size += need;
       if (htab->etab.dynamic_sections_created
 	  && (bfd_link_pic (info)
 	      || (eh->dynindx != -1
 		  && !SYMBOL_REFERENCES_LOCAL (info, eh)))
 	  && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
 	{
-	  htab->etab.srelgot->size += sizeof (Elf32_External_Rela);
-	  if ((hh->tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
-	    htab->etab.srelgot->size += 2 * sizeof (Elf32_External_Rela);
-	  else if ((hh->tls_type & GOT_TLS_GD) == GOT_TLS_GD)
-	    htab->etab.srelgot->size += sizeof (Elf32_External_Rela);
+	  bfd_boolean tprel_known = (bfd_link_executable (info)
+				     && SYMBOL_REFERENCES_LOCAL (info, eh));
+	  htab->etab.srelgot->size
+	    += got_relocs_needed (hh->tls_type, need, tprel_known);
 	}
     }
   else
@@ -2195,20 +2220,17 @@ elf32_hppa_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
 	{
 	  if (*local_got > 0)
 	    {
+	      unsigned int need;
+
 	      *local_got = sec->size;
-	      sec->size += GOT_ENTRY_SIZE;
-	      if ((*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
-		sec->size += 2 * GOT_ENTRY_SIZE;
-	      else if ((*local_tls_type & GOT_TLS_GD) == GOT_TLS_GD)
-		sec->size += GOT_ENTRY_SIZE;
+	      need = got_entries_needed (*local_tls_type);
+	      sec->size += need;
 	      if (bfd_link_pic (info))
-	        {
-		  srel->size += sizeof (Elf32_External_Rela);
-		  if ((*local_tls_type & (GOT_TLS_GD | GOT_TLS_IE)) == (GOT_TLS_GD | GOT_TLS_IE))
-		    srel->size += 2 * sizeof (Elf32_External_Rela);
-		  else if ((*local_tls_type & GOT_TLS_GD) == GOT_TLS_GD)
-		    srel->size += sizeof (Elf32_External_Rela);
-	        }
+		{
+		  bfd_boolean tprel_known = bfd_link_executable (info);
+		  htab->etab.srelgot->size
+		    += got_relocs_needed (*local_tls_type, need, tprel_known);
+		}
 	    }
 	  else
 	    *local_got = (bfd_vma) -1;
@@ -4025,17 +4047,17 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 	    indx = 0;
 	    if (hh != NULL)
 	      {
-	        bfd_boolean dyn;
-	        dyn = htab->etab.dynamic_sections_created;
-
-		if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn,
-						     bfd_link_pic (info),
-						     &hh->eh)
-		    && (!bfd_link_pic (info)
-			|| !SYMBOL_REFERENCES_LOCAL (info, &hh->eh)))
-		  {
-		    indx = hh->eh.dynindx;
-		  }
+		if (!htab->etab.dynamic_sections_created
+		    || hh->eh.dynindx == -1
+		    || SYMBOL_REFERENCES_LOCAL (info, &hh->eh)
+		    || UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh))
+		  /* 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.  */
+		  ;
+		else
+		  indx = hh->eh.dynindx;
 		off = hh->eh.got.offset;
 		tls_type = hh->tls_type;
 	      }
@@ -4061,44 +4083,41 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 	           now, and emit any relocations.  If both an IE GOT and a
 	           GD GOT are necessary, we emit the GD first.  */
 
-		if ((bfd_link_pic (info) || indx != 0)
-		    && (hh == NULL
-			|| ELF_ST_VISIBILITY (hh->eh.other) == STV_DEFAULT
-			|| hh->eh.root.type != bfd_link_hash_undefweak))
+		if (indx != 0
+		    || (bfd_link_pic (info)
+			&& (hh == NULL
+			    || !UNDEFWEAK_NO_DYNAMIC_RELOC (info, &hh->eh))))
 		  {
 		    need_relocs = TRUE;
 		    loc = htab->etab.srelgot->contents;
-		    /* FIXME (CAO): Should this be reloc_count++ ? */
-		    loc += htab->etab.srelgot->reloc_count * sizeof (Elf32_External_Rela);
+		    loc += (htab->etab.srelgot->reloc_count
+			    * sizeof (Elf32_External_Rela));
 		  }
 
 		if (tls_type & GOT_TLS_GD)
 		  {
 		    if (need_relocs)
 		      {
-			outrel.r_offset = (cur_off
-					   + htab->etab.sgot->output_section->vma
-					   + htab->etab.sgot->output_offset);
-			outrel.r_info = ELF32_R_INFO (indx,R_PARISC_TLS_DTPMOD32);
+			outrel.r_offset
+			  = (cur_off
+			     + htab->etab.sgot->output_section->vma
+			     + htab->etab.sgot->output_offset);
+			outrel.r_info
+			  = ELF32_R_INFO (indx, R_PARISC_TLS_DTPMOD32);
 			outrel.r_addend = 0;
-			bfd_put_32 (output_bfd, 0, htab->etab.sgot->contents + cur_off);
 			bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 			htab->etab.srelgot->reloc_count++;
 			loc += sizeof (Elf32_External_Rela);
-
-			if (indx == 0)
-			  bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
-				      htab->etab.sgot->contents + cur_off + 4);
-			else
-			  {
-			    bfd_put_32 (output_bfd, 0,
-					htab->etab.sgot->contents + cur_off + 4);
-			    outrel.r_info = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
-			    outrel.r_offset += 4;
-			    bfd_elf32_swap_reloca_out (output_bfd, &outrel,loc);
-			    htab->etab.srelgot->reloc_count++;
-			    loc += sizeof (Elf32_External_Rela);
-			  }
+			outrel.r_info
+			  = ELF32_R_INFO (indx, R_PARISC_TLS_DTPOFF32);
+			outrel.r_offset += 4;
+			bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
+			htab->etab.srelgot->reloc_count++;
+			loc += sizeof (Elf32_External_Rela);
+			bfd_put_32 (output_bfd, 0,
+				    htab->etab.sgot->contents + cur_off);
+			bfd_put_32 (output_bfd, 0,
+				    htab->etab.sgot->contents + cur_off + 4);
 		      }
 		    else
 		      {
@@ -4109,28 +4128,28 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 		           to module 1, the executable.  */
 		        bfd_put_32 (output_bfd, 1,
 				    htab->etab.sgot->contents + cur_off);
-		        bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
+			bfd_put_32 (output_bfd, relocation - dtpoff_base (info),
 				    htab->etab.sgot->contents + cur_off + 4);
 		      }
-
-
 		    cur_off += 8;
 		  }
 
 		if (tls_type & GOT_TLS_IE)
 		  {
-		    if (need_relocs)
+		    if (need_relocs
+			&& !(bfd_link_executable (info)
+			     && SYMBOL_REFERENCES_LOCAL (info, &hh->eh)))
 		      {
-			outrel.r_offset = (cur_off
-					   + htab->etab.sgot->output_section->vma
-					   + htab->etab.sgot->output_offset);
-			outrel.r_info = ELF32_R_INFO (indx, R_PARISC_TLS_TPREL32);
-
+			outrel.r_offset
+			  = (cur_off
+			     + htab->etab.sgot->output_section->vma
+			     + htab->etab.sgot->output_offset);
+			outrel.r_info = ELF32_R_INFO (indx,
+						      R_PARISC_TLS_TPREL32);
 			if (indx == 0)
 			  outrel.r_addend = relocation - dtpoff_base (info);
 			else
 			  outrel.r_addend = 0;
-
 			bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc);
 			htab->etab.srelgot->reloc_count++;
 			loc += sizeof (Elf32_External_Rela);
@@ -4138,7 +4157,6 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 		    else
 		      bfd_put_32 (output_bfd, tpoff (info, relocation),
 				  htab->etab.sgot->contents + cur_off);
-
 		    cur_off += 4;
 		  }
 
@@ -4148,6 +4166,35 @@ elf32_hppa_relocate_section (bfd *output_bfd,
 		  local_got_offsets[r_symndx] |= 1;
 	      }
 
+	    if ((tls_type & GOT_NORMAL) != 0
+		&& (tls_type & (GOT_TLS_GD | GOT_TLS_LDM | GOT_TLS_IE)) != 0)
+	      {
+		if (hh != NULL)
+		  _bfd_error_handler (_("%s has both normal and TLS relocs"),
+				      hh_name (hh));
+		else
+		  {
+		    Elf_Internal_Sym *isym
+		      = bfd_sym_from_r_symndx (&htab->sym_cache,
+					       input_bfd, r_symndx);
+		    if (isym == NULL)
+		      return FALSE;
+		    sym_name
+		      = bfd_elf_string_from_elf_section (input_bfd,
+							 symtab_hdr->sh_link,
+							 isym->st_name);
+		    if (sym_name == NULL)
+		      return FALSE;
+		    if (*sym_name == '\0')
+		      sym_name = bfd_section_name (input_bfd, sym_sec);
+		    _bfd_error_handler
+		      (_("%B:%s has both normal and TLS relocs"),
+		       input_bfd, sym_name);
+		  }
+		bfd_set_error (bfd_error_bad_value);
+		return FALSE;
+	      }
+
 	    if ((tls_type & GOT_TLS_GD)
 	  	&& r_type != R_PARISC_TLS_GD21L
 	  	&& r_type != R_PARISC_TLS_GD14R)
@@ -4290,8 +4337,7 @@ elf32_hppa_finish_dynamic_symbol (bfd *output_bfd,
     }
 
   if (eh->got.offset != (bfd_vma) -1
-      && (hppa_elf_hash_entry (eh)->tls_type & GOT_TLS_GD) == 0
-      && (hppa_elf_hash_entry (eh)->tls_type & GOT_TLS_IE) == 0
+      && (hppa_elf_hash_entry (eh)->tls_type & GOT_NORMAL) != 0
       && !UNDEFWEAK_NO_DYNAMIC_RELOC (info, eh))
     {
       bfd_boolean is_dyn = (eh->dynindx != -1

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