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]

Re: PATCH: PR ld/4590: String merging breaks ia64 linker


On Tue, Jun 12, 2007 at 04:02:00PM +0200, Andreas Schwab wrote:
> "H. J. Lu" <hjl@lucon.org> writes:
> 
> > Please try this one.
> >
> > Thanks.
> >
> > H.J.
> > -----
> > 2007-06-12  H.J. Lu  <hongjiu.lu@intel.com>
> >
> > 	PR ld/4590
> > 	* elfxx-ia64.c (sort_dyn_sym_info): Take a new argument for
> > 	string merge.  Keep the valid got_offset when removing
> > 	duplicated entries for string merge
> > 	(get_dyn_sym_info): Initialize the got_offset field to -1.
> > 	Update call to sort_dyn_sym_info.
> > 	(elfNN_ia64_relocate_section): Set addend_merged if the
> > 	addend is merged with another one.  Call sort_dyn_sym_info
> > 	to sort array of addend and remove duplicates.
> 
> Still getting the same assertion failures.
> 

Can you try this one?


H.J.
---
2007-06-12  H.J. Lu  <hongjiu.lu@intel.com>

	PR ld/4590
	* elfxx-ia64.c (sort_dyn_sym_info): Take a new argument for
	string merge.  Keep the valid got_offset when removing
	duplicated entries for string merge
	(get_dyn_sym_info): Initialize the got_offset field to -1.
	Update call to sort_dyn_sym_info.
	(elfNN_ia64_relocate_section): Set addend_merged if the
	addend is merged with another one.  Call sort_dyn_sym_info
	to sort array of addend and remove duplicates.

--- binutils/bfd/elfxx-ia64.c.merge	2007-06-12 05:54:55.000000000 -0700
+++ binutils/bfd/elfxx-ia64.c	2007-06-12 07:46:25.000000000 -0700
@@ -2233,21 +2233,29 @@ addend_compare (const void *xp, const vo
 
 static unsigned int
 sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info,
-		   unsigned int count)
+		   unsigned int count, bfd_boolean merged)
 {
   bfd_vma curr, prev;
-  unsigned int i, dup, diff, dest, src, len;
+  unsigned int i, kept, dup, diff, dest, src, len;
 
   qsort (info, count, sizeof (*info), addend_compare);
 
   /* Find the first duplicate.  */
-  prev = info [0].addend;
+  kept = 0;
+  prev = info [kept].addend;
   for (i = 1; i < count; i++)
     {
       curr = info [i].addend;
       if (curr == prev)
-	break;
+	{
+	  /* If a string is merged with another one, we need to make
+	     sure that KEPT has a valid got_offset.  */
+	  if (merged && info [kept].got_offset == (bfd_vma) -1)
+	    info [kept].got_offset = info [i].got_offset;
+	  break;
+	}
       prev = curr;
+      kept++;
     }
 
   /* Remove duplicates.  */
@@ -2264,8 +2272,14 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn
 	  if (curr == prev)
 	    {
 	      for (src = i + 1; src < count; src++)
-		if (info [src].addend != curr)
-		  break;
+		{
+		  if (info [src].addend != curr)
+		    break;
+		  /* If a string is merged with another one, we need
+		     to make sure that KEPT has a valid got_offset.  */
+		  if (merged && info [kept].got_offset == (bfd_vma) -1)
+		    info [kept].got_offset = info [src].got_offset;
+		}
 	    }
 	  else
 	    src = i;
@@ -2273,13 +2287,19 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn
 	  if (src >= count)
 	    break;
 
-	  /* Find the next duplicate.  */
+	  /* Find the next duplicate.  SRC will be kept.  */
 	  prev = info [src].addend;
 	  for (dup = src + 1; dup < count; dup++)
 	    {
 	      curr = info [dup].addend;
 	      if (curr == prev)
-		break;
+		{
+		  /* If a string is merged with another one, we keep
+		     the valid got_offset in SRC.  */
+		  if (merged && info [src].got_offset == (bfd_vma) -1)
+		    info [src].got_offset = info [dup].got_offset;
+		  break;
+		}
 	      prev = curr;
 	    }
 
@@ -2290,20 +2310,46 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn
 	  if (len == 1 && dup < count)
 	    {
 	      /* If we only move 1 element, we combine it with the next
-		 one.  Find the next different one.  */
+		 one.  We will keep DUP instead of SRC.  Make sure that
+		 DUP has a valid got_offset.  */
+
+	      bfd_vma got_offset = info [src].got_offset;
+
+	      kept = dup;
+
+	      /* Find the next different one.   */
 	      for (diff = dup + 1, src++; diff < count; diff++, src++)
-		if (info [diff].addend != curr)
-		  break;
+		{
+		  if (info [diff].addend != curr)
+		    break;
+		  kept = diff;
+		  /* DIFF may be kept.  If a string is merged with
+		     another one, we need to make sure that a valid
+		     got_offset is kept.  */
+		  if (merged && got_offset == (bfd_vma) -1)
+		    got_offset = info [diff].got_offset;
+		}
+
+	      if (merged && info [kept].got_offset == (bfd_vma) -1)
+		info [kept].got_offset = got_offset;
 
 	      if (diff < count)
 		{
-		  /* Find the next duplicate.  */
+		  /* Find the next duplicate.  DIFF will be kept.  */
 		  prev = info [diff].addend;
 		  for (dup = diff + 1; dup < count; dup++)
 		    {
 		      curr = info [dup].addend;
 		      if (curr == prev)
-			break;
+			{
+			  /* If a string is merged with another one,
+			     we need to make sure that DIFF has a
+			     valid got_offset.  */
+			  if (merged
+			      && info [diff].got_offset == (bfd_vma) -1)
+			    info [diff].got_offset = info [dup].got_offset;
+			  break;
+			}
 		      prev = curr;
 		      diff++;
 		    }
@@ -2316,6 +2362,9 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn
 	  memmove (&info [dest], &info [src], len * sizeof (*info));
 
 	  dest += len;
+
+	  /* We will keep this one.  */
+	  kept = dest - 1;
 	}
 
       count = dest;
@@ -2442,6 +2491,7 @@ has_space:
       /* Append the new one to the array.  */
       dyn_i = info + count;
       memset (dyn_i, 0, sizeof (*dyn_i));
+      dyn_i->got_offset = (bfd_vma) -1;
       dyn_i->addend = addend;
       
       /* We increment count only since the new ones are unsorted and
@@ -2454,7 +2504,7 @@ has_space:
 	 array isn't sorted.  */
       if (count != sorted_count)
 	{
-	  count = sort_dyn_sym_info (info, count);
+	  count = sort_dyn_sym_info (info, count, FALSE);
 	  *count_p = count;
 	  *sorted_count_p = count;
 	}
@@ -4652,9 +4702,16 @@ elfNN_ia64_relocate_section (output_bfd,
 					- sym_sec->output_section->vma
 					- sym_sec->output_offset;
 		    }
-		  
-		  qsort (loc_h->info, loc_h->count,
-			 sizeof (*loc_h->info), addend_compare);
+
+		  /* We may have introduced duplicated entries. We need
+		     to remove them properly.  */
+		  count = sort_dyn_sym_info (loc_h->info, loc_h->count,
+					     TRUE);
+		  if (count != loc_h->count)
+		    {
+		      loc_h->count = count;
+		      loc_h->sorted_count = count;
+		    }
 
 		  loc_h->sec_merge_done = 1;
 		}


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