Ken Lin
Ken Lin

Reputation: 1035

arm-none-eabi-gcc assmebly instructions not pointing to the correct function address on Cortex-M4

I am trying to port over this [code][1] to read the stack frame in the hard fault handler for my STM32F302C8:

    __asm volatile
    (
        " tst lr, #4                                                n"
        " ite eq                                                    n"
        " mrseq r0, msp                                             n"
        " mrsne r0, psp                                             n"
        " ldr r1, [r0, #24]                                         n"
        " ldr r2, handler2_address_const                            n"
        " bx r2                                                     n"
        " handler2_address_const: .word prvGetRegistersFromStack    n"
    );

However, the generated assembly instruction doesn't load the correct value of prvGetReigsetersFromStack into R2.

Version 1:

08000b22 <HardFault_Handler>:
 * @brief This function handles Hard fault interrupt.
 */
void HardFault_Handler(void)
{
    SHARED_HARD_FAULT_HANDLER_ASSEMBLY
 8000b22:       f01e 0f04       tst.w   lr, #4 
 8000b26:       bf0c            ite     eq     
 8000b28:       f3ef 8008       mrseq   r0, MSP
 8000b2c:       f3ef 8009       mrsne   r0, PSP
 8000b30:       6981            ldr     r1, [r0, #24]
 8000b32:       4a00            ldr     r2, [pc, #0]    ; (8000b34 <HardFault_Handler+0x12>)
 8000b34:       4710            bx      r2     

08000b36 <handler2_address_const>:
 8000b36:       08006c15        stmdaeq r0, {r0, r2, r4, sl, fp, sp, lr}
}

Note the comment (8000b34 <HardFault_Handler+0x12>), I am loading the value at 8000b34 to r2 instead of the value at 8000b36 (i.e. handler2_address_const)

What's even more interesting is, if I move the function definition somewhere in the same source file, the code now behaves as expected:

Version 2:

08000b58 <HardFault_Handler>:
void HardFault_Handler(void)
{
 8000b58:       b480            push    {r7}   
 8000b5a:       af00            add     r7, sp, #0 
    __asm volatile(
 8000b5c:       f01e 0f04       tst.w   lr, #4 
 8000b60:       bf0c            ite     eq     
 8000b62:       f3ef 8008       mrseq   r0, MSP
 8000b66:       f3ef 8009       mrsne   r0, PSP
 8000b6a:       6981            ldr     r1, [r0, #24]
 8000b6c:       4a00            ldr     r2, [pc, #0]    ; (8000b70 <handler2_address_const>)
 8000b6e:       4710            bx      r2     

08000b70 <handler2_address_const>:
 8000b70:       08006c25        stmdaeq r0, {r0, r2, r5, sl, fp, sp, lr}
    " bx r2                                                     \n"
    " handler2_address_const: .word prvGetRegistersFromStack    \n");  
}

Note that the comment is now (8000b70 <handler2_address_const>), which is the memory address that contains a function pointer to `prvGetRegistersFromStack.

Note that in both versions of the code, the generated instruction is the same: ```` ldr r2, [pc, #0]

, but the comment is different. I thought maybe this was just a mistake by the disassembler, but with **Version 1** of my code, `prvGetRegistersFromStack` never gets called.

I am using the newest `arm-none-eabi-gcc-2019q3-update`.


  [1]: https://www.freertos.org/Debugging-Hard-Faults-On-Cortex-M-Microcontrollers.html

Upvotes: 0

Views: 187

Answers (1)

Ken Lin
Ken Lin

Reputation: 1035

Update: The root-cause was due to alignment. I found two possible solutions:

  1. Replace bx with b and just branch directly to the function
  2. Force an alignment on HardFault_Handler()

Upvotes: 1

Related Questions