From 1416057852c2649d2c3d0636b4e6007f3bc2d043 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Mon, 9 Jul 2012 08:17:34 +0000 Subject: [PATCH] PR ld/14323 * elflink.c (elf_sort_symbol): Sort by size too. (elf_link_add_object_symbols ): Simplify binary search. Do not depend on ordering of symbol aliases. Match largest size. --- bfd/ChangeLog | 7 +++++++ bfd/elflink.c | 41 ++++++++++++++++++++++++++--------------- 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 + + PR ld/14323 + * elflink.c (elf_sort_symbol): Sort by size too. + (elf_link_add_object_symbols ): Simplify binary search. + Do not depend on ordering of symbol aliases. Match largest size. + 2012-07-03 H.J. Lu * 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) { -- 2.7.4