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: PR ld/4590: String merging breaks ia64 linker


When a string is merged with another one, we have to remove its
addend from the array of addends.  Otherwise, get_dyn_sym_info
may return the entry whose addend has been merged.  This patch
calls sort_dyn_sym_info to remove the merged addends from the
array.


H.J.
---
bfd/

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

	PR ld/4590
	* elfxx-ia64.c (elfNN_ia64_dyn_sym_info): Add addend_merged.
	(addend_merged_compare): New.
	(sort_dyn_sym_info): Call addend_merged_compare to sort array
	of addend.
	(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.

ld/testsuite/

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

	PR ld/4590
	* ld-ia64/merge1.d: New.
	* ld-ia64/merge1.s: Likewise.

--- binutils/bfd/elfxx-ia64.c.merge	2007-06-09 07:31:50.000000000 -0700
+++ binutils/bfd/elfxx-ia64.c	2007-06-09 11:19:37.000000000 -0700
@@ -124,6 +124,9 @@ struct elfNN_ia64_dyn_sym_info
   unsigned want_tprel : 1;
   unsigned want_dtpmod : 1;
   unsigned want_dtprel : 1;
+
+  /* TRUE if this addend is merged with another one.  */
+  unsigned addend_merged: 1;
 };
 
 struct elfNN_ia64_local_hash_entry
@@ -2229,6 +2232,25 @@ addend_compare (const void *xp, const vo
   return x->addend < y->addend ? -1 : x->addend > y->addend ? 1 : 0;
 }
 
+/* This is similar to addend_compare.  But it puts unmerged entry
+   before merged ones.  It is used by sort_dyn_sym_info to remove
+   duplicated entries which have been merged.  */
+
+static int
+addend_merged_compare (const void *xp, const void *yp)
+{
+  const struct elfNN_ia64_dyn_sym_info *x
+    = (const struct elfNN_ia64_dyn_sym_info *) xp;
+  const struct elfNN_ia64_dyn_sym_info *y
+    = (const struct elfNN_ia64_dyn_sym_info *) yp;
+
+  if (x->addend == y->addend)
+    return (x->addend_merged < y->addend_merged
+	    ? -1 : x->addend_merged > y->addend_merged ? 1 : 0);
+  else
+    return x->addend < y->addend ? -1 : 1;
+}
+
 /* Sort elfNN_ia64_dyn_sym_info array and remove duplicates.  */
 
 static unsigned int
@@ -2238,7 +2260,7 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn
   bfd_vma curr, prev;
   unsigned int i, dup, diff, dest, src, len;
 
-  qsort (info, count, sizeof (*info), addend_compare);
+  qsort (info, count, sizeof (*info), addend_merged_compare);
 
   /* Find the first duplicate.  */
   prev = info [0].addend;
@@ -4634,27 +4656,36 @@ elfNN_ia64_relocate_section (output_bfd,
 		{
 		  struct elfNN_ia64_dyn_sym_info *dynent;
 		  unsigned int count;
+		  bfd_vma addend;
 
 		  for (count = loc_h->count, dynent = loc_h->info;
 		       count != 0;
 		       count--, dynent++)
 		    {
 		      msec = sym_sec;
+		      addend = dynent->addend;
 		      dynent->addend =
 			_bfd_merged_section_offset (output_bfd, &msec,
 						    elf_section_data (msec)->
 						    sec_info,
 						    sym->st_value
-						    + dynent->addend);
+						    + addend);
 		      dynent->addend -= sym->st_value;
 		      dynent->addend += msec->output_section->vma
 					+ msec->output_offset
 					- sym_sec->output_section->vma
 					- sym_sec->output_offset;
+		      dynent->addend_merged = dynent->addend != addend;
+		    }
+
+		  /* We may introduce a duplicated entry here. We need
+		     to remove it properly.  */
+		  count = sort_dyn_sym_info (loc_h->info, loc_h->count);
+		  if (count != loc_h->count)
+		    {
+		      loc_h->count = count;
+		      loc_h->sorted_count = count;
 		    }
-		  
-		  qsort (loc_h->info, loc_h->count,
-			 sizeof (*loc_h->info), addend_compare);
 
 		  loc_h->sec_merge_done = 1;
 		}
--- binutils/ld/testsuite/ld-ia64/merge1.d.merge	2007-06-09 11:20:28.000000000 -0700
+++ binutils/ld/testsuite/ld-ia64/merge1.d	2007-06-09 11:22:27.000000000 -0700
@@ -0,0 +1,9 @@
+#source: merge1.s
+#as: -x
+#ld: -shared
+#objdump: -d
+
+#...
+[ 	]*[a-f0-9]+:	0b 60 80 02 00 24 	\[MMI\]       addl r12=32,r1;;
+[ 	]*[a-f0-9]+:	c0 c0 04 00 48 00 	            addl r12=24,r1
+#pass
--- binutils/ld/testsuite/ld-ia64/merge1.s.merge	2007-06-09 11:20:31.000000000 -0700
+++ binutils/ld/testsuite/ld-ia64/merge1.s	2007-06-09 11:14:34.000000000 -0700
@@ -0,0 +1,12 @@
+	.section .rodata.str1.8,"aMS", 1
+.LC1:	.string "foo"
+.LC2:	.string "foo"
+	.section .data.rel.local,"aw"
+	.quad .LC2
+	.section .rodata,"a"
+.LC3:	.string "bar"
+	.balign 8
+	.space 0x400000
+	.text
+	addl r12=@ltoffx(.LC1),r1 ;;
+	addl r12=@ltoffx(.LC3),r1 ;;


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