diff options
author | Alan Modra <amodra@gmail.com> | 2019-07-12 15:28:19 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2019-07-15 16:02:42 +0930 |
commit | 5b9d7a9a647260ba754fbd2a176d37806f15acc8 (patch) | |
tree | f3132ca940426fcde7aef977903f483a391d4779 /bfd/elflink.c | |
parent | 03181f1c38753b24e9d13491e102b5fa685076a2 (diff) | |
download | gdb-5b9d7a9a647260ba754fbd2a176d37806f15acc8.zip gdb-5b9d7a9a647260ba754fbd2a176d37806f15acc8.tar.gz gdb-5b9d7a9a647260ba754fbd2a176d37806f15acc8.tar.bz2 |
Fix __bss_start assertion failure in _bfd_elf_fix_symbol_flags
> Building LLVM 6.0 on FreeBSD/powerpc (devel/llvm60 port) the assertion
> in the subject trips (displays twice) when linking libLTO.so.1. The
> issue has been filed in FreeBSD's bugzilla, at
> https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=237068 . It appears
> the 'llvm::hashing::detail::get_execution_seed()::seed@@JL_LLVM_6.0'
> symbol is being weakly aliased to an indirect symbol
> __bss_start@@JL_LLVM_6.0. Since __bss_start@@JL_LLVM_6.0 is an
> indirect symbol, it fails the assertion.
I haven't looked under a debugger at your testcase but I think I know
what is going on here. You have a shared library with a weakly
defined llvm::hashing::detail::get_execution_seed()::seed which
happens to be at the same location as __bss_start in that library. At
the time the linker loads symbols for that library, it sees they are
both versioned and thus introduces non-versioned indirect symbols for
them. The linker considers the symbols as possibly being aliases,
setting up h->u.alias and h->is_weakalias such that
__bss_start@@JL_LLVM_6.0 is the definition. No real problem so far,
the definition is bfd_link_hash_defined, except that the zero size, no
type __bss_start symbol possibly should not be considered an alias in
the first place.
Later, __bss_start as defined by the linker script is entered into the
linker symbol table. This is similar to __bss_start being defined by
a regular object file in that ELF symbol resolution rules say that the
value of __bss_start in the library is overridden by __bss_start in
the executable/library being produced. So to accomplish the override,
ld flips __bss_start from being an indirect symbol pointing at
__bss_start@@JL_LLVM_6.0 to __bss_start@@JL_LLVM_6.0 being an indirect
symbol pointing at __bss_start. That's how we get an unexpected
indirect symbol and hit the assert.
What should happen I think, is for the def->def_regular code above the
assert to run in this case. The symbols are no longer aliases.
* elflink.c (_bfd_elf_fix_symbol_flags): If the def for an
alias is no longer bfd_link_hash_defined, clear the alias.
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index d146a4b..9175d3f 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -2918,8 +2918,16 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, /* If the real definition is defined by a regular object file, don't do anything special. See the longer description in - _bfd_elf_adjust_dynamic_symbol, below. */ - if (def->def_regular) + _bfd_elf_adjust_dynamic_symbol, below. If the def is not + bfd_link_hash_defined as it was when put on the alias list + then it must have originally been a versioned symbol (for + which a non-versioned indirect symbol is created) and later + a definition for the non-versioned symbol is found. In that + case the indirection is flipped with the versioned symbol + becoming an indirect pointing at the non-versioned symbol. + Thus, not an alias any more. */ + if (def->def_regular + || def->root.type != bfd_link_hash_defined) { h = def; while ((h = h->u.alias) != def) @@ -2932,7 +2940,6 @@ _bfd_elf_fix_symbol_flags (struct elf_link_hash_entry *h, BFD_ASSERT (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak); BFD_ASSERT (def->def_dynamic); - BFD_ASSERT (def->root.type == bfd_link_hash_defined); (*bed->elf_backend_copy_indirect_symbol) (eif->info, def, h); } } |