ARM Cortex-M处理器硬故障处理中的冗余代码

Redundant code in hard fault handling of ARM Cortex-M processor

来自FreeRTOS.org, 关于 调试硬故障和其他异常 在 ARM Cortex-M3 和 ARM Cortex-M4 微控制器上 ,根据 FreeRTOS 人员的说法,我们可以使用以下代码来调试 ARM Cortex-M 硬故障 -

/* The fault handler implementation calls a function called
prvGetRegistersFromStack(). */
static void HardFault_Handler(void)
{
    __asm volatile
    (
        " tst lr, #4                                                \n"
        " ite eq                                                    \n"
        " mrseq r0, msp                                             \n"
        " mrsne r0, psp                                             \n"
        " ldr r1, [r0, #24]    <======== NOTE THIS LINE             \n"
        " ldr r2, handler2_address_const                            \n"
        " bx r2                                                     \n"
        " handler2_address_const: .word prvGetRegistersFromStack    \n"
    );
}

现在,据我了解,标记的行没有任何作用,也没有在对应的 prvGetRegistersFromStack 函数中使用:

void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
{
/* These are volatile to try and prevent the compiler/linker optimising them
away as the variables never actually get used.  If the debugger won't show the
values of the variables, make them global my moving their declaration outside
of this function. */
volatile uint32_t r0;
volatile uint32_t r1;
volatile uint32_t r2;
volatile uint32_t r3;
volatile uint32_t r12;
volatile uint32_t lr; /* Link register. */
volatile uint32_t pc; /* Program counter. */
volatile uint32_t psr;/* Program status register. */

    r0 = pulFaultStackAddress[ 0 ];
    r1 = pulFaultStackAddress[ 1 ];
    r2 = pulFaultStackAddress[ 2 ];
    r3 = pulFaultStackAddress[ 3 ];

    r12 = pulFaultStackAddress[ 4 ];
    lr = pulFaultStackAddress[ 5 ];
    pc = pulFaultStackAddress[ 6 ];
    psr = pulFaultStackAddress[ 7 ];

    /* When the following line is hit, the variables contain the register values. */
    for( ;; );
}

pulFaultStackAddressmrseq r0, mspmrsne r0, psp 使用寄存器 r0 传递,它是函数中使用的唯一参数。那么 ldr r1, [r0, #24] 行有什么用途吗?

CPU、OS 和编译器制造商经常合谋为特定平台制定标准 ABI (aka Abstract Binary Interface)。它允许您使用您的程序 link 由不同 compilers/languages 生成的目标文件。调用约定定义了 return 值和参数如何在调用者和被调用代码之间传递,以及允许以不同语言编写或由不同工具编译的可互操作组件所需的其他细节。

您在汇编代码中看到的是 should be documented by the ARM consortium 的 ABI 详细信息。为了从汇编程序中成功调用 C 代码,您必须了解 ABI。请注意,编译器编写者可以自由地以他们希望的任何方式实现他们的调用约定,因此您的里程数可能会有所不同。这就是我建议您查看 C 编译器文档的原因。大多数 C 编译器都提供可配置的调用方案,有时平台 ABI 是默认的,有时不是。

鉴于您的目标是 RTOS,他们可能有自己的 ABI,在这种情况下,他们可能修改了 OSS 编译器工具链,但很可能他们遵循 ARM Cortex ABI。如果目标板没有任何 OS 可用,则所有赌注均无效,您应咨询板制造商以获取相关文档(如果有)。

我们可能对此读得太多了。我认为将 prvGetRegistersFromStack 地址推到 4 字节边界(我的 M7 和外部 SDRAM 需要)只是一个小问题。他们可以使用对齐指令来实现相同的目的。

void HardFault_Handler(void)
{
    __asm volatile
        (
            " tst lr, #4                                                \n"
            " ite eq                                                    \n"
            " mrseq r0, msp                                             \n"
            " mrsne r0, psp                                             \n"
            " ldr r2, handler2_address_const                            \n"
            " bx r2                                                     \n"
            " .align 4                                                  \n"
            " handler2_address_const: .word prvGetRegistersFromStack    \n"
        );
}

但是,嘿,如果可行,谁能说出哪种方法更好:)

干杯, 大卫