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?
Does the compiler allowed to read data from the stack frame after releasing it?
allegedly, this looks like a compiler issue.