+2019-10-14 Alan Modra <amodra@gmail.com>
+
+ * elf-strtab.c (strrevcmp): Comment.
+ * merge.c (strrevcmp): Likewise.
+ * elf64-ppc.c (compare_symbols): Correct final pointer comparison.
+ Comment on why comparing pointers ensures a stable sort.
+ * elflink.c (struct elf_symbol): Add void* to union.
+ (elf_sort_elf_symbol): Ensure a stable sort with pointer comparison.
+ (elf_sym_name_compare): Likewise.
+ (bfd_elf_match_symbols_in_sections): Style fix.
+ (elf_link_sort_cmp1): Comment.
+
2019-10-14 Alan Modra <amodra@gmail.com>
PR 24955
if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0)
return 1;
- return a > b;
+ /* Finally, sort on where the symbol is in memory. The symbols will
+ be in at most two malloc'd blocks, one for static syms, one for
+ dynamic syms, and we distinguish the two blocks above by testing
+ BSF_DYNAMIC. Since we are sorting the symbol pointers which were
+ originally in the same order as the symbols (and we're not
+ sorting the symbols themselves), this ensures a stable sort. */
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
}
/* Search SYMS for a symbol of the given VALUE. */
{
Elf_Internal_Sym *isym;
struct elf_symbuf_symbol *ssym;
+ void *p;
} u;
const char *name;
};
const Elf_Internal_Sym *s1 = *(const Elf_Internal_Sym **) arg1;
const Elf_Internal_Sym *s2 = *(const Elf_Internal_Sym **) arg2;
- return s1->st_shndx - s2->st_shndx;
+ if (s1->st_shndx != s2->st_shndx)
+ return s1->st_shndx > s2->st_shndx ? 1 : -1;
+ /* Final sort by the address of the sym in the symbuf ensures
+ a stable sort. */
+ if (s1 != s2)
+ return s1 > s2 ? 1 : -1;
+ return 0;
}
static int
{
const struct elf_symbol *s1 = (const struct elf_symbol *) arg1;
const struct elf_symbol *s2 = (const struct elf_symbol *) arg2;
- return strcmp (s1->name, s2->name);
+ int ret = strcmp (s1->name, s2->name);
+ if (ret != 0)
+ return ret;
+ if (s1->u.p != s2->u.p)
+ return s1->u.p > s2->u.p ? 1 : -1;
+ return 0;
}
static struct elf_symbuf_head *
goto done;
if (!info->reduce_memory_overheads)
- elf_tdata (bfd1)->symbuf = ssymbuf1
- = elf_create_symbuf (symcount1, isymbuf1);
+ {
+ ssymbuf1 = elf_create_symbuf (symcount1, isymbuf1);
+ elf_tdata (bfd1)->symbuf = ssymbuf1;
+ }
}
if (ssymbuf1 == NULL || ssymbuf2 == NULL)
goto done;
if (ssymbuf1 != NULL && !info->reduce_memory_overheads)
- elf_tdata (bfd2)->symbuf = ssymbuf2
- = elf_create_symbuf (symcount2, isymbuf2);
+ {
+ ssymbuf2 = elf_create_symbuf (symcount2, isymbuf2);
+ elf_tdata (bfd2)->symbuf = ssymbuf2;
+ }
}
if (ssymbuf1 != NULL && ssymbuf2 != NULL)
Elf_Internal_Rela rela[1];
};
+/* qsort stability here and for cmp2 is only an issue if multiple
+ dynamic relocations are emitted at the same address. But targets
+ that apply a series of dynamic relocations each operating on the
+ result of the prior relocation can't use -z combreloc as
+ implemented anyway. Such schemes tend to be broken by sorting on
+ symbol index. That leaves dynamic NONE relocs as the only other
+ case where ld might emit multiple relocs at the same address, and
+ those are only emitted due to target bugs. */
+
static int
elf_link_sort_cmp1 (const void *A, const void *B)
{