aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Modra <amodra@gmail.com>2012-07-09 08:17:34 +0000
committerAlan Modra <amodra@gmail.com>2012-07-09 08:17:34 +0000
commit1416057852c2649d2c3d0636b4e6007f3bc2d043 (patch)
tree3679f16c8e269dad6e993cff4632632635a4dcf8
parent2e515f7e37e004b44360e957005ea278532699a2 (diff)
downloadgdb-1416057852c2649d2c3d0636b4e6007f3bc2d043.zip
gdb-1416057852c2649d2c3d0636b4e6007f3bc2d043.tar.gz
gdb-1416057852c2649d2c3d0636b4e6007f3bc2d043.tar.bz2
PR ld/14323
* elflink.c (elf_sort_symbol): Sort by size too. (elf_link_add_object_symbols <weakdefs>): Simplify binary search. Do not depend on ordering of symbol aliases. Match largest size.
-rw-r--r--bfd/ChangeLog7
-rw-r--r--bfd/elflink.c41
2 files changed, 33 insertions, 15 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index d48c506..91b4793 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -1,3 +1,10 @@
+2012-07-09 Alan Modra <amodra@gmail.com>
+
+ PR ld/14323
+ * elflink.c (elf_sort_symbol): Sort by size too.
+ (elf_link_add_object_symbols <weakdefs>): Simplify binary search.
+ Do not depend on ordering of symbol aliases. Match largest size.
+
2012-07-03 H.J. Lu <hongjiu.lu@intel.com>
* elf.c (assign_section_numbers): Check if number of sections
diff --git a/bfd/elflink.c b/bfd/elflink.c
index 7679b9a..574b6e2 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3145,7 +3145,7 @@ on_needed_list (const char *soname, struct bfd_link_needed_list *needed)
return FALSE;
}
-/* Sort symbol by value and section. */
+/* Sort symbol by value, section, and size. */
static int
elf_sort_symbol (const void *arg1, const void *arg2)
{
@@ -3164,7 +3164,8 @@ elf_sort_symbol (const void *arg1, const void *arg2)
if (sdiff != 0)
return sdiff > 0 ? 1 : -1;
}
- return 0;
+ vdiff = h1->size - h2->size;
+ return vdiff == 0 ? 0 : vdiff > 0 ? 1 : -1;
}
/* This function is used to adjust offsets into .dynstr for
@@ -4726,7 +4727,6 @@ error_free_dyn:
struct elf_link_hash_entry *hlook;
asection *slook;
bfd_vma vlook;
- long ilook;
size_t i, j, idx;
hlook = weaks;
@@ -4740,14 +4740,13 @@ error_free_dyn:
slook = hlook->root.u.def.section;
vlook = hlook->root.u.def.value;
- ilook = -1;
i = 0;
j = sym_count;
- while (i < j)
+ while (i != j)
{
bfd_signed_vma vdiff;
idx = (i + j) / 2;
- h = sorted_sym_hash [idx];
+ h = sorted_sym_hash[idx];
vdiff = vlook - h->root.u.def.value;
if (vdiff < 0)
j = idx;
@@ -4761,24 +4760,36 @@ error_free_dyn:
else if (sdiff > 0)
i = idx + 1;
else
- {
- ilook = idx;
- break;
- }
+ break;
}
}
/* We didn't find a value/section match. */
- if (ilook == -1)
+ if (i == j)
continue;
- for (i = ilook; i < sym_count; i++)
+ /* With multiple aliases, or when the weak symbol is already
+ strongly defined, we have multiple matching symbols and
+ the binary search above may land on any of them. Step
+ one past the matching symbol(s). */
+ while (++idx != j)
+ {
+ h = sorted_sym_hash[idx];
+ if (h->root.u.def.section != slook
+ || h->root.u.def.value != vlook)
+ break;
+ }
+
+ /* Now look back over the aliases. Since we sorted by size
+ as well as value and section, we'll choose the one with
+ the largest size. */
+ while (idx-- != i)
{
- h = sorted_sym_hash [i];
+ h = sorted_sym_hash[idx];
/* Stop if value or section doesn't match. */
- if (h->root.u.def.value != vlook
- || h->root.u.def.section != slook)
+ if (h->root.u.def.section != slook
+ || h->root.u.def.value != vlook)
break;
else if (h != hlook)
{