On 04/04/2016 06:36 AM, Andrew Bennett wrote:
Hi,

In MIPS (and similarly for other RISC architectures) to load an absolute 
address of an object
requires a two instruction sequence: one instruction to load the high part of 
the object's address,
and one instruction to load the low part of the object's address.  Typically 
the result from the
calculation of the high part of the address will only be used by one 
instruction to load
the low part of the address.  However, in certain situations (for example when 
loading or
storing double word values) the result of computing the high part of the 
address can be
used by multiple instructions to load the low parts of an address at different 
offsets.  Lets
show this with an example C program.
On the PA we started with L and R selectors (top 21 bits and low 11 bits). There were implmemented with simple shift and mask respectively.

It turns out that there's overlap between what bits are set by the high and lo_sum patterns. ie, we can use a single high to access multiple lo_sum objects that are nearby.

That brought the LR and RR selectors which would round the addend to an 8k boundary.



Notice here that the high part of the address of object h is loaded into 
register $2,
and this is then used as part of the low part calculation by two the sw 
instructions which each
have different offsets.  In MIPS the value of a low part calculation is treated 
as a signed value.
It is therefore valid to use the result of a high part calculation with 
multiple low part calculations
containing different offsets so long as when adding the result of the high part 
to the each of the
sign extended low parts we get valid addresses.
Right.  Not terribly unlike the PA.


However, if we add the packed attribute to the h structure, the fields of the 
structure will
not be naturally aligned and we can break the previous condition.  Lets explain 
this in more
detail with the following C program.

struct __attribute__((packed))
{
  short s;
  unsigned long long l;
} h;

void foo (void)
{
  h.l = 0;
}

When this is compiled for MIPS it produces the following assembly:

          lui     $2,%hi(h)
         addiu   $4,$2,%lo(h+2)
         addiu   $3,$2,%lo(h+6)
         swl     $0,3($4)
         swr     $0,%lo(h+2)($2)
         swl     $0,3($3)
         jr      $31
         swr     $0,%lo(h+6)($2)

         ...

          .globl  h
         .section        .bss,"aw",@nobits
         .align  2
         .type   h, @object
         .size   h, 10
h:
         .space  10


There are two things to highlight here.  Firstly the alignment of the h 
structure has decreased
from 8 bytes to 4 bytes.  Secondly we have a low part calculation which adds an 
offset of 6
to the address of the h structure which is greater than its alignment.

When the MIPS linker resolves a HI relocation (i.e. %hi(h)) it finds the next LO
relocation (i.e. %lo(h+2)) in the relocation table and using the information 
from both
of these relocations it computes the object's address and extracts its high 
part.  Then, when the
MIPS linker resolves a LO relocation it adds the offset to the object's address 
and then extracts
the low part.

Lets assume that object h has an address of 0x80007ffc.  When the MIPS linker 
resolves the value
of the HI relocation for object h, it will also use the value of the LO 
relocation for object h
with an offset of 2.  The high part value is therefore:
It almost sounds like you need to be preventing the compiler from considering a lo_sum (whatever) as an offsettable memory address when the underlying object has had its alignment decreased from its natural alignment.

I wouldn't be at all surprised if you do this you won't see the calls into adjust_address_1 occurring in the first place.

jeff

Reply via email to