This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Bad MIPS address arithmetic


On Mon, 10 May 2010, Paul Koning wrote:

> I spotted this in binutils 2.18.
> 
> Given the source file:
> 
> foo:	ld	$v0,40000($sp)
> 	jr	$ra
> 
> The resulting code is:
> 
> 	lui	v0, 1
> 	addu	v0, v0, sp
> 	jr	ra
> 	ld	v0, -25536(sp) 
> 
> The problem is that this produces wrong addresses in machines with 64
> bit registers, if the current sp is 0x7fff0000 or higher.  If so, the
> addu produces 0xffffffff8000nnnn in v0, and the ld then references
> 0xffffffff7fffnnnn which is not likely to be a valid address.
> 
> It seems that daddu rather than addu should be used here, for O64 (and
> probably N32) ABIs.

 I dare not speak of the o64 ABI as its details have always been a mystery 
to me.  But with n32 the code generated is correct.  You can't just offset 
an address of "0x7fff0000 or higher" by 40000, because you are crossing 
from KUSEG to KSEG0 this way.  This is undefined behaviour -- the n32's 
31-bit KUSEG space ends at 0x7fffffff.

 Now I agree there is a problem, namely with legacy 64-bit MIPS hardware 
that did not properly support address space truncation that would 
correctly support the 31-bit user address space suitable for n32 
processes.  The only controlling bit for the 64-bit mode was CP0.Status.UX 
that enabled both 64-bit operations and 64-bit addresses at the same time.  
This was corrected in the MIPS64 ISA with the addition of the 
CP0.Status.PX that only enables 64-bit operations, but keeps addresses 
truncated to 32-bit segments.  With CP0.Status.PX set the LD instruction 
above correctly refers to 0xffffffff8000nnnn.

 The difference is however somewhat academic -- at the kernel level with 
legacy processors you get an unhandled TLBL exception rather than the 
expected AdEL one.  A properly written OS kernel will kill the offender 
with a signal in both cases.

 Even if you're advanced enough to handle the signal sent, then you don't 
really need to take any special precautions -- the faulting address passed 
to the handler has to be properly sign-extended from 32 bits by user 
software (typically by using LW to retrieve) and (at least with Linux) you 
won't notice a difference as a SIGSEGV is sent in response to both 
exceptions under these circumstances.

 Have I made it clear enough?

  Maciej


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]