(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