qsort isn't guaranteed to be a stable sort, that is, elements
comparing equal according to the comparison function may be reordered
relative to their original ordering. Of course sometimes you may not
care, but even in those cases it is good to force some ordering
(ie. not have the comparison function return 0) so that linker output
is reproducible over different libc qsort implementations.
One way to make qsort stable (which the glibc manual incorrectly says
is the only way) is to augment the elements being sorted with a
monotonic counter of some kind, and use that counter as the final
arbiter of ordering in the comparison function.
Another way is to set up an array of pointers into the array of
elements, first pointer to first element, second pointer to second
element and so so, and sort the pointer array rather than the element
array. Final arbiter in the comparison function then is the pointer
difference. This works well with, for example, the symbol pointers
returned by _bfd_elf_canonicalize_symtab which point into a symbol
array.
This patch fixes a few places where sorting by symbol pointers is
appropriate, and adds comments where qsort stability is a non-issue.
* 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.
The CTF linking process wants to deduplicate the CTF strtab against the
ELF strtab, for which it needs to know the number of strings in the
strtab and it needs to be able to extract them one by one.
The BFD strtab functions only support returning the
size-or-section-length of the strtab (with _bfd_elf_strtab_size)
and returning the offset (but not string!) and decrementing the refcount
at the same time.
So add new functions _bfd_elf_strtab_len (that just returns the length
in strings of the strtab, never the section size) and bfd_elf_strtab_str
(which returns the string at a given strtab index, and its offset,
without touching the refcount).
It is probably a mistake to use _bfd_elf_strtab_str in particular before
_bfd_elf_strtab_finalize is called, and will not produce useful output
if you do so.
v5: fix tabdamage.
bfd/
* elf-strtab.c (_bfd_elf_strtab_len): New.
(_bfd_elf_strtab_str): Likewise.
* bfd-elf.h: Declare them.
I noticed when writing _bfd_elf_strtab_save/restore that size_t would
be better than bfd_size_type for a number of things in elf-strtab.c.
Using a 64-bit bfd_size_type on a 32-bit host doesn't make much sense
for array sizes and indices.
* elf-strtab.c (struct strtab_save): Use size_t for "size".
(struct elf_strtab_hash): Likewise for "size" and "alloced".
(_bfd_elf_strtab_init): Formatting.
(_bfd_elf_strtab_add): Return size_t rather than bfd_size_type.
(_bfd_elf_strtab_addref): Take size_t idx param.
(_bfd_elf_strtab_delref, _bfd_elf_strtab_refcount): Likewise.
(_bfd_elf_strtab_offset): Likewise.
(_bfd_elf_strtab_clear_all_refs): Use size_t idx.
(_bfd_elf_strtab_save): Use size_t "idx" and "size" vars.
(_bfd_elf_strtab_restore, _bfd_elf_strtab_emit): Similarly.
(_bfd_elf_strtab_finalize): Similarly.
* elf-bfd.h (_bfd_elf_strtab_add): Update prototypes.
(_bfd_elf_strtab_addref, _bfd_elf_strtab_delref): Likewise.
(_bfd_elf_strtab_refcount, _bfd_elf_strtab_offset): Likewise.
* elf.c (bfd_elf_get_elf_syms): Calculate symbol buffer size
using bfd_size_type.
(bfd_section_from_shdr): Delete amt.
(_bfd_elf_init_reloc_shdr): Likewise.
(_bfd_elf_link_assign_sym_version): Likewise.
(assign_section_numbers): Use size_t reloc_count.
* elflink.c (struct elf_symbuf_head): Use size_t "count".
(bfd_elf_link_record_dynamic_symbol): Use size_t for some vars.
(elf_link_is_defined_archive_symbol): Likewise.
(elf_add_dt_needed_tag): Likewise.
(elf_finalize_dynstr): Likewise.
(elf_link_add_object_symbols): Likewise.
(bfd_elf_size_dynamic_sections): Likewise.
(elf_create_symbuf): Similarly.
(bfd_elf_match_symbols_in_sections): Likewise.
(elf_link_swap_symbols_out): Likewise.
(elf_link_check_versioned_symbol): Likewise.
(bfd_elf_gc_record_vtinherit): Likewise.
(bfd_elf_gc_common_finalize_got_offsets): Likewise.
This reverts the pr16467 change, which was incorrect due to faulty
analysis of the pr16467 testcase. The failure was not due to a
mismatch in symbol type (ifunc/non-ifunc) but due to a symbol loop
being set up.
See https://sourceware.org/ml/binutils/2016-06/msg00013.html for some
rambling on versioned symbols and ELF shared library symbol overriding
that explain this patch.
bfd/
PR ld/20159
PR ld/16467
* elflink.c (_bfd_elf_merge_symbol): Revert PR16467 change.
(_bfd_elf_add_default_symbol): Don't indirect to/from defined
symbol given a version by a script different to the version
of the symbol being added.
(elf_link_add_object_symbols): Use _bfd_elf_strtab_save and
_bfd_elf_strtab_restore. Don't fudge dynstr references.
* elf-strtab.c (_bfd_elf_strtab_restore_size): Delete.
(struct strtab_save): New.
(_bfd_elf_strtab_save, _bfd_elf_strtab_restore): New functions.
* elf-bfd.h (_bfd_elf_strtab_restore_size): Delete.
(_bfd_elf_strtab_save, _bfd_elf_strtab_restore): Declare.
* libbfd.c (bfd_realloc_or_free): New function. Performs like
bfd_realloc, but if the (re)allocation fails, the pointer is
freed.
* libbfd-in.h: Prototype.
* libbfd.h: Regenerate.
* bfdio.c (bfd_bwrite): Use the new function.
(bfd_seek): Likewise.
* bfdwin.c:(bfd_get_file_window): Likewise.
* elf-strtab.c (_bfd_elf_strtab_add): Likewise.
* elf32-ppc.c (ppc_elf_relax_section): Likewise.
* elf32-xtensa.c (vsprintf_msg): Likewise.
* mach-o.c (bfd_mach_o_core_fetch_environment): Likewise.
* stabs.c (_bfd_link_seciton_stabs): Likewise.
* vms-misc.c (_bfd_vms_get_record): Likewise.
* vms-tir.c (check_section): Likewise.
* vms.c (vms_new_section_hook): Likewise.
* elf32-arm.c (elf32_arm_section_map_add): Check that the
allocation of sec_data->map succeeded before using it.
* elflink.c (elf_link_output_sym): Do not overwrite finfo->
symshndxbuf until it is known that the reallocation succeeded.
(BFD32_BACKENDS_CFILES): Add elf-strtab.c.
(elf-strtab.lo): Add rule.
* Makefile.in: Rebuilt.
* configure.in (elf): Add elf-strtab.lo.
* configure: Rebuilt.
* elf-bfd.h (elf_strtab_hash): Forward declare.
(struct elf_link_hash_table): Change dynstr type to
struct elf_strtab_hash *.
(struct elf_obj_tdata): Change strtab_ptr type to
struct elf_strtab_hash *.
(_bfd_elf_strtab_init, _bfd_elf_strtab_free, _bfd_elf_strtab_add,
_bfd_elf_strtab_addref, _bfd_elf_strtab_delref,
_bfd_elf_strtab_clear_all_refs, _bfd_elf_strtab_size,
_bfd_elf_strtab_offset, _bfd_elf_strtab_emit,
_bfd_elf_strtab_finalize): New prototypes.
* elf-strtab.c: New file.
* elflink.h (elf_link_add_object_symbols): Use _bfd_elf_strtab_add
and _bfd_elf_strtab_size instead of _bfd_stringtab calls.
Call _bfd_elf_strtab_delref if DT_NEEDED entry is not needed or
when forcing dynamic symbol to local.
(elf_link_create_dynamic_sections): Call
_bfd_elf_strtab_init instead of elf_stringtab_init.
(elf_link_record_local_dynamic_symbol): Likewise, change
dynstr type. Use _bfd_elf_strtab functions instead of
_bfd_stringtab calls.
(size_dynamic_sections): Use _bfd_elf_strtab functions instead of
_bfd_stringtab calls. For DT_RUNPATH and Verdaux vda_name fields,
call _bfd_elf_strtab_addref. Call elf_finalize_dynstr.
(elf_adjust_dynstr_offsets, elf_finalize_dynstr): New functions.
(elf_fix_symbol_flags): Call _bfd_elf_strtab_delref when forcing
dynamic symbol to local.
(elf_link_assign_sym_version): Likewise.
(elf_bfd_final_link): Call _bfd_elf_strtab_emit instead of
_bfd_stringtab_emit.
* elflink.c (_bfd_elf_link_record_dynamic_symbol): Change dynstr
type. Call _bfd_elf_strtab functions instead of
_bfd_stringtab functions.
* elf64-sparc.c (sparc64_elf_size_dynamic_sections): Likewise.
* elf.c (_bfd_elf_init_reloc_shdr): Likewise.
(elf_fake_sections): Likewise.
(assign_section_numbers): Call _bfd_elf_strtab_clear_all_refs
on shstrtab hash table, call _bfd_elf_strtab_addref on each section
name in the output. Call _bfd_elf_strtab_finalize and
use _bfd_elf_strtab_offset to finalize sh_name section header fields.
(_bfd_elf_compute_section_file_positions): Use _bfd_elf_strtab_size
instead of _bfd_stringtab_size.
(prep_headers): Change shstrtab type.
Use _bfd_elf_strtab calls instead of _bfd_stringtab calls.