我目前正在为Arm Cortex-M0 +微控制器开发固件,并且面临一个相当有趣的问题。我不是在寻找任何答案,而是想与其他开发人员分享问题,以便我(希望)对我所面临的问题有所了解。我将在下面进行描述:
我有一个程序可以从外部闪存芯片动态加载(正确编译和链接)代码,并直接在MCU RAM中执行。有趣的是,在逐步运行(通过调试器)时,我可以完美地执行RAM加载的代码,但是在自由运行时,它总是会崩溃(正式为HardFault)。我试图禁用所有中断,我仔细检查了指令,内存地址,字节对齐方式以及所有内容,但是我仍然无法查明异常的原因。
你们中有人对可能发生的事情有任何暗示吗?我非常想知道更多有关您的经历!谢谢,
更新1(30/05)
在这种情况下,自由运行表示未在分支到RAM之前立即设置断点。每当我进入分支并在RAM中执行指令时,它将正确运行并返回。无论断点不在哪里(因此MCU都会通过分支进行缩放),都会观察到HardFault。请注意,即使在启动调试器但未设置断点的情况下启动,它也会崩溃。
更新2(30/05)
我正在使用赛普拉斯S6E1C3系列Arm Cortex M0 + FM0 +微控制器。
更新3(30/05)
深入研究并使用代码后,我可以使其正常工作!但是,它给我带来的问题多于答案。阅读有关BLX指令(BLX)的ARM官方文档后,我发现分支地址的LSBit确定CPU指令模式(1使其以Thumb模式运行)。通过显式设置此位,即使在自由运行模式 ,我也可以使代码始终运行。事实是,RAM中的代码尚未在Thumb模式下进行编译,并且没有明显原因,为什么使用调试器逐步运行代码会导致指令模式改变。 。有什么想法吗?
K。
答案 0 :(得分:1)
仅Cortex-M 支持Thumb模式,不支持ARM模式,因此告诉编译器使用Cortex-M0 +的编译器可确保它将创建Thumb2代码。
这就是为什么您需要设置目标地址的低位。
https://en.wikipedia.org/wiki/ARM_Cortex-M#Instruction_sets
在Cortex-M架构中仅支持Thumb-1和Thumb-2指令集。不支持旧的32位ARM指令集。
如果您实际上查看内存中的代码字节,您会发现它们是Thumb2指令。
唯一的问题是调试器如何设法使其成为 not 错误。也许它无论如何都必须专门处理BLX,并且不能模拟故障-仅拇指微体系结构行为切换到ARM模式。也许只是处理单步中断最终会在Thumb模式下正确返回。
答案 1 :(得分:1)
问题出在分支机构的地址(由@PeterCordes正确指出)。跳转到RAM的代码是以下代码(针对此受众群体略有调整):
// Prepare address and Function Pointer
uint32_t codeBufferAddress = reinterpret_cast<uint32_t>(&buffer) + offset;
void(*methodFromRAM)(void*) = reinterpret_cast<void(*)(void*)>(codeBufferAddress | 0x01);
// Branch to RAM
// thisPointer holds an object byte-stream...
(*methodFromRAM)(reinterpret_cast<void*>(thisPointer));
请注意,在第3行中,codeBufferAddress
与0x01
(codeBufferAddress | 0x01
)进行了相或运算,以确保分支将以拇指模式进行。在我发布此问题时,codeBufferAddress
持有的值为0x20003E40
,这显然未设置LSBit,因此将迫使MCU在 ARM模式下运行。
我认为编译器将无法推断和调整分支模式,因为地址是动态生成的(尽管我认为它可能更聪明,并强制所有分支都在其中运行拇指模式,因为我的MCU只能解码Thumb)。
无论如何,当我以逐步模式运行时,我无法观察到目标地址的任何变化,现在我只能猜测它迫使MCU在拇指模式下运行。 ..但这只是一个猜测。有什么想法吗?
K。