GOLD handling of weak symbols (including x86 vs. ARM)
Richard Sandiford
richard.sandiford@linaro.org
Wed Nov 3 15:39:00 GMT 2010
Ian Lance Taylor <iant@google.com> writes:
> Richard Sandiford <richard.sandiford@linaro.org> writes:
>>> So I think we have two alternatives: 1) use the PLT entry for a
>>> function call and use a dynamic reloc when not making a function call;
>>> 2) always use a dynamic reloc.
>>
>> But this means putting a dynamic reloc in the text section and...
>>
>>> If I understand the ARM case, you are asking about the :lower16:foo and
>>> :upper16:foo operands, not the bl. You want those operands to get
>>> dynamic relocs. Why is that not happening? Perhaps we simply need to
>>> add R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS to the switch in
>>> reloc_is_non_pic in arm.cc.
>>
>> ...unfortunately, in the case of Thumb, you're not allowed to have dynamic
>> R_ARM_THM_MOV*_ABS* reloctions. They have to be resolved statically.
>
> Then I don't understand how this could possibly work if the weak
> undefined symbol is defined by a shared library. I'm sorry if I'm not
> grasping your question.
>
> Are you saying that a weak undefined symbol should be seen as zero if it
> is not defined in the object being linked, even if it is defined by a
> shared library at run time? I don't see how that could be right.
>
> Or are you saying that this particular assembly sequence should
> implicitly test the value in the object being linked, even though the
> symbol does not have hidden visibility and is not in some other way
> forced to be local? I think I would question whether the assembly
> sequence is valid. It's not clear to me that that is a meaningful
> operation in ELF.
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;
}
This sort of code can be useful if the TU is sometimes linked with a
definition of foo and sometimes isn't. You only want to call foo if it
is defined. I'm talking about what happens when foo isn't defined at
static link time (not even by a shared library).
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.
The observation was then that, if you add @PLT to the x86 call,
the linkers change behaviour. Both linkers still produce no dynamic
relocations for (&foo != 0), but the way that they resolve that &foo
reference differs. BFD LD resolves it to 0 whereas GOLD LD resolves it
to the PLT entry. Thus with BFD LD, &foo is hard-coded to 0, and foo ()
is still never called. With GOLD, &foo is hard-coded to the address
of the PLT, and foo () is always called, even if it isn't defined.
The GOLD behaviour triggers a segfault when foo isn't defined.
The second-order question was then: if GOLD wants to handle &foo
in this way, what should happen on targets, like Thumb, that don't
define separate @PLT call relocations?
I'm probably not making this any clearer, sorry. :-)
> If these operations were being used to load the address of the function
> into a register in order to call it later, then as far as I can see the
> only possible correct result would be the address of the PLT entry.
> Otherwise it would be impossible for a weak undefined symbol to be
> defined by a shared object loaded at runtime.
In this case, the absolute relocations are being used purely to test
whether the function is defined. It isn't used for an indirect call.
Richard
More information about the Binutils
mailing list