This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
Re: PATCH: PR ld/4590: String merging breaks ia64 linker
On Mon, Jun 11, 2007 at 10:37:45AM +0200, Andreas Schwab wrote:
> "H. J. Lu" <hjl@lucon.org> writes:
>
> > Please provide me a testcase to show it.
>
> This is a better one, it tests more cases:
>
> .section .rodata.str1.8,"aMS", 1
> .LC1: .string "foo"
> .LC2: .string "foo"
> .LC3: .string "bar"
> .LC4: .string "bar"
> .LC5: .string "baz"
> .LC6: .string "baz"
> .section .data.rel.local,"aw"
> .quad .LC2
> .quad .LC4
> .quad .LC5
> .section .rodata,"a"
> .LC7: .string "mumble"
> .balign 8
> .space 0x400000
> .text
> addl r12=@ltoffx(.LC1),r1 ;;
> addl r12=@ltoffx(.LC3),r1 ;;
> addl r12=@ltoffx(.LC6),r1 ;;
> addl r12=@ltoffx(.LC7),r1 ;;
>
Could you please try this patch?
Thanks.
H.J.
---
2007-06-11 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.
--- bfd/elfxx-ia64.c.merged 2007-06-09 14:54:39.000000000 -0700
+++ bfd/elfxx-ia64.c 2007-06-11 08:47:53.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,39 @@ 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. */
+ if (merged && info [dup].got_offset == (bfd_vma) -1)
+ info [dup].got_offset = info [src].got_offset;
+
+ /* 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;
+ /* If a string is merged with another one, we need
+ to make sure that DUP has a valid got_offset. */
+ if (merged && info [dup].got_offset == (bfd_vma) -1)
+ info [dup].got_offset = info [diff].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++;
}
@@ -2442,6 +2481,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 +2494,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 +4692,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;
}