[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: Bug#649241: binutils: Either gas or ld is doing the wrong thing with R_SPARC_WDISP22 relocations on sparc



(Hooray for investigating long-standing bug reports?)

On Sat, Nov 19, 2011 at 09:41:21AM +0100, Mike Hommey wrote:
> Package: binutils
> Version: 2.21.90.20111025-1
> Severity: important
>
> In Iceweasel 9, there is a piece of assembly that can be simplified as
> the following:
>
> .text
> .global foo
> .type   foo, #function
> foo:
> 	ba bar
> 	nop
>
> .global bar
> .type   bar, #function
> bar:
> 	call exit
>
> When compiling the above, the resulting binary ends up with a runtime
> R_SPARC_WDISP22 relocation that ld.so doesn't know about:
>
> $ gcc -o test.so -shared test.s
> $ LD_PRELOAD=$(pwd)/test.so cat
> cat: error while loading shared libraries: /home/glandium/test.so: unexpected reloc type 0x08
>
> One would expect ld to actually care about this relocation itself at
> (static) link time. Or gas to emit a relocation that ld knows about.

So, the problem here is that you're making a shared library and thus
bar, being a global symbol, is by default preemptible (if you make it
non-global then the runtime linker is happy, but you can't preempt it).
In the case of using a normal "call" instruction for which the assembler
generates an R_SPARC_WPLT30 relocation (when given -KPIC), the linker
generates a PLT entry and everything is as you'd expect. However, none
of the branches have corresponding WPLT relocations available. Gold is
rather more helpful here, giving:

> error: /tmp/ccgupDIX.o: requires unsupported dynamic reloc; recompile with -fPIC

which, while not especially informative as to *which* relocation was
bad, at least stops it from producing an output the runtime linker will
crash on (and one which has evil text relocations...).

The canonical way to perform a tail-call on SPARC like this is:

> 	or %o7, %g0, %REG
> 	call bar
> 	 or %REG, %g0, %o7

where REG is whatever you have free. This obviously has to be done in
the *same* register window as the caller (otherwise when bar returns
there'll still be an extra window to pop). This saves the return
address, does a call-and-link (clobbering %o7 with PC+8) and then
restores %o7 in the handy delay slot, emulating a call-without-link.

In fact, ld is smart enough to recognise this pattern as not being a
real call, and turns it into the following:

> 	or %o7, %g0, %REG
> 	b bar@plt
> 	 nop

Gold does the same but uses the V9 branch instead. Unfortunately there's
still a wasted instruction there, but it's better than it was.

So to summarise, I guess there are two issues here:

 1. bfd should give an error when trying to use an instruction other
    than call to branch to a preemptible function (currently there are
    no places in elfxx-sparc.c where the "recompile with -fPIC" string
    appears, so there are likely other things like this).

 2. Perhaps new R_SPARC_WPLT{10,16,19,22} should be introduced to allow
    shorter tail-call sequences like this? Glancing at bfd it should be
    fairly straightforward, and I imagine the same is true for gold.

Regards,
James


Reply to: