【问题标题】:IAR assembler BKPT immediate as input operandIAR 汇编器 BKPT 立即作为输入操作数
【发布时间】:2019-05-28 14:13:10
【问题描述】:

我正在为 Cortex M4 设备编写闪存加载程序,我想使用断点指令的立即值“返回”驱动 PC 应用程序的值。

虽然对立即数进行硬编码可以正常工作:

__asm("bkpt 0x70");
__asm("bkpt %0" : : "i" (0x70));

只要我想“返回”一些依赖于运行时的东西,比如

uint8_t status = Flash_EraseAll();
__asm("bkpt %0" : : "i" (status));

编译失败

错误[Ta090]:立即操作数不是常数

我尝试使用具有不同连接设置的预处理器宏,但无济于事。

有没有人知道如何将运行时相关状态标志作为即时输入到 IAR 中的 __asm() 块中?根据我阅读 here 的内容,这并不完全可能,但可能有一个聪明的 hacky 方法来做到这一点。

P.S.:是的,作为一种解决方法,我可以使用 switch 语句来列出并硬编码每个可能的状态,但这很丑而且很长。

【问题讨论】:

  • 当您在第一个 ASM 语句中修改 sp 时,您的解决方案是不安全的。 sp的push、断点和恢复必须在同一个asm语句中。
  • @TimothyBaldwin 这可能解释了我遇到的一些奇怪行为。在我修改我的编辑之前,您能否详细说明这究竟是如何不安全的?设备/堆栈工作案例会发生什么?我必须添加 __("bkpt 0x0");是我的代码的最后一条语句
  • 发布您的答案作为答案,人们可​​以对其进行投票。不要通过将其编辑到问题中来赋予它特殊状态。如果它比(半途而废的)现有答案更好,您可以接受自己的答案。
  • @PeterCordes 感谢您的提示,我修改了线程。

标签: c breakpoints inline-assembly iar


【解决方案1】:

我会将值压入堆栈,然后使用带有定义数字的bkpt 指令,因此调试器可以查看堆栈中的此状态。

类似这样的东西(伪代码):

__asm("push %0" : : "i" (status));
__asm("bkpt %0" : : "i" (0x70));

当然你不应该忘记之后清理堆栈。

由于bkpt 仅使用立即数编码,因此您显然不能在运行时更改它,因为您必须修改代码。

【讨论】:

  • 嗯...这不是一个坏主意,而且看起来很简单。没想到。我会等待一段时间,看看是否有人对此有其他想法。谢谢!
  • 两条指令都必须是一个 asm 语句的一部分,否则编译器可能会决定在这些语句之间放置一些编译器生成的指令。此外,大概您需要在恢复后清理堆栈。 (平@davidanderle)。此外,很明显,对于status,您需要一个除"i" 之外的约束,因为"i" 需要一个编译时间常数来替换为立即数。可能你想要"r"(status),你可以再次硬编码bkpt 0x70,除非你想用C宏定义来设置数字。
【解决方案2】:

基于@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”,并将该寄存器的内容存储在堆栈指针的预递减地址下,然后立即用 0 停止 CPU 的执行。

如果目标停止(bkpt 命中),驱动应用程序将轮询目标。如果暂停,通过读取当前 PC 下的 16 位数据 (__asm("bkpt 0x00") -> 0xbe00 -> #imm = 0xbe00 & 0x00ff = 0),应用程序可以确保执行已在右侧停止地方。然后它将读取最终 SP 地址下的 32 位数据,以获取嵌入式代码的执行状态。

通过这种方式,我们可以动态地向外界“报告”更多内容(在本例中为 32 位),而不是来自 bkpt 立即数的静态 8 位代码。

正如@PeterCordes 强调的那样,push 和 bkpt 语句必须在同一个内联汇编指令中,否则编译器可能会决定在语句之间插入代码。此外,SP 必须恢复到 __asm() 之前的值,因为编译器假定对 SP 的唯一控制。

【讨论】:

  • 你没有提到在任何地方恢复SP。有了这个asm,断点处理程序需要在SP中添加4才能恢复,否则inline asm在不告诉编译器的情况下修改了SP。
  • @PeterCordes 我的程序到此结束,所以我不需要恢复任何东西。我想如果有人想在从 bkpt 恢复执行后做任何其他事情,他们可以添加一个“add sp, sp, #4”来撤消 str 所做的事情?
  • 是的。这是一个非常关键的细节,对于任何可能会觉得这很有用的未来读者来说,这是一个非常重要的细节。
  • @PeterCordes 感谢您的帮助,非常感谢!
猜你喜欢
  • 2019-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
  • 2017-06-22
相关资源
最近更新 更多