This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
GOLD handling of weak symbols (including x86 vs. ARM)
- From: Richard Sandiford <richard dot sandiford at linaro dot org>
- To: binutils at sourceware dot org
- Date: Wed, 03 Nov 2010 09:26:29 +0000
- Subject: GOLD handling of weak symbols (including x86 vs. ARM)
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