【发布时间】:2023-04-11 11:17:01
【问题描述】:
我的 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\n"
"mov r3, #0x4\n"
"tst r2, r3\n"
"beq _MSP\n"
//process stack was being used.
"_PSP:\n"
"mrs r0, psp\n"
"b _END\n"
//main stack was being used.
"_MSP:\n"
"mrs r0, msp\n"
"b _END\n"
"_END:\n"
"b fault_handler\n"
);
}
函数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
这看起来更准确。 但我认为保存的寄存器应该指示它们在闪存中的位置?那么这有什么意义呢?
【问题讨论】:
-
在指令流抢占时,硬件将上下文状态保存到一个 SP 寄存器指向的堆栈中,请参阅第 B1-186 页的 SP 寄存器。使用的堆栈取决于异常发生时处理器的模式。
-
在异常进入和退出的伪代码序列中描述了用于异常进入和退出的堆栈指针,请参见第 B1-196 页的异常进入行为和第 B1-198 页的异常返回行为更多细节。 SP_main 在重置时被选中并初始化,请参阅第 B1-195 页的重置行为。
-
为什么要和msp搞混?
-
你应该从真正的汇编语言开始,这样你就不会让任何编译器弄乱你正在尝试做的事情。
-
嘿@old_timer!再次感谢!我假设您在提及页码时指的是 ARMvxM 参考手册。我查看了那里的伪代码,并验证了在异常发生期间正在使用进程堆栈,并且进程堆栈是推送核心寄存器的位置。我不一定要弄乱 msp,我只是好奇为什么推送的寄存器具有与 msp 相关联的地址而不与 psp 相关联。你知道为什么会这样吗?
标签: arm cortex-m fault thumb stack-frame