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 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;
}