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 07:18:31PM +0200, Andreas Schwab wrote:
> "H. J. Lu" <hjl@lucon.org> writes:
>
> > 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?
>
> This works for me.
>
Try this one. sort_dyn_sym_info is highly optimized. I hope I get
it right this time. The idea is to always make got_offset valid
for the current addend.
H.J.
----
bfd/
2007-06-12 H.J. Lu <hongjiu.lu@intel.com>
PR ld/4590
* elfxx-ia64.c (sort_dyn_sym_info): Keep the valid got_offset
when removing duplicated entries.
(get_dyn_sym_info): Initialize the got_offset field to -1.
Update call to sort_dyn_sym_info.
(elfNN_ia64_relocate_section): Call sort_dyn_sym_info to sort
array of addend and remove duplicates.
--- binutils/bfd/elfxx-ia64.c.merge 2007-06-12 18:37:38.000000000 -0700
+++ binutils/bfd/elfxx-ia64.c 2007-06-12 22:31:50.000000000 -0700
@@ -2235,18 +2235,25 @@ static unsigned int
sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info,
unsigned int count)
{
- bfd_vma curr, prev;
- unsigned int i, dup, diff, dest, src, len;
+ bfd_vma curr, prev, got_offset;
+ unsigned int i, kept, dup, diff, dest, src, len;
qsort (info, count, sizeof (*info), addend_compare);
/* Find the first duplicate. */
prev = info [0].addend;
+ got_offset = info [0].got_offset;
for (i = 1; i < count; i++)
{
curr = info [i].addend;
if (curr == prev)
- break;
+ {
+ /* For duplicates, make sure that got_offset is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [i].got_offset;
+ break;
+ }
+ got_offset = info [i].got_offset;
prev = curr;
}
@@ -2257,15 +2264,31 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn
dest = i++;
while (i < count)
{
+ /* Make sure that KEPT has a valid got_offset. */
+ kept = dest - 1;
+ if (got_offset != (bfd_vma) -1)
+ info [kept].got_offset = got_offset;
+
curr = info [i].addend;
+ got_offset = info [i].got_offset;
/* Move a block of elements whose first one is different from
the previous. */
if (curr == prev)
{
for (src = i + 1; src < count; src++)
- if (info [src].addend != curr)
- break;
+ {
+ if (info [src].addend != curr)
+ break;
+ /* For duplicates, make sure that got_offset is
+ valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [src].got_offset;
+ }
+
+ /* Make sure that KEPT has a valid got_offset. */
+ if (got_offset != (bfd_vma) -1)
+ info [kept].got_offset = got_offset;
}
else
src = i;
@@ -2273,37 +2296,69 @@ 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;
+ got_offset = info [src].got_offset;
for (dup = src + 1; dup < count; dup++)
{
curr = info [dup].addend;
if (curr == prev)
- break;
+ {
+ /* Make sure that got_offset is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [dup].got_offset;
+ break;
+ }
prev = curr;
+ got_offset = info [dup].got_offset;
}
/* How much to move. */
len = dup - src;
i = dup + 1;
+ /* Make sure that DUP - 1 has a valid got_offset. */
+ if (got_offset != (bfd_vma) -1)
+ info [dup - 1].got_offset = got_offset;
+
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 (got_offset != (bfd_vma) -1)
+ info [dup].got_offset = 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;
+ /* Make sure that got_offset is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [diff].got_offset;
+ }
+
+ if (got_offset == (bfd_vma) -1)
+ info [diff - 1].got_offset = got_offset;
if (diff < count)
{
- /* Find the next duplicate. */
+ /* Find the next duplicate. DIFF will be kept. */
prev = info [diff].addend;
+ got_offset = info [diff].got_offset;
for (dup = diff + 1; dup < count; dup++)
{
curr = info [dup].addend;
if (curr == prev)
- break;
+ {
+ /* For duplicates, make sure that got_offset
+ is valid. */
+ if (got_offset == (bfd_vma) -1)
+ got_offset = info [diff].got_offset;
+ break;
+ }
+ got_offset = info [diff].got_offset;
prev = curr;
diff++;
}
@@ -2442,6 +2497,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
@@ -4652,9 +4708,15 @@ 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);
+ if (count != loc_h->count)
+ {
+ loc_h->count = count;
+ loc_h->sorted_count = count;
+ }
loc_h->sec_merge_done = 1;
}