Subject: Re: EGCS enabled on mips
To: Jonathan Stone <jonathan@DSG.Stanford.EDU>
From: Todd Whitesel <toddpw@best.com>
List: tech-toolchain
Date: 10/31/1998 23:53:09
> But %hiadj is what the current %hi reloc means: the HI16 and LO16
> relocs are defined such that the low-order offset is signed.
ugh, I had a bit flipped when I was reading the prior discussion. But...
> lui $1, %hi (expr1) # ..carry compensation needed
> addiu $1, %lo(expr1) # NB: %lo is sign extended
> lui $2, %hi (expr2)
> addiu $2, %lo(expr2)
> and haifa scheduling can (from what warner says) potentially turn it
> into something like:
> lui $1, %hi (expr1)
> lui $2, %hi (expr2)
> addiu $1, %lo(expr1)
> addiu $2, %lo(expr2)
> (which is oversimplified, but it captures what i think Warner Losh is
> reporting the LInux/mips people ran into.)
> is that a clearer explanation?
Not really. I had to read the rest of this before I realized the killer:
> here's a couple of the relevant comment from elf32-mips.c. first from
> just above _bfd_mips_elf_hi16_reloc(),
> /* Do a R_MIPS_HI16 relocation. This has to be done in combination
> [... ...] */
> and second from inside the body of _bfd_mips_elf_lo16_reloc()
> /* The low order 16 bits are always treated as a signed
> [ ... ..] */
> which confirm my understanding.
This can only make sense if the LO16 relocation also adds in a small offset
from the actual instruction containing the LO16, because the HI16 only has
its expression to look at when deciding if there was a carry or not. This
would explain why the linker has to search for a matching LO16 in order to
tell the HI16 what to do.
> You mean Greenhils and Wind River use an extension with unsigned
> low-order offsets? That would make life easier.
> But the obvious downside is that the no-carry way means more expensive
Now that I think about it, the Wind River stuff I am thinking of was for
PowerPC, so it may not apply. Definitely the Green Hills stuff used two
HI16 relocs, one which assumed a carry out of the low-order offset and
one which assumed that there would not be a carry. They were:
%lo(expr) = (expr & 0xFFFF)
%hi(expr) = ((expr >> 16) & 0xFFFF)
%hiadj(expr) = (((expr + (expr & 0x8000)) >> 16) & 0xFFFF)
Probably with COFF, they had to do the linker-search-and-match thing that's
being discussed here, but with ELF I am pretty sure they used addends, and
stopped putting any offsets into the actual instructions.
> That'd mean EGCS can never interleave one lui %hi/addiu %lo with
> another, because doing so would clobber the magic register. (the fact
> that the assembler does it more-or-less the other way round is
> immaterial: if they're paired, they're paired, it doesnt matter
> which way the dependency points as long as theyre all consistent.)
This is probably the best short-term fix.
Todd Whitesel
toddpw @ best.com