0

How do you assure stack alignment inside an ISR? Does the arm C compiler force stack alignment in ISR?

For example, in my understanding local scope variables in a function are pushed onto the stack. Suppose you have a char array of 3 bytes and then an ISR is called. Within that ISR another function is called which requires 4 byte alignment of stack.

Does the ARM compiler fix it or is it broken?

My motivation for this question is I am having an issue with fprintf inside an ISR, I think it might be a stack alignment issue. I'm compiling for an device, but there isn't room for that many tags in an SO question.

artless noise
  • 21,212
  • 6
  • 68
  • 105
FourierFlux
  • 439
  • 5
  • 13
  • ISR = Interrupt Service Routine? – Erik Eidt Jan 09 '22 at 17:55
  • What [specific] processor and OS are you using? The [hidden] ISR prolog/epilog code will take care of stack alignment. Your issue is [probably] that you can _not_ do `fprintf` within an ISR. It [probably] suffers from the same issues that `fprintf` has inside a [linux] signal handler. See: `man signal-safety` – Craig Estey Jan 09 '22 at 17:55
  • Also, note that `fprintf` is relatively slow. ISRs should be fast to keep latency as small as possible. So, even if you could, why do you want to do `fprintf` inside an ISR? What you probably want is for the ISR to store data it gets in a ring queue. The base level code can pull data from this queue and issue the `fprintf`. I'd edit your question and post more about what you're actually trying to do. – Craig Estey Jan 09 '22 at 17:58
  • It seemed to work when I only used integers instead of printing floats so I think maybe it's an issue with the byte alignment. from what I understand floats are upgraded to double before string conversion. The ISR creates a string which is copied to a queue for transmission. – FourierFlux Jan 09 '22 at 18:10
  • Are you allowed to use floating point in an ISR? There's potentially lots of issues there, depending on the OS & processor. – Erik Eidt Jan 09 '22 at 18:43
  • Again, what processor and what OS (e.g. linux, freertos, bare metal)? Most systems don't allow floating pt in a kernel or ISR. If you are doing `fprintf` from an ISR, how do you handle the resulting disk interrupt? How do you handle/prevent stacked interrupts? I'll assume this is some ADC-like device. Have the ISR take in whatever values, put them in a struct, and _enqueue_ the struct. Have the base task level dequeue from the struct queue, do `fprintf` or whatever. `fprintf` calls `malloc`, so calling it in an ISR corrupts the heap. – Craig Estey Jan 09 '22 at 18:46
  • See: https://os.mbed.com/handbook/Ticker https://developer.arm.com/documentation/ka002512/latest https://developer.arm.com/documentation/ka002512/latest https://www.chiefdelphi.com/t/printf-inside-interrupt-routine/86253 https://stackoverflow.com/questions/12704196/c-printf-in-interrupt-handler https://stackoverflow.com/questions/3941271/why-are-malloc-and-printf-said-as-non-reentrant – Craig Estey Jan 09 '22 at 18:59
  • I removed it from ISR and relocated code and it causes a hard fault still though in the past it hasn't. I still strongly believe there is some alignment issue with regards to the stack and fprintf internals but I could be wrong. It looks like embedded printf for float is generally problematic. – FourierFlux Jan 09 '22 at 19:13
  • 1
    A sane compiler won't misalign the stack even if you have a `char arr[3]`, look at its asm output. Much more likely the problem is trying to call a function like `fprintf` that needs to take a lock from inside an ISR. What if the lock for that `FILE*` is already taken? – Peter Cordes Jan 09 '22 at 20:20
  • supposedly gcc follows the arm eabi, which wants a 64 bit aligned stack, but if you look at the gcc output you will see that it does not enforce the alignment on every push/pop, it can/will leave the stack such that an interrupt will be serviced with an unaligned stack. If good enough for gcc, I guess good enough for us – old_timer Jan 09 '22 at 20:32
  • @old_timer the eabi only requires 64 bit alignment at entry to an externally linked function, and it is the caller's responsibility to align. It is allowed to be 4 byte aligned mid-function and the hardware detects this when an interrupt occurs and and has the option to skip an extra 4 bytes before jumping to the handler. – Tom V Jan 10 '22 at 19:35
  • which architectures have this architecture feature and where is the setting for it? – old_timer Jan 10 '22 at 22:23

1 Answers1

2

For ARMv7M (including the Cortex-M3 in your atsam3x) the stack alignment in interrupt handlers is controlled by hardware.

Firstly, it is impossible to ever have the stack pointer aligned any worse than 4 bytes. This is because the bottom two bits of the stack pointer are always zero and no instruction can ever change them. The compiler knows this and so if you create char[3] it rounds it up to 4 bytes.

If the STKALIGN bit of the CCR control register is 0 then this is all that happens. The stack pointer is aligned to a multiple of 4 bytes on entry to an interrupt handler function.

If the STKALIGN bit is 1 then the hardware automatically aligns the stack to an 8-byte boundary on entry to an interrupt.

On Cortex-M3 the reset value of the CCR.STKALIGN is 1, and ARM strongly recommend that you do not change it.

In the ARM ABI it is the responsibility of the caller to align the stack. This is because there is a 50:50 chance that it knows it is already aligned without doing anything, so this is much more efficient.

If your compiler is configured to generate code for the ARM ABI then it will assume that the stack is correctly aligned to an 8-byte boundary on entry to any externally linked function and not generate any code to align it again in the called function.

On ARMv7M (and v6M) it is normal and correct to use a bare function as an interrupt handler. There is no ISR prolog/epilog as mentioned in some of the comments.

All of this combined means that as long as your compiler is configured to use the ARM ABI, and as long as you haven't changed the default value of CCR.STKALIGN then your stack will always be correctly aligned.

Tom V
  • 4,827
  • 2
  • 5
  • 22