This is the mail archive of the binutils@sources.redhat.com 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]

Re: telling symbols defined only in the linker script


On Mar  1, 2004, Alexandre Oliva <aoliva@redhat.com> wrote:

> I've run into a problem in FR-V FDPIC, while linking static
> executables, if a symbol is weak-referenced but not defined except for
> an assignment in a linker script.  We fail to allocate a rofixup entry
> for it, because at size_dynamic_sections() time it's still undefweak,
> but when we get to the point of emitting rofixups, it's become
> defined, so we emit a rofixup and end up missing entries at the end.

This patch fixes a problem that I thought at first was the one biting
me: in case one symbol is an alias to another, but we have PIC
relocations referencing both of them, we have to merge them into a
single entry, instead of possibly enabling one of the entries to hide
or overwrite the other.

Since the problem I had was unrelated, I ended up adding some code to
verify that no symbol gets more dynamic relocations or rofixup entries
than originally reserved.  Here's the patch that enabled me to figure
out exactly which symbol it was that was getting more entries than
originally reserved.  It adds some needless overhead, so perhaps it
should be conditionally compiled, but the overhead isn't all that
significant, and it's a nice sanity check, so I propose that we
compile it in unconditionally.

Ok to install?

Index: bfd/ChangeLog
from  Alexandre Oliva  <aoliva@redhat.com>

	* elf32-frv.c (struct frv_pic_relocs_info): Added fixups and
	dynrelocs.
	(_frv_count_got_plt_entries): Initialize them.
	(frv_pic_relocs_info_find): Add insert argument.  Adjust all
	callers.
	(frv_pic_relocs_info_for_global): Likewise.
	(frv_pic_relocs_info_for_local): Likewise.
	(frv_pic_merge_early_relocs_info): New.
	(_frv_resolve_final_relocs_info): Use it in case one entry maps to
	another.
	(_frv_add_dyn_reloc): Add entry argument.  Adjust all callers.
	Check that we don't exceed the allocated count for entry.
	(_frv_add_rofixup): Likewise.
	(_frv_emit_got_relocs_plt_entries): Adjust for coding standards.
	(elf32_frv_finish_dynamic_sections): Improve error message in case
	we emit too few rofixup entries.

Index: bfd/elf32-frv.c
===================================================================
RCS file: /cvs/uberbaum/bfd/elf32-frv.c,v
retrieving revision 1.16
diff -u -p -r1.16 elf32-frv.c
--- bfd/elf32-frv.c 1 Mar 2004 10:11:38 -0000 1.16
+++ bfd/elf32-frv.c 1 Mar 2004 12:21:39 -0000
@@ -748,6 +748,10 @@ struct frv_pic_relocs_info
      relocations referencing the symbol.  */
   unsigned relocs32, relocsfd, relocsfdv;
 
+  /* The number of .rofixups entries and dynamic relocations allocated
+     for this symbol, minus any that might have already been used.  */
+  unsigned fixups, dynrelocs;
+
   /* The offsets of the GOT entries assigned to symbol+addend, to the
      function descriptor's address, and to a function descriptor,
      respectively.  Should be zero if unassigned.  The offsets are
@@ -789,10 +793,14 @@ frv_pic_relocs_info_eq (const void *entr
 static struct frv_pic_relocs_info *
 frv_pic_relocs_info_find (struct htab *ht,
 			  bfd *abfd,
-			  const struct frv_pic_relocs_info *entry)
+			  const struct frv_pic_relocs_info *entry,
+			  enum insert_option insert)
 {
   struct frv_pic_relocs_info **loc =
-    (struct frv_pic_relocs_info **) htab_find_slot (ht, entry, INSERT);
+    (struct frv_pic_relocs_info **) htab_find_slot (ht, entry, insert);
+
+  if (! loc)
+    return NULL;
 
   if (*loc)
     return *loc;
@@ -818,7 +826,8 @@ inline static struct frv_pic_relocs_info
 frv_pic_relocs_info_for_global (struct htab *ht,
 				bfd *abfd,
 				struct elf_link_hash_entry *h,
-				bfd_vma addend)
+				bfd_vma addend,
+				enum insert_option insert)
 {
   struct frv_pic_relocs_info entry;
 
@@ -826,7 +835,7 @@ frv_pic_relocs_info_for_global (struct h
   entry.d.h = h;
   entry.addend = addend;
 
-  return frv_pic_relocs_info_find (ht, abfd, &entry);
+  return frv_pic_relocs_info_find (ht, abfd, &entry, insert);
 }
 
 /* Obtain the address of the entry in HT associated with the SYMNDXth
@@ -836,7 +845,8 @@ inline static struct frv_pic_relocs_info
 frv_pic_relocs_info_for_local (struct htab *ht,
 			       bfd *abfd,
 			       long symndx,
-			       bfd_vma addend)
+			       bfd_vma addend,
+			       enum insert_option insert)
 {
   struct frv_pic_relocs_info entry;
 
@@ -844,7 +854,59 @@ frv_pic_relocs_info_for_local (struct ht
   entry.d.abfd = abfd;
   entry.addend = addend;
 
-  return frv_pic_relocs_info_find (ht, abfd, &entry);
+  return frv_pic_relocs_info_find (ht, abfd, &entry, insert);
+}
+
+/* Merge fields set by check_relocs() of two entries that end up being
+   mapped to the same (presumably global) symbol.  */
+
+inline static void
+frv_pic_merge_early_relocs_info (struct frv_pic_relocs_info *e2,
+				 struct frv_pic_relocs_info const *e1)
+{
+  e2->got12 |= e1->got12;
+  e2->gotlos |= e1->gotlos;
+  e2->gothilo |= e1->gothilo;
+  e2->fd |= e1->fd;
+  e2->fdgot12 |= e1->fdgot12;
+  e2->fdgotlos |= e1->fdgotlos;
+  e2->fdgothilo |= e1->fdgothilo;
+  e2->fdgoff12 |= e1->fdgoff12;
+  e2->fdgofflos |= e1->fdgofflos;
+  e2->fdgoffhilo |= e1->fdgoffhilo;
+  e2->gotoff |= e1->gotoff;
+  e2->call |= e1->call;
+  e2->sym |= e1->sym;
+
+#if 0
+  /* These are set in _frv_count_got_plt_entries() or later, and this
+     function is only called in _frv_resolve_final_relocs_info(), that
+     runs just before it, so we don't have to worry about the fields
+     below.  */
+
+  e2->plt |= e1->plt;
+  e2->privfd |= e1->privfd;
+  e2->lazyplt |= e1->lazyplt;
+  e2->done |= e1->done;
+
+  e2->relocs32 += e1->relocs32;
+  e2->relocsfd += e1->relocsfd;
+  e2->relocsfdv += e1->relocsfdv;
+  e2->fixups += e1->fixups;
+  e2->dynrelocs += e1->dynrelocs;
+
+  if (abs (e1->got_entry) < abs (e2->got_entry))
+    e2->got_entry = e1->got_entry;
+  if (abs (e1->fdgot_entry) < abs (e2->fdgot_entry))
+    e2->fdgot_entry = e1->fdgot_entry;
+  if (abs (e1->fd_entry) < abs (e2->fd_entry))
+    e2->fd_entry = e1->fd_entry;
+
+  if (e1->plt_entry < e2->plt_entry)
+    e2->plt_entry = e1->plt_entry;
+  if (e1->lzplt_entry < e2->lzplt_entry)
+    e2->lzplt_entry = e1->lzplt_entry;
+#endif
 }
 
 /* Every block of 65535 lazy PLT entries shares a single call to the
@@ -859,7 +921,8 @@ frv_pic_relocs_info_for_local (struct ht
 
 inline static bfd_vma
 _frv_add_dyn_reloc (bfd *output_bfd, asection *sreloc, bfd_vma offset,
-		    int reloc_type, long dynindx, bfd_vma addend)
+		    int reloc_type, long dynindx, bfd_vma addend,
+		    struct frv_pic_relocs_info *entry)
 {
   Elf_Internal_Rela outrel;
   bfd_vma reloc_offset;
@@ -874,13 +937,17 @@ _frv_add_dyn_reloc (bfd *output_bfd, ase
 			    sreloc->contents + reloc_offset);
   sreloc->reloc_count++;
 
+  BFD_ASSERT (entry->dynrelocs > 0);
+  entry->dynrelocs--;
+
   return reloc_offset;
 }
 
 /* Add a fixup to the ROFIXUP section.  */
 
 static bfd_vma
-_frv_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset)
+_frv_add_rofixup (bfd *output_bfd, asection *rofixup, bfd_vma offset,
+		  struct frv_pic_relocs_info *entry)
 {
   bfd_vma fixup_offset;
 
@@ -894,7 +961,13 @@ _frv_add_rofixup (bfd *output_bfd, asect
       bfd_put_32 (output_bfd, offset, rofixup->contents + fixup_offset);
     }
   rofixup->reloc_count++;
-	      
+
+  if (entry)
+    {
+      BFD_ASSERT (entry->fixups > 0);
+      entry->fixups--;
+    }
+
   return fixup_offset;
 }
 
@@ -999,13 +1072,13 @@ _frv_emit_got_relocs_plt_entries (struct
 	{
 	  if (sec)
 	    ad += sec->output_section->vma;
-	  if (entry->symndx != -1 ||
-	      entry->d.h->root.type != bfd_link_hash_undefweak)
+	  if (entry->symndx != -1
+	      || entry->d.h->root.type != bfd_link_hash_undefweak)
 	    _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
 			      frv_got_section (info)->output_section->vma
 			      + frv_got_section (info)->output_offset
 			      + frv_got_initial_offset (info)
-			      + entry->got_entry);
+			      + entry->got_entry, entry);
 	}
       else
 	_frv_add_dyn_reloc (output_bfd, frv_gotrel_section (info),
@@ -1016,7 +1089,7 @@ _frv_emit_got_relocs_plt_entries (struct
 			     + entry->got_entry)
 			    + frv_got_section (info)->output_section->vma
 			    + frv_got_section (info)->output_offset,
-			    R_FRV_32, idx, ad);
+			    R_FRV_32, idx, ad, entry);
 	
       bfd_put_32 (output_bfd, ad,
 		  frv_got_section (info)->contents
@@ -1089,7 +1162,7 @@ _frv_emit_got_relocs_plt_entries (struct
 				frv_got_section (info)->output_section->vma
 				+ frv_got_section (info)->output_offset
 				+ frv_got_initial_offset (info)
-				+ entry->fdgot_entry);
+				+ entry->fdgot_entry, entry);
 	    }
 	  else
 	    _frv_add_dyn_reloc (output_bfd, frv_gotrel_section (info),
@@ -1100,7 +1173,7 @@ _frv_emit_got_relocs_plt_entries (struct
 				 + entry->fdgot_entry)
 				+ frv_got_section (info)->output_section->vma
 				+ frv_got_section (info)->output_offset,
-				reloc, idx, ad);
+				reloc, idx, ad, entry);
 	}
 
       bfd_put_32 (output_bfd, ad,
@@ -1142,19 +1215,19 @@ _frv_emit_got_relocs_plt_entries (struct
 	  if (sec)
 	    ad += sec->output_section->vma;
 	  ofst = 0;
-	  if (entry->symndx != -1 ||
-	      entry->d.h->root.type != bfd_link_hash_undefweak)
+	  if (entry->symndx != -1
+	      || entry->d.h->root.type != bfd_link_hash_undefweak)
 	    {
 	      _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
 				frv_got_section (info)->output_section->vma
 				+ frv_got_section (info)->output_offset
 				+ frv_got_initial_offset (info)
-				+ entry->fd_entry);
+				+ entry->fd_entry, entry);
 	      _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
 				frv_got_section (info)->output_section->vma
 				+ frv_got_section (info)->output_offset
 				+ frv_got_initial_offset (info)
-				+ entry->fd_entry + 4);
+				+ entry->fd_entry + 4, entry);
 	    }
 	}
       else
@@ -1170,7 +1243,7 @@ _frv_emit_got_relocs_plt_entries (struct
 				 + entry->fd_entry)
 				+ frv_got_section (info)->output_section->vma
 				+ frv_got_section (info)->output_offset,
-				R_FRV_FUNCDESC_VALUE, idx, ad);
+				R_FRV_FUNCDESC_VALUE, idx, ad, entry);
 	}
 
       /* If we've omitted the dynamic relocation, just emit the fixed
@@ -1922,14 +1995,14 @@ elf32_frv_relocate_section (output_bfd, 
 	  if (h != NULL)
 	    picrel = frv_pic_relocs_info_for_global (frv_relocs_info (info),
 						     input_bfd, h,
-						     orig_addend);
+						     orig_addend, INSERT);
 	  else
 	    /* In order to find the entry we created before, we must
 	       use the original addend, not the one that may have been
 	       modified by _bfd_elf_rela_local_sym().  */
 	    picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info),
 						    input_bfd, r_symndx,
-						    orig_addend);
+						    orig_addend, INSERT);
 	  if (! picrel)
 	    return FALSE;
 
@@ -2092,7 +2165,8 @@ elf32_frv_relocate_section (output_bfd, 
 					  (output_bfd, info,
 					   input_section, rel->r_offset)
 					  + input_section->output_section->vma
-					  + input_section->output_offset);
+					  + input_section->output_offset,
+					  picrel);
 		      }
 		  }
 		else if ((bfd_get_section_flags (output_bfd,
@@ -2114,7 +2188,7 @@ elf32_frv_relocate_section (output_bfd, 
 					 input_section, rel->r_offset)
 					+ input_section->output_section->vma
 					+ input_section->output_offset,
-					r_type, dynindx, addend);
+					r_type, dynindx, addend, picrel);
 		  }
 	      }
 
@@ -2192,7 +2266,8 @@ elf32_frv_relocate_section (output_bfd, 
 					  (output_bfd, info,
 					   input_section, rel->r_offset)
 					  + input_section->output_section->vma
-					  + input_section->output_offset);
+					  + input_section->output_offset,
+					  picrel);
 			if (r_type == R_FRV_FUNCDESC_VALUE)
 			  _frv_add_rofixup
 			    (output_bfd,
@@ -2201,7 +2276,7 @@ elf32_frv_relocate_section (output_bfd, 
 			     (output_bfd, info,
 			      input_section, rel->r_offset)
 			     + input_section->output_section->vma
-			     + input_section->output_offset + 4);
+			     + input_section->output_offset + 4, picrel);
 		      }
 		  }
 	      }
@@ -2226,7 +2301,7 @@ elf32_frv_relocate_section (output_bfd, 
 					 input_section, rel->r_offset)
 					+ input_section->output_section->vma
 					+ input_section->output_offset,
-					r_type, dynindx, addend);
+					r_type, dynindx, addend, picrel);
 		  }
 		/* We want the addend in-place because dynamic
 		   relocations are REL.  Setting relocation to it
@@ -2806,6 +2881,7 @@ _frv_count_got_plt_entries (void **entry
 {
   struct frv_pic_relocs_info *entry = *entryp;
   struct _frv_dynamic_got_info *dinfo = dinfo_;
+  unsigned relocs = 0, fixups = 0;
 
   /* Allocate space for a GOT entry pointing to the symbol.  */
   if (entry->got12)
@@ -2862,27 +2938,33 @@ _frv_count_got_plt_entries (void **entry
     dinfo->lzplt += 8;
 
   if (!dinfo->info->executable || dinfo->info->pie)
-    dinfo->relocs += entry->relocs32 + entry->relocsfd + entry->relocsfdv;
+    relocs = entry->relocs32 + entry->relocsfd + entry->relocsfdv;
   else
     {
       if (entry->symndx != -1 || FRV_SYM_LOCAL (dinfo->info, entry->d.h))
 	{
 	  if (entry->symndx != -1
-	      || entry->d.h->root.type != bfd_link_hash_undefweak)	  
-	    dinfo->fixups += entry->relocs32 + 2 * entry->relocsfdv;
+	      || entry->d.h->root.type != bfd_link_hash_undefweak)
+	    fixups += entry->relocs32 + 2 * entry->relocsfdv;
 	}
       else
-	dinfo->relocs += entry->relocs32 + entry->relocsfdv;
+	relocs += entry->relocs32 + entry->relocsfdv;
+
       if (entry->symndx != -1 || FRV_FUNCDESC_LOCAL (dinfo->info, entry->d.h))
 	{
 	  if (entry->symndx != -1
 	      || entry->d.h->root.type != bfd_link_hash_undefweak)
-	    dinfo->fixups += entry->relocsfd;
+	    fixups += entry->relocsfd;
 	}
       else
-	dinfo->relocs += entry->relocsfd;
+	relocs += entry->relocsfd;
     }
 
+  entry->dynrelocs += relocs;
+  entry->fixups += fixups;
+  dinfo->relocs += relocs;
+  dinfo->fixups += fixups;
+
   return 1;
 }
 
@@ -3210,6 +3292,7 @@ _frv_resolve_final_relocs_info (void **e
   if (entry->symndx == -1)
     {
       struct elf_link_hash_entry *h = entry->d.h;
+      struct frv_pic_relocs_info *oentry;
 
       while (h->root.type == bfd_link_hash_indirect
 	     || h->root.type == bfd_link_hash_warning)
@@ -3218,6 +3301,17 @@ _frv_resolve_final_relocs_info (void **e
       if (entry->d.h == h)
 	return 1;
 
+      oentry = frv_pic_relocs_info_for_global (*htab, 0, h, entry->addend,
+					       NO_INSERT);
+
+      if (oentry)
+	{
+	  /* Merge the two entries.  */
+	  frv_pic_merge_early_relocs_info (oentry, entry);
+	  htab_clear_slot (*htab, entryp);
+	  return 1;
+	}
+
       entry->d.h = h;
 
       /* If we can't find this entry with the new bfd hash, re-insert
@@ -3581,13 +3675,22 @@ elf32_frv_finish_dynamic_sections (bfd *
 		+ hgot->root.u.def.section->output_offset;
 
 	      _frv_add_rofixup (output_bfd, frv_gotfixup_section (info),
-				got_value);
+				got_value, 0);
 	    }
 
 	  if (frv_gotfixup_section (info)->_raw_size
 	      != (frv_gotfixup_section (info)->reloc_count * 4))
 	    {
-	      if (!elf_hash_table (info)->dynamic_sections_created)
+	      if (frv_gotfixup_section (info)->_raw_size
+		  < frv_gotfixup_section (info)->reloc_count * 4)
+		{
+		  info->callbacks->warning
+		    (info, "LINKER BUG: .rofixup section size mismatch",
+		     ".rofixup", NULL, NULL, 0);
+		  abort ();
+		  return FALSE;
+		}
+	      else if (!elf_hash_table (info)->dynamic_sections_created)
 		{
 		  info->callbacks->warning
 		    (info, "no dynamic sections, missing -melf32frvfd?",
@@ -3931,12 +4034,12 @@ elf32_frv_check_relocs (abfd, info, sec,
 	      picrel
 		= frv_pic_relocs_info_for_global (frv_relocs_info (info),
 						  abfd, h,
-						  rel->r_addend);
+						  rel->r_addend, INSERT);
 	    }
 	  else
 	    picrel = frv_pic_relocs_info_for_local (frv_relocs_info (info),
 						    abfd, r_symndx,
-						    rel->r_addend);
+						    rel->r_addend, INSERT);
 	  if (! picrel)
 	    return FALSE;
 	  break;

-- 
Alexandre Oliva   Enjoy Guarana', see http://www.ic.unicamp.br/~oliva/
Happy GNU Year!                     oliva@{lsd.ic.unicamp.br, gnu.org}
Red Hat GCC Developer                 aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist                Professional serial bug killer

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