为什么我需要从LDR指令的标签中减去1?

Iva*_*sen 3 assembly arm iar cortex-m

我正在使用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
Run Code Online (Sandbox Code Playgroud)

如果我不减去1,LDR指令将在标签后的一个字节加载数据。StackEnd包含值0x20000400,但是SP加载了0x5F200004,除非我从标签中减去1。0x5F是BusFault_Handler中的第一个字节。

谁能解释为什么我需要减去1.我配置错误吗?我检查了数据是否已字(4字节)对齐。

Joh*_*han 6

当计算在拇指模式下定义的标签的地址时,汇编器将自动设置最低有效位,因为它假定代码标签是分支目标,而没有其他内容。因此,当StackBeginStackEnd标签定义为代码的一部分时,它们将设置LSB。

为避免此问题,请确保在定义StackBeginStackEnd标签时,汇编程序处于数据模式。

        THUMB
BusFault_Handler:
        LDR         R0, StackBegin
        CMP         SP, R0
        IT  GT
        BGT         BusFault_Post_Handler   ; Call if SP is OK
        LDR         SP, StackEnd            ; On stack overflow, set SP to top of main stack;
        B           MainStackOverflow_Handler

        DATA
StackBegin:     DC32        SFB(CSTACK) ; Start of main stack
StackEnd:       DC32        SFE(CSTACK) ; End of main stack
        THUMB
Run Code Online (Sandbox Code Playgroud)