.reloc improvement

Alan Modra amodra@gmail.com
Thu Aug 18 14:08:00 GMT 2011
This patch makes some improvements to relocations emitted by the
.reloc directive:
1) A symbol on these relocs is converted to section symbol plus offset
   if the symbol satisifes S_IS_LOCAL and some section related
   conditions.  For example, forward/backward labels like "1f", and
   ELF locals like .L123 will be converted.  This helps keep the
   symbol table tidy.
2) These relocations are merge sorted with the normal fixup relocs,
   instead of being emitted after the fixup relocs.  A merge sort
   ought to be sufficient;  If someone generates .reloc with offsets
   out of order then I'd say they obviously don't care about reloc
   sorting!
3) Time taken to find .reloc frags should be considerably better
   than it used to be.

	* write.c (resolve_reloc_expr_symbols): Convert local symbols
	on relocs to section+offset.
	(get_frag_for_reloc): New function.
	(write_relocs): Merge sort fixup relocs with those from .reloc
	directives.

Index: gas/write.c
===================================================================
RCS file: /cvs/src/src/gas/write.c,v
retrieving revision 1.144
diff -u -p -r1.144 write.c
--- gas/write.c	4 Aug 2011 20:53:58 -0000	1.144
+++ gas/write.c	18 Aug 2011 13:25:23 -0000
@@ -708,7 +708,20 @@ resolve_reloc_expr_symbols (void)
 	      sec = NULL;
 	    }
 	  else if (sym != NULL)
-	    symbol_mark_used_in_reloc (sym);
+	    {
+	      if (S_IS_LOCAL (sym) && !symbol_section_p (sym))
+		{
+		  asection *symsec = S_GET_SEGMENT (sym);
+		  if (!(((symsec->flags & SEC_MERGE) != 0
+			 && addend != 0)
+			|| (symsec->flags & SEC_THREAD_LOCAL) != 0))
+		    {
+		      addend += S_GET_VALUE (sym);
+		      sym = section_symbol (symsec);
+		    }
+		}
+	      symbol_mark_used_in_reloc (sym);
+	    }
 	}
       if (sym == NULL)
 	{
@@ -1146,15 +1159,37 @@ install_reloc (asection *sec, arelent *r
     }
 }
 
+static fragS *
+get_frag_for_reloc (fragS *last_frag,
+		    const segment_info_type *seginfo,
+		    const struct reloc_list *r)
+{
+  fragS *f;
+  
+  for (f = last_frag; f != NULL; f = f->fr_next)
+    if (f->fr_address <= r->u.b.r.address
+	&& r->u.b.r.address < f->fr_address + f->fr_fix)
+      return f;
+
+  for (f = seginfo->frchainP->frch_root; f != NULL; f = f->fr_next)
+    if (f->fr_address <= r->u.b.r.address
+	&& r->u.b.r.address < f->fr_address + f->fr_fix)
+      return f;
+
+  as_bad_where (r->file, r->line,
+		_("reloc not within (fixed part of) section"));
+  return NULL;
+}
+
 static void
 write_relocs (bfd *abfd, asection *sec, void *xxx ATTRIBUTE_UNUSED)
 {
   segment_info_type *seginfo = seg_info (sec);
-  unsigned int i;
   unsigned int n;
   struct reloc_list *my_reloc_list, **rp, *r;
   arelent **relocs;
   fixS *fixp;
+  fragS *last_frag;
 
   /* If seginfo is NULL, we did not create this section; don't do
      anything with it.  */
@@ -1188,12 +1223,19 @@ write_relocs (bfd *abfd, asection *sec, 
 
   relocs = (arelent **) xcalloc (n, sizeof (arelent *));
 
-  i = 0;
+  n = 0;
+  r = my_reloc_list;
+  last_frag = NULL;
   for (fixp = seginfo->fix_root; fixp != (fixS *) NULL; fixp = fixp->fx_next)
     {
-      int j;
       int fx_size, slack;
       offsetT loc;
+      arelent **reloc;
+#ifndef RELOC_EXPANSION_POSSIBLE
+      arelent *rel;
+
+      reloc = &rel;
+#endif
 
       if (fixp->fx_done)
 	continue;
@@ -1208,28 +1250,46 @@ write_relocs (bfd *abfd, asection *sec, 
 		      _("internal error: fixup not contained within frag"));
 
 #ifndef RELOC_EXPANSION_POSSIBLE
-      {
-	arelent *reloc = tc_gen_reloc (sec, fixp);
-
-	if (!reloc)
-	  continue;
-	relocs[i++] = reloc;
-	j = 1;
-      }
+      *reloc = tc_gen_reloc (sec, fixp);
 #else
-      {
-	arelent **reloc = tc_gen_reloc (sec, fixp);
+      reloc = tc_gen_reloc (sec, fixp);
+#endif
 
-	for (j = 0; reloc[j]; j++)
-	  relocs[i++] = reloc[j];
-      }
+      while (*reloc)
+	{
+	  while (r != NULL && r->u.b.r.address < (*reloc)->address)
+	    {
+	      fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
+	      if (f != NULL)
+		{
+		  last_frag = f;
+		  relocs[n++] = &r->u.b.r;
+		  install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+		}
+	      r = r->next;
+	    }
+	  relocs[n++] = *reloc;
+	  install_reloc (sec, *reloc, fixp->fx_frag,
+			 fixp->fx_file, fixp->fx_line);
+#ifndef RELOC_EXPANSION_POSSIBLE
+	  break;
+#else
+	  reloc++;
 #endif
+	}
+    }
 
-      for ( ; j != 0; --j)
-	install_reloc (sec, relocs[i - j], fixp->fx_frag,
-		       fixp->fx_file, fixp->fx_line);
+  while (r != NULL)
+    {
+      fragS *f = get_frag_for_reloc (last_frag, seginfo, r);
+      if (f != NULL)
+	{
+	  last_frag = f;
+	  relocs[n++] = &r->u.b.r;
+	  install_reloc (sec, &r->u.b.r, f, r->file, r->line);
+	}
+      r = r->next;
     }
-  n = i;
 
 #ifdef DEBUG4
   {
@@ -1249,23 +1309,6 @@ write_relocs (bfd *abfd, asection *sec, 
   }
 #endif
 
-  for (r = my_reloc_list; r != NULL; r = r->next)
-    {
-      fragS *f;
-      for (f = seginfo->frchainP->frch_root; f; f = f->fr_next)
-	if (f->fr_address <= r->u.b.r.address
-	    && r->u.b.r.address < f->fr_address + f->fr_fix)
-	  break;
-      if (f == NULL)
-	as_bad_where (r->file, r->line,
-		      _("reloc not within (fixed part of) section"));
-      else
-	{
-	  relocs[n++] = &r->u.b.r;
-	  install_reloc (sec, &r->u.b.r, f, r->file, r->line);
-	}
-    }
-
   if (n)
     {
       flagword flags = bfd_get_section_flags (abfd, sec);

-- 
Alan Modra
Australia Development Lab, IBM



More information about the Binutils mailing list