Ivan Johansen
Ivan Johansen

Reputation: 165

Why do I need to subtract 1 from label in LDR instruction?

I am working on an ARM Cortex-M4 processor using IAR Embedded Workbench. When the main stack overflows I get a bus fault. I have therefore written a small function in assembly to check if the bus fault was caused by a stack overflow, set the stack pointer and call a dedicated stack overflow handler.

The following code shows the function and it works fine. My problem is that I had to subtract 1 from the labels in the two LDR instructions and I don't understand why.

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

If I don't subtract 1, the LDR instructions load data one byte after the label. StackEnd contains the value 0x20000400, but SP is loaded with 0x5F200004 unless I subtract 1 from the label. The 0x5F is the first byte in BusFault_Handler.

Can anyone explain why I need to subtract 1. Have I configured something wrong. I have checked that the data is word (4 byte) aligned.

Upvotes: 3

Views: 554

Answers (1)

Johan
Johan

Reputation: 3881

When the calculating the address for a label defined when in thumb-mode the assembler will automatically set the least significant bit since it assumes that code labels are branch-targets and nothing else. Thus, when the StackBegin and StackEnd labels are defined as part of the code, they will have the LSB set.

To avoid this problem make sure that the assembler is in data-mode when the StackBegin and StackEnd labels are defined.

        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

Upvotes: 6

Related Questions