堆栈对齐和 ISR

Stack alignment and ISR

如何确保 ISR 中的堆栈对齐? arm C 编译器是否强制 ISR 中的堆栈对齐?

例如,在我的理解中,函数中的局部作用域变量被压入堆栈。假设您有一个 3 字节的 char 数组,然后调用了一个 ISR。在该 ISR 中,另一个函数被调用,它需要堆栈的 4 字节对齐。

ARM 编译器修复它还是损坏了?

我提出这个问题的动机是我在 ISR 中遇到 fprintf 问题,我认为这可能是堆栈对齐问题。我正在为 设备编译,但在 SO 问题中没有那么多标签的空间。

对于 ARMv7M(包括您的 atsam3x 中的 Cortex-M3),中断处理程序中的堆栈对齐由硬件控制。

首先,堆栈指针不可能比 4 字节更差。这是因为堆栈指针的低两位始终为零,并且任何指令都无法更改它们。编译器知道这一点,因此如果您创建 char[3],它会将其四舍五入为 4 个字节。

如果 CCR 控制寄存器的 STKALIGN 位为 0,那么就会发生这种情况。堆栈指针在进入中断处理函数时与 4 字节的倍数对齐。

如果 STKALIGN 位为 1,则硬件会在进入中断时自动将堆栈对齐到 8 字节边界。

在 Cortex-M3 上 CCR.STKALIGN 的复位值为 1,ARM 强烈建议您不要更改它。

在 ARM ABI 中,调用者负责对齐堆栈。这是因为它有 50:50 的机会在不做任何事情的情况下知道它已经对齐,所以这样效率更高。

如果您的编译器配置为为 ARM ABI 生成代码,那么它会假定堆栈在进入任何外部链接函数时正确对齐到 8 字节边界,并且不会生成任何代码来再次对齐它调用的函数。

在 ARMv7M(和 v6M)上,使用裸函数作为中断处理程序是正常且正确的。没有某些评论中提到的 ISR prolog/epilog。

所有这些组合意味着只要您的编译器配置为使用 ARM ABI,并且只要您没有更改 CCR.STKALIGN 的默认值,那么您的堆栈将始终正确对齐.