在Hardfault期间,ARM Cortex-M0堆栈寄存器是以$ psp还是$ msp保存?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Hardfault期间,ARM Cortex-M0堆栈寄存器是以$ psp还是$ msp保存?相关的知识,希望对你有一定的参考价值。

我有一个问题,我的Cortex-M0是硬故障,所以我试图调试它。我正在尝试打印发生硬故障时被推入堆栈的ARM内核寄存器的内容。

这是我的基本汇编代码:

__attribute__((naked)) void HardFaultVector(void) {
    asm volatile(
        // check LR to see whether the process stack or the main stack was being used at time of exception.
        "mov r2, lr
"
        "mov r3, #0x4
"
        "tst r2, r3
"
        "beq _MSP
"

        //process stack was being used.
        "_PSP:
"
        "mrs r0, psp
"
        "b _END
"

        //main stack was being used.
        "_MSP:
"
        "mrs r0, msp
"
        "b _END
"

        "_END:
"
        "b fault_handler
"
    );  
}  

函数fault_handler将打印被推送到进程堆栈或主堆栈的堆栈帧的内容。这是我的问题:

当我打印应该具有已保存寄存器的堆栈帧的内容时,这是我看到的:

Stack frame at 0x20000120:
 pc = 0xfffffffd; saved pc 0x55555554
 called by frame at 0x20000120, caller of frame at 0x20000100
 Arglist at unknown address.
 Locals at unknown address, Previous frame's sp is 0x20000120
 Saved registers:
  r0 at 0x20000100, r1 at 0x20000104, r2 at 0x20000108, r3 at 0x2000010c, r12 at 0x20000110, lr at 0x20000114, pc at 0x20000118, xPSR at 0x2000011c

您可以看到保存的寄存器,这些寄存器是发生硬故障时ARM内核推送的寄存器。您还可以看到行pc = 0xfffffffd;,表示这是LREXC_RETURN值。值0xfffffffd向我表明在硬故障时正在使用进程堆栈。

如果我打印$psp值,我得到以下内容:

gdb $ p/x $psp
$91 = 0x20000328

如果我打印$msp值,我得到以下内容:

gdb $ p/x $msp
$92 = 0x20000100

您可以清楚地看到$msp指向堆栈的顶部,据说保存的寄存器位于堆栈顶部。这是不是意味着主堆栈具有ARM内核推送到堆栈的已保存寄存器?

如果我打印内存内容,从$msp地址开始,我得到以下内容:

gdb $ x/8xw 0x20000100
0x20000100 <__process_stack_base__>:    0x55555555  0x55555555  0x55555555  0x55555555
0x20000110 <__process_stack_base__+16>: 0x55555555  0x55555555  0x55555555  0x55555555

它是空的...

现在,如果我打印内存内容,从$psp地址开始,我得到以下内容:

gdb $ x/8xw 0x20000328
0x20000328 <__process_stack_base__+552>:    0x20000860  0x00000054  0x00000054  0x20000408
0x20000338 <__process_stack_base__+568>:    0x20000828  0x08001615  0x1ad10800  0x20000000

这看起来更准确。但我认为保存的寄存器应该指示它们位于闪存中的哪个位置?那么这有什么意义呢?

答案

old_timer在你的问题下的评论都是正确的。在异常进入时,寄存器将被推送到活动堆栈,无论当时是PSP还是MSP。默认情况下,所有代码都使用主堆栈(MSP),但如果您使用的是除完全裸机之外的任何内容,则可能是您使用的任何内核都已将Thread模式切换为使用进程堆栈(PSP)。

大多数调查表明PSP正在使用中,你的记忆在PSP周围窥探,而MSP几乎无可争辩。你所拥有的唯一证据就是MSP是fault_handler函数的结果,你没有发布源代码;所以我的第一个猜测就是这个功能在某种程度上被打破了。

还要记住,进入HardFault处理程序的一个常见原因是另一个异常处理程序导致异常。在内存损坏的情况下很容易发生这种情况。在这些情况下(假设线程模式使用PSP),CPU将首先进入处理程序模式以响应原始异常,将r0-r3,r12,lr,pc,psr推送到进程堆栈。它将开始执行原始异常处理程序,然后再次出错,在进入HardFault处理程序时将r0-r3,r12,lr,pc,psr推送到主堆栈。通常会有一些解决方法。

old_timer也提到使用真正的汇编语言,我也同意这里。即使((naked))属性应该删除序言和结尾(在它们之间的大多数可能的'compilerisms'),如果它是用裸汇编语言编写的,那么你的代码将更具可读性。内联汇编语言有其用途,例如,如果你想做一些非常低级的事情,你不能从C做,但你想避免调用返回开销。但是当你的整个函数是用汇编语言编写的时候,没有理由使用它。

以上是关于在Hardfault期间,ARM Cortex-M0堆栈寄存器是以$ psp还是$ msp保存?的主要内容,如果未能解决你的问题,请参考以下文章

使用 C++ 将半字写入闪存时出现 ARM Cortex-M HardFault 异常

Cortex-M3开发经验:在HardFault中打印栈信息

未对齐访问会导致ARM Cortex-M4出错

Cortex-M3开发经验:确定发生HardFault的地方

未对齐的访问导致 ARM Cortex-M4 上的错误

arm 学习选Cortex-M3还是arm9?