在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;
,表示这是LR
的EXC_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中打印栈信息