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