简体   繁体   English

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

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

From FreeRTOS.org , regarding Debugging Hard Fault & Other Exceptions on ARM Cortex-M3 and ARM Cortex-M4 microcontrollers , according to FreeRTOS guys we can use the following code in order to debug a ARM Cortex-M Hard Fault- 来自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"
    );
}

Now, to my understanding, the marked line has no effect and is not used in the counterpart prvGetRegistersFromStack function: 现在,据我所知,标记的行无效,并且未在对应的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( ;; );
}

pulFaultStackAddress is passed using register r0 by mrseq r0, msp or by mrsne r0, psp and it's the only argument used in the function. pulFaultStackAddress通过寄存器r0mrseq r0, msp或由mrsne r0, psp它是函数中使用的唯一参数。 So is there a purpose for the ldr r1, [r0, #24] line ? 那么, ldr r1, [r0, #24]行是否有用途?

CPU, OS and compiler makers often collude to produce a standard ABI (aka Abstract Binary Interface) for a particular platform. CPU,OS和编译器制造商经常合谋为特定平台生产标准ABI(又称为抽象二进制接口) It's what allows you to link object files produced by different compilers/languages with your program. 它是使您可以将不同的编译器/语言生成的目标文件与程序链接在一起的方法。 The calling conventions define how return values and parameters are passed between caller and called code, and other details required to allow inter-operable components written in different languages or compiled by different tools. 调用约定定义了如何在调用者和被调用代码之间传递返回值和参数,以及允许使用不同语言编写或由不同工具编译的可互操作组件所需的其他详细信息。

What you are seeing in the assembler code is an ABI detail that should be documented by the ARM consortium . 您在汇编代码中看到的是ABI详细信息,该详细信息应由ARM联盟记录 In order to successfully call into C code from assembler, you must understand the ABI. 为了从汇编程序成功调用C代码,您必须了解ABI。 Note that compiler writers are free to implement their calling conventions any way they wish, so your mileage may vary. 请注意,编译器编写者可以按自己希望的任何方式自由实现其调用约定,因此您的工作量可能会有所不同。 That's why I suggested you check your C compiler documentation. 这就是为什么我建议您检查C编译器文档的原因。 Most C compilers provide configurable calling schemes, sometimes the platform ABI is the default, sometimes it's not. 大多数C编译器提供可配置的调用方案,有时平台ABI是默认的,有时不是。

Given that your target is an RTOS, it's possible they have their own ABI, in which case they probably modified an OSS compiler tool chain, but it is most likely that they follow the ARM Cortex ABI. 考虑到您的目标是RTOS,他们可能拥有自己的ABI,在这种情况下,他们可能会修改OSS编译器工具链,但是很可能他们遵循ARM Cortex ABI。 In cases where the target board doesn't have any OS's available, all bets are off and you should consult the board maker for relevant documentation (if any). 如果目标板没有可用的操作系统,则所有选择均不适用,您应咨询板制造商以获取相关文档(如果有)。

We might be reading too much into this. 我们可能对此读得太多。 I think it's just a kludge to push the prvGetRegistersFromStack address on to a 4 byte boundary (required by my M7 and external SDRAM). 我认为将prvGetRegistersFromStack地址推到4个字节的边界(这是我的M7和外部SDRAM所要求的)只是个麻烦。 They could use the align directive to achieve the same thing. 他们可以使用align指令来实现相同的目的。

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"
        );
}

But hey, if it works who's to say which way's better :) 但是,嘿,如果可行,谁会说哪种方法更好:)

Cheers, David 大卫,干杯

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM