Assertion failure in elflink.c:2824 (binutils 2.30, powerpc)

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Assertion failure in elflink.c:2824 (binutils 2.30, powerpc)

Justin Hibbits-3
Hi,

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.

My thought, shown in comment #51, and Mark Millard's comment #52, is
that 'def' may need to itself be resolved to its target as well, by
duplicating the while loop resolving h's indirection.

Is this correct thinking?

The failure is 100% reproducible on FreeBSD/powerpc, with binutils 2.30
and 2.32.

Thanks,

Justin Hibbits
Reply | Threaded
Open this post in threaded view
|

Re: Assertion failure in elflink.c:2824 (binutils 2.30, powerpc)

Alan Modra-3
On Wed, Jul 10, 2019 at 02:18:36PM -0500, Justin Hibbits wrote:

> Hi,
>
> 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.
>
> My thought, shown in comment #51, and Mark Millard's comment #52, is
> that 'def' may need to itself be resolved to its target as well, by
> duplicating the while loop resolving h's indirection.
>
> Is this correct thinking?

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.

Please try the following.  I'll add a comment and commit this in a few
days or on hearing back from you that this doesn't break anything on
FreeBSD.

diff --git a/bfd/elflink.c b/bfd/elflink.c
index 65a5f5da74..9689d132ab 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -2922,7 +2922,8 @@ _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)
+      if (def->def_regular
+  || def->root.type != bfd_link_hash_defined)
  {
   h = def;
   while ((h = h->u.alias) != def)
@@ -2935,7 +2936,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);
  }
     }

--
Alan Modra
Australia Development Lab, IBM
Reply | Threaded
Open this post in threaded view
|

Re: Assertion failure in elflink.c:2824 (binutils 2.30, powerpc)

Justin Hibbits-3
On Thu, Jul 11, 2019 at 8:02 PM Alan Modra <[hidden email]> wrote:

>
> On Wed, Jul 10, 2019 at 02:18:36PM -0500, Justin Hibbits wrote:
> > Hi,
> >
> > 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.
> >
> > My thought, shown in comment #51, and Mark Millard's comment #52, is
> > that 'def' may need to itself be resolved to its target as well, by
> > duplicating the while loop resolving h's indirection.
> >
> > Is this correct thinking?
>
> 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.
>
> Please try the following.  I'll add a comment and commit this in a few
> days or on hearing back from you that this doesn't break anything on
> FreeBSD.
>
> diff --git a/bfd/elflink.c b/bfd/elflink.c
> index 65a5f5da74..9689d132ab 100644
> --- a/bfd/elflink.c
> +++ b/bfd/elflink.c
> @@ -2922,7 +2922,8 @@ _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)
> +      if (def->def_regular
> +         || def->root.type != bfd_link_hash_defined)
>         {
>           h = def;
>           while ((h = h->u.alias) != def)
> @@ -2935,7 +2936,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);
>         }
>      }
>

Hi Alan,

That patched worked perfectly.  The llvm port built successfully.  I
kicked off a larger ports build to make sure the package is usable,
but I'm pretty confident of it.

Thanks for the insight and fix!  This has plagued me for a while now,
so I'm really happy now.

- Justin