On Tuesday, July 31, 2012 7:27:09 PM UTC+3, Andrew Haley wrote:
> el wrote:
> > On Tuesday, July 31, 2012 12:19:44 PM UTC+3, Andrew Haley wrote:
> >> el wrote:
> >> > I'm working on a MIPS-based embedded system.
> >> > Below is an assembly code snippet of the end of some function.
> >> > This code was compiled by gcc 4.5.2 with -mips16e and -Os flags.
> >> > - Line 6: the stack frame is released and ra,s0 and s1 registers are restored from the stack.
> >> > - Line 8: returns to the caller function (jump to the return address)
> >> > - Line 9: branch delay slot instruction which stores in v0 (return value) a value pointed by register a0
> >> > Note that 0(a) is located in the stack (sp + 26) - see lines 2,3,5
> >> > 1) 8024c3be: 9206 lw v0,24(sp)
> >> > 2) 8024c3c0: 677d move v1,sp
> >> > 3) 8024c3c2: 4387 addiu a0,v1,7
> >> > 4) 8024c3c4: 67bc move a1,gp
> >> > 5) 8024c3c6: 4c13 addiu a0,19
> >> > 6) 8024c3c8: 6478 restore 64,ra,s0-s1
> >> > 7) 8024c3ca: f3a6 dd50 sw v0,13232(a1)
> >> > 8) 8024c3ce: e820 jr ra
> >> > 9) 8024c3d0: 8c40 lh v0,0(a0) // sp+26
> >> > 10) 8024c3d2: 6500 nop
> >> > This asm code (generated by GCC) seems to be faulty as the cpu reads value from the stack frame (line 9) after it was 'released' (line 6).
> >> > Here is a problematic scenario which demonsrates the issue:
> >> > 1. A task is running this function.
> >> > 1. Interrupt is triggered between lines 7 and 8.
> >> > 2. The context of the task is stored in the stack (which was restored beforehand in line 6).
> >> > 3. As a result the value stored in 0(a0)=sp+26 is overwritten by the context information!
> >> > 4. The ISR ends and the task context is resotred.
> >> > 5. the instruction in line 9 is executed --> The function returns in v0 incorrect value!
> >> > Regardless of the RTOS I'm using (it's not linux), is this code legitimate?
> >> It's not necessarily wrong. This is a matter of whether the system
> >> ABI uses a "red zone", an area beyond the stack pointer. I don't
> >> think MIPS usually does, but I don't know anything about the OS you're
> >> using.
> > Our OS is FreeRTOS and use MIPS without shadow registers. so upon
> > context switch we save all current registers on the stack of the
> > task/interrupt (in the 'red zone').
> > So far we worked with an old version of the compiler 'gcc version
> > 3.4.4 mipssde-6.06.01-20070420' - we didn't see the problem there,
> > the 'red zone' was never used by a function.
> > Recently we switched to a new compiler 'gcc version 4.5.2 Sourcery
> > CodeBench Lite 2011.09-86' and we started seeing this problem.
> > Note that this will only happen if we compile to mips16 and apply
> > size optimization. Otherwise this problem won't occur.
> I see that you got another answer on the gcc list: it's a bug. MIPS
> doesn't use a red zone.
> Andrew.