使用全局 C 变量的 IAR 内联汇编

IAR inline assembly using global C variable

我正在为 ARM 6.50.4 功能安全版本 6.50 使用 IAR Embedded Workbench 而且我似乎无法使汇编内联指令正常工作。

对于背景: 我正在尝试使用 PIT 中断在 ARM7TDMI 上实现上下文切换。 保存当前上下文时,我必须获取中断函数的堆栈地址,该地址保存在一个全局 C 变量中,该变量在同一个 c 文件中声明:

unsigned int* ptTask_CurrentTask;

__irq void SysIrqHandler( void )
{
// ... saving registers
__asm volatile( "LDR    R0, %0\n\t"  ::"r"(ptTask_CurrentTask)               );     
//... save the new top of stack
//select new task and restore associated registers
}

根据我从 EWARM_DevelopmentGuide.ENU.pdf 中收集到的信息,上面的指令应该使用正确的语法。 我也尝试了不同的格式化指令的方法,但我得到的是:

Error[og006]: Syntax error in inline assembly: "Error[401]: Operand syntax error".

现在,当我将完整的上下文保存程序集例程导出到单独的 .s 文件并从 c 调用该函数时,以下指令工作正常。 LDR R0, =ptTask_CurrentTask

既然汇编指令在他们自己的工作中,我执行内联汇编指令的方式肯定有问题,但我看不出有什么问题。

由于 r 约束,编译器已经为您将值加载到寄存器中,您不需要自己执行 LDR%0 引用了一个已经包含 ptTask_CurrentTask 值的寄存器。您可以使用 -S 选项检查或反汇编编译器是否确实为您加载:

__asm volatile( ""  ::"r"(ptTask_CurrentTask));

变为:

    ldr     r3, .L3        # these two are generated by the compiler
    ldr     r3, [r3, #0]   # for loading the operand
    ... # here comes your asm code
.L3:
    .word   ptTask_CurrentTask

在这种情况下,编译器选择了 r3。如果你在r0中特别需要它,你可以使用一个寄存器变量。

"r" 约束指示通用寄存器,因此它最终发出 LDR R0, Rx,这确实是无效语法。如果您真的想在汇编代码中执行实际的指针取消引用,请直接嵌入正确的语法:

__asm volatile( "LDR R0, [%0]\n\t" ::"r"(ptTask_CurrentTask));

或者,更好的是,使用适当的约束来指示它是内存操作数(指针)并将语法留给编译器:

__asm volatile( "LDR R0, %0\n\t" ::"m"(ptTask_CurrentTask));

或者浪费一条额外的指令,让编译器操心负载:

__asm volatile( "MOV R0, %0\n\t" ::"r"(*ptTask_CurrentTask));

无论哪种方式,直接触摸 r0 而不在 clobber 列表中声明它可能是一个坏主意...