Fix __bss_start assertion failure in _bfd_elf_fix_symbol_flags
authorAlan Modra <amodra@gmail.com>
Fri, 12 Jul 2019 05:58:19 +0000 (15:28 +0930)
committerAlan Modra <amodra@gmail.com>
Mon, 15 Jul 2019 06:32:42 +0000 (16:02 +0930)
> 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.

bfd/ChangeLog
bfd/elflink.c

index b41c05965cec32c93d65abf2d00eff5ae44b57da..7d841e29e59da1b26196078cea4d68d5bbe7a936 100644 (file)
@@ -1,3 +1,8 @@
+2019-07-15  Alan Modra  <amodra@gmail.com>
+
+       * elflink.c (_bfd_elf_fix_symbol_flags): If the def for an
+       alias is no longer bfd_link_hash_defined, clear the alias.
+
 2019-07-13  Alan Modra  <amodra@gmail.com>
 
        * elflink.c (_bfd_elf_omit_section_dynsym_default): Don't keep
index d146a4b285a4f962d8535e3b4745366b231eba69..9175d3fa20eeffd5eead0bda5fbcb74b554cef95 100644 (file)
@@ -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);
        }
     }