MIPS embedded PIC bug.
Geoff Keating
geoffk@geoffk.org
Thu Feb 8 16:00:00 GMT 2001
> Cc: binutils@sourceware.cygnus.com, nickc@sourceware.cygnus.com
> From: cgd@sibyte.com (Chris G. Demetriou)
> Date: 08 Feb 2001 14:58:12 -0800
>
> Geoff Keating <geoffk@geoffk.org> writes:
> > > Really? My understanding of this says that if it can't be resolved
> > > into something PC-relative, you need to emit more complex code, and a
> > > sample like the above, but with L20 not defined in the same segment,
> > > can't be resolved into something PC-relative with a single
> > > instruction.
> >
> > Sure it can.
> >
> > The basic PC-relative reloc looks like:
> >
> > .word Lbar-.
> >
> > This is a PC-relative reloc to Lbar, because the address we need is
> > the address of Lbar less the address of the PC, which is `.' in assembler.
> >
> > A similar problem looks like:
> >
> > Lfoo:
> > .word 0
> > .word Lbar-Lfoo
> >
> > The expression 'Lbar-Lfoo' can be rewritten as 'Lbar-Lfoo+.-.',
> > which (because Lfoo and the .word are in the same segment) can be
> > rewritten in this case as 'Lbar-4-.', which is a PC-relative reloc to
> > Lbar-4.
>
> Sure... but when you start trying to put that into the 16-bit offset
> field in an instruction, in many cases (esp. when . and the label are
> in different sections) it's just not going to work.
The rule on this is the same as for that on regular MIPS HI16/LO16
pairing: you try to find the HI16 that corresponds to the LO16 and
combine them. Really, the linker should also adjust for the
difference in location between the relocs, but at present I think it
doesn't.
The idea is that, in strict compliance with the MIPS ABI, every HI16
reloc is supposed to be immediately followed by a LO16 reloc to the
same value.
Unfortunately, this restricts optimisation opportunities, and so you
can configure (perhaps it is the default) GCC to not do this. This is
IMHO playing Russian Roulette with your code.
(The real solution is to not use REL relocs, use RELA instead.)
You can see in the testcase that the REL_HI16 reloc should be
immediately followed by a REL_LO16 reloc:
> la $3,g1-l3 # R_MIPS_GNU_REL_HI16 g1 0
> # R_MIPS_GNU_REL_LO16 g1 C
...
> The testcase expects 'la' to be emitted as multiple instructions, one
> with the REL_HI16 and one with REL_LO16. Both mean that a full 32-bit
> address can be relocated, i.e. anyplace it ends up, it's good.
>
> In the case that triggers the error messages, because the test in the
> code at issue succeeds, instead a _single_ instruction would be
> output, with only a 16-bit RELOC_LO16. The code output in this case
> is _not_ attempting to be PC-relative, as far as I can tell.
That's bad. That should be fixed.
Remember, in this case we _have to_ allow a full 32-bit address,
because the assembler doesn't know where 'g1' might end up. A typical
case is that g1 is in the data section and this is in the text
section, in which case they're almost never going to be less than 32k
apart unless the program is very small and uses no libraries.
> Anyway, this feeds into the question of "in what circumstances is it
> breaking?" And about that, to continue about "it worked when it was
> submitted":
>
> 1999-11-15 Gavin Romig-Koch <gavin@cygnus.com>
>
> * mips-opc.c (la): Create a version that just uses addiu directly.
> (dla): Expand to daddiu if possible.
>
> These use the 'o' instruction operand format.
>
> To be honest, I'm not sure what the benefit of providing doing those
> directly in the opcode table is. It seems to me that any benefit
> could be had by doing a bit of coding in the la and dla expansions.
>
> But on the other hand, i'm not sure it _should_ be handled in C,
> rather than in the table; the EMBEDDED_PIC check in the 'o' format
> handling code really does seem too loose to me. It really doesn't
> seem to me that you can handle the general case in a simple 16-bit
> relocation, which is what it apparently allows.
I think there are only two cases:
- The address is a constant and less than +/- 2^15, in which case you
can generate one instruction; or
- you don't know the address, or it's too big, in which case you must
generate two.
--
- Geoffrey Keating <geoffk@geoffk.org>
More information about the Binutils
mailing list