I'm trying to chase down a bug in my C code for the AVR Atmega1284. Every so often, it looks like I may be getting a corrupted stack.
Looking at the compiler-generated code, I see lots of blocks like this:
95a: cd b7 in r28, 0x3d ; 61 95c: de b7 in r29, 0x3e ; 62 95e: ac 97 sbiw r28, 0x2c ; 44 960: 0f b6 in r0, 0x3f ; 63 962: f8 94 cli 964: de bf out 0x3e, r29 ; 62 966: 0f be out 0x3f, r0 ; 63 968: cd bf out 0x3d, r28 ; 61
I think this is loading the 16-bit stack pointer from port 0x3d-3e, subtracting 0x2C (reserving space on the stack), then writing the result back. Along the way, it also reads the current status register from port 0x3f, then disables interrupts, and later restores the saved status.
But isn't the timing of the status register update wrong in this code? It restores interrupts (second to last line) before it writes the second byte of the stack pointer (last line). Why doesn't it write both stack pointer bytes, and *then* restore the saved status?
If an interrupt is already pending when the saved status is restored, the interrupt handler could be invoked before the stack pointer is completely updated, causing it to write to unexpected locations in RAM when the handler uses the stack. Which is very much like the behavior I'm seeing.
This is with AVR studio 5, which I believe is using avr-gcc 188.8.131.52.