avrdudes / avr-libc

The AVR-LibC package provides a subset of the standard C library for AVR 8-bit RISC microcontrollers.
https://avrdudes.github.io/avr-libc/
Other
261 stars 56 forks source link

[bug #29774] prologue/epilogue stack pointer manipulation not interrupt safe in XMega #429

Closed avrs-admin closed 2 years ago

avrs-admin commented 2 years ago

Tue 04 May 2010 06:05:21 PM CEST

The function prologue and epilogue code (in list files _prologuesaves and _epiloguerestores) finish by clearing interrupts, changing the stack pointer, then restoring the status register (potentially enabling interrupts).

The actual code from the list file for my XMega project is shown below. Note that 0x3F is the status register (including interrupt enable), and 0x3D with 0x3E are the stack pointer.

The status register is preserved, then interrupts are cleared. Half of the stack is written, the status register is restored, then the other half of the stack is written. On most architectures this is correct as one instruction can safely execute after enabling interrupts (restore SREG) before an interrupt can occur.

0001b082 <__epilogue_restores__>:
...
1b0aa:        0f b6               in        r0, 0x3f        ; 63
1b0ac:        f8 94               cli
1b0ae:        de bf               out        0x3e, r29        ; 62
1b0b0:        0f be               out        0x3f, r0        ; 63
1b0b2:        cd bf               out        0x3d, r28        ; 61
1b0b4:        ed 01               movw        r28, r26
1b0b6:        08 95               ret

The XMega, however, can jump to an interrupt immediately after the status register is restored and before the second half of the stack is written. Therefore any interrupt code that uses the stack will potentially write to an arbitrary memory location. In my application this results in stack corruption and a function return to an arbitrary address.

The solution is to restore the status register on line later ("out 0x3f, r0" after "out 0x3d, r28"). Since this code appears to be external to the avr-libc project I am not sure how to implement the fix beyond my own version of the library.

This behavior can be tested by setting an interrupt to be always active such as a very fast timer interrupt. The code will execute one instruction between interrupts and therefore an interrupt will occur at the point indicated above.

This issue was migrated from https://savannah.nongnu.org/bugs/?29774

avrs-admin commented 2 years ago

Joerg Wunsch Wed 05 May 2010 06:12:31 AM CEST

As you already noticed, the function prologue/epilogue handling is not part of avr-libc.  It's part of GCC.

So please report this to GCC's bugzilla.