Subject: 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:
> 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 doesn't know about:
> $ gcc -o -shared test.s
> $ LD_PRELOAD=$(pwd)/ cat
> cat: error while loading shared libraries: /home/glandium/ 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* r...

elocation 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 [email protected]
> 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.


Programming list archiving by: Enterprise Git Hosting