【发布时间】:2019-12-31 10:05:17
【问题描述】:
我正在使用 IAR Embedded Workbench 开发 ARM Cortex-M4 处理器。当主堆栈溢出时,我得到一个总线故障。因此,我在汇编中编写了一个小函数来检查总线故障是否是由堆栈溢出引起的,设置堆栈指针并调用专用的堆栈溢出处理程序。
以下代码显示了该功能,并且可以正常工作。我的问题是我必须从两个 LDR 指令中的标签中减去 1,我不明白为什么。
StackBegin: DC32 SFB(CSTACK) ; Start of main stack
StackEnd: DC32 SFE(CSTACK) ; End of main stack
BusFault_Handler:
LDR R0, StackBegin-1 ; No idea why we need to subtract 1
CMP SP, R0
IT GT
BGT BusFault_Post_Handler ; Call if SP is OK
LDR SP, StackEnd-1 ; On stack overflow, set SP to top of main stack; No idea why we need to subtract 1
B MainStackOverflow_Handler
如果我不减 1,LDR 指令会在标签后一个字节加载数据。 StackEnd 包含值 0x20000400,但 SP 加载为 0x5F200004,除非我从标签中减去 1。 0x5F 是 BusFault_Handler 中的第一个字节。
谁能解释为什么我需要减去 1。我是否配置错误。我已检查数据是否为字(4 字节)对齐。
【问题讨论】:
-
程序内存中的两个常量可能没有正确对齐。尝试在两条
DC32指令之前添加ALIGN 2。此外,您需要IT HS(“无符号更高或相同”),因为指针是无符号的,并且最低堆栈地址SFB(CSTACK)是有效地址。 -
可能
CSTACK部分未按 4 对齐?在这两种情况下生成什么 asm 代码? StackEnd 包含值 0x20000400 你是怎么发现的? -
有可能是汇编器给标签地址加了1,因为标签在拇指模式下的文本部分。
-
@fuz - 非常好。根据IAR manual:“在使用 DC8、DC16 或 DC32 定义 Thumb 代码部分中的数据时,始终使用 DATA 指令,否则数据上的标签将设置位 0。”。实现目标的更简单方法是
LDR R0, =(SFB(CSTACK)) -
你最好清除位 0 (
bic address, address, #1) 而不是减去 1。