GOLD handling of weak symbols (including x86 vs. ARM)

Ian Lance Taylor iant@google.com
Wed Nov 3 15:57:00 GMT 2010


Richard Sandiford <richard.sandiford@linaro.org> writes:

> Yeah, that's basically the first-order question.  Going back to the
> source code:
>
>     extern void foo (void) __attribute__ ((weak));
>     int
>     main ()
>     {
>       if (&foo)
>         foo ();
>
>       return 0;
>     }

I agree that this C code has to work one way or another, where by "work"
I mean that the test of &foo has to return 0 if the symbol is not
defined anywhere, not even by a shared library loaded at runtime.

> GCC, when not compiling PIC, traditionally uses absolute accesses for
> the (&foo != 0) test and a non-@PLT call for "foo ()".  (The x86 code
> I posted is the output from this testcase, which comes from the GCC
> testsuite.)  This approach "works" with both BFD LD and GOLD on x86,
> with neither linker allowing a run-time override of foo.  Both linkers
> resolve the &foo reference to zero without any dynamic relocs.  The foo ()
> call is never executed, even if foo is defined by an LD_PRELOAD.
>
> That's what I was expecting, but I'm not sure from your response
> whether it's what you were expecting or not.

OK, I may be starting to see what you are getting at.  When the linker
sees the relocs generated for &foo, it doesn't know whether the value is
going to be called later or whether it is only going to be compared
against zero.  It's ambiguous.  If we're going to do a comparison
against zero, then the only correct behaviour is to use a dynamic
relocation, which will evaluate to either zero or the address of the
function in a shared library.  If we're going to call the function
later, then we can either use a dynamic relocation or we can refer to
the PLT entry.  Putting those together, the only correct behaviour is to
use a dynamic relocation in all cases.

If we are linking code for which we should not generate a dynamic
relocation, then we are screwed.  There is no possible way to generate
code which is correct in all cases.

However, over in needs_dynamic_reloc, I see this:

    // A reference to an undefined symbol from an executable should be
    // statically resolved to 0, and does not need a dynamic relocation.
    // This matches gnu ld behavior.
    if (this->is_undefined() && !parameters->options().shared())
      return false;

So I think we've already decided that we are screwed in this case.

And that means that we should remove these lines from use_plt_offset:
    if (this->is_weak_undefined())
      return true;
since we've decided that such symbols should be statically resolved to
0.

That seems weird to me but perhaps it makes sense in some universe.

Ian



More information about the Binutils mailing list