Subject: Re: EGCS enabled on mips
To: Jonathan Stone <jonathan@DSG.Stanford.EDU>
From: Todd Whitesel <>
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 @