IAR 汇编程序 BKPT 立即数作为输入操作数
IAR assembler BKPT immediate as input operand
我正在为 Cortex M4 设备编写闪存加载程序,我想 "return" 使用断点指令的立即值为驱动 PC 应用程序赋值。
虽然对立即数进行硬编码工作正常:
__asm("bkpt 0x70");
__asm("bkpt %0" : : "i" (0x70));
一旦我想要 "return" 一些东西 运行-时间依赖性喜欢
uint8_t status = Flash_EraseAll();
__asm("bkpt %0" : : "i" (status));
编译失败
Error[Ta090]: Immediate operand is not constant
我尝试使用具有不同连接设置的预处理器宏,但无济于事。
有没有人知道我如何将 运行 时间相关状态标志作为即时输入到 IAR 中的 __asm()
块?根据我读到的 here,这不太可能,但可能有一个聪明的 hacky 方法来做到这一点。
P.S.: 是的,作为一种解决方法,我可以使用 switch 语句,在其中列出并硬编码每个可能的状态,但这既丑陋又冗长。
我会将值压入堆栈,然后使用带有已定义数字的 bkpt
指令,以便调试器可以查看此状态的堆栈。
类似这样的东西(伪代码):
__asm("push %0" : : "i" (status));
__asm("bkpt %0" : : "i" (0x70));
当然你不应该忘记事后清理堆栈。
由于 bkpt
仅使用立即数编码,您显然不能在运行时更改它,因为您必须修改代码。
根据@Devolus的想法,我得出以下结论:
uint32_t status = Flash_EraseAll();
__asm volatile ("str %0, [sp, #-4]!\n\t" // Push to stack
"bkpt 0x0\n\t" // Halt CPU
"add sp, sp, #4\n\t" // Restore SP
: : "r"(status)); // status as input to __asm()
汇编指令告诉编译器将状态变量放入一个方便的寄存器 "r",并将该寄存器的内容存储在堆栈指针的 pre-decremented 地址下,然后停止 CPU的执行立即数 0。
如果目标停止(bkpt 命中),驾驶应用程序将轮询目标。如果暂停,通过读取当前PC下的16位数据(__asm("bkpt 0x00") -> 0xbe00 -> #imm = 0xbe00 & 0x00ff = 0),应用程序可以确保执行停在了正确的地方。然后它会读取最终 SP 地址下的 32 位数据以获取嵌入式代码的执行状态。
这样一来,我们就可以 "report" 动态地向外界发送更多内容(在本例中为 32 位),而不是来自 bkpt 立即数的静态 8 位代码。
正如@PeterCordes强调的那样,push 和 bkpt 语句必须在同一内联汇编指令中,否则编译器可能会决定在语句之间插入代码。此外,SP 必须恢复为 __asm() 之前的值,因为编译器会单独控制 SP。
我正在为 Cortex M4 设备编写闪存加载程序,我想 "return" 使用断点指令的立即值为驱动 PC 应用程序赋值。
虽然对立即数进行硬编码工作正常:
__asm("bkpt 0x70");
__asm("bkpt %0" : : "i" (0x70));
一旦我想要 "return" 一些东西 运行-时间依赖性喜欢
uint8_t status = Flash_EraseAll();
__asm("bkpt %0" : : "i" (status));
编译失败
Error[Ta090]: Immediate operand is not constant
我尝试使用具有不同连接设置的预处理器宏,但无济于事。
有没有人知道我如何将 运行 时间相关状态标志作为即时输入到 IAR 中的 __asm()
块?根据我读到的 here,这不太可能,但可能有一个聪明的 hacky 方法来做到这一点。
P.S.: 是的,作为一种解决方法,我可以使用 switch 语句,在其中列出并硬编码每个可能的状态,但这既丑陋又冗长。
我会将值压入堆栈,然后使用带有已定义数字的 bkpt
指令,以便调试器可以查看此状态的堆栈。
类似这样的东西(伪代码):
__asm("push %0" : : "i" (status));
__asm("bkpt %0" : : "i" (0x70));
当然你不应该忘记事后清理堆栈。
由于 bkpt
仅使用立即数编码,您显然不能在运行时更改它,因为您必须修改代码。
根据@Devolus的想法,我得出以下结论:
uint32_t status = Flash_EraseAll();
__asm volatile ("str %0, [sp, #-4]!\n\t" // Push to stack
"bkpt 0x0\n\t" // Halt CPU
"add sp, sp, #4\n\t" // Restore SP
: : "r"(status)); // status as input to __asm()
汇编指令告诉编译器将状态变量放入一个方便的寄存器 "r",并将该寄存器的内容存储在堆栈指针的 pre-decremented 地址下,然后停止 CPU的执行立即数 0。
如果目标停止(bkpt 命中),驾驶应用程序将轮询目标。如果暂停,通过读取当前PC下的16位数据(__asm("bkpt 0x00") -> 0xbe00 -> #imm = 0xbe00 & 0x00ff = 0),应用程序可以确保执行停在了正确的地方。然后它会读取最终 SP 地址下的 32 位数据以获取嵌入式代码的执行状态。
这样一来,我们就可以 "report" 动态地向外界发送更多内容(在本例中为 32 位),而不是来自 bkpt 立即数的静态 8 位代码。
正如@PeterCordes强调的那样,push 和 bkpt 语句必须在同一内联汇编指令中,否则编译器可能会决定在语句之间插入代码。此外,SP 必须恢复为 __asm() 之前的值,因为编译器会单独控制 SP。