GOLD handling of weak symbols (including x86 vs. ARM)
Richard Sandiford
richard.sandiford@linaro.org
Wed Nov 3 09:26:00 GMT 2010
This may be something that has already been discussed to death.
If so, apologies in advance. (I tried to search, but couldn't
find anything.)
I notice that GOLD and BFD LD differ in the way they handle PLTs
for undefined weak symbols in executables. Take this testcase
from the GCC testsuite.
extern void foo (void) __attribute__ ((weak));
int
main ()
{
if (&foo)
foo ();
return 0;
}
If you implement it like this on x86:
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
movl $foo, %eax
testl %eax, %eax
je .L2
call foo
.L2:
movl $0, %eax
movl %ebp, %esp
popl %ebp
ret
.size main, .-main
.weak foo
then it works with both BFD LD and GOLD. foo is set to 0 and there is
no PLT. But if you add "@PLT" to the call -- not necessarily a sensible
thing, I realise, but bear with me -- then the two linkers differ.
BFD LD creates the PLT and uses it for the call. However, it still
resolves the absolute relocation for "movl $foo..." to 0. GOLD instead
points the absolute relocation to the PLT entry. So the modified code
still "works" with BFD LD for but crashes with GOLD.
If this happens on x86, then I can see there's an argument for blaming
the assembly code. The problem comes with targets like Thumb that don't
have separate relocations for PLT vs. non-PLT calls. AIUI, the linker
has no way of telling whether a given Thumb branch originally had @PLT
attached to it or not. (@PLT does of course affect assembler behaviour.)
So, in the corresponding code for Thumb:
.global main
.thumb
.thumb_func
.type main, %function
main:
.fnstart
.LFB0:
@ args = 0, pretend = 0, frame = 0
@ frame_needed = 0, uses_anonymous_args = 0
push {r3, lr}
.save {r3, lr}
movw r3, #:lower16:foo
movt r3, #:upper16:foo
cbz r3, .L2
bl foo
.L2:
movs r0, #0
pop {r3, pc}
.fnend
.size main, .-main
.weak foo
GOLD effectively handles "bl foo" in the same way that it would handle
"call foo@PLT" on x86. It creates a PLT for foo, then resolves the
absolute relocations to the PLT rather than 0.
I see that use_plt_offset specifically has:
// If this is a weak undefined symbol, we need to use the PLT
// entry; the symbol may be defined by a library loaded at
// runtime.
if (this->is_weak_undefined())
return true;
At this point we have determined that we can't use dynamic relocs.
We've also already dealt with the general case of undefined symbols
in shared libraries:
// If we are generating a shared object, and this symbol is
// undefined or preemptible, we need to use the PLT entry.
if (parameters->options().shared()
&& (this->is_undefined() || this->is_preemptible()))
return true;
so it seems the behaviour is to some extent deliberate. IIRC,
it's part of the code to handle LD_PRELOADs that define weak symbols.
What's the best way out here?
Richard
More information about the Binutils
mailing list