手臂;内联汇编;使用暂存器;

arm; inline asm; use scratch register;

内联汇编程序存在一些我无法理解的问题。

我有一个内联汇编程序的函数。在 ASM 块内,我需要使用一些临时寄存器来修改一些系统值。

void setHW(uint32_t val) {
    asm volatile (
        mrc 15, 0, r0, ...
        orr r0, r0, %0 
        mcr 15, 0, r0, ...
        : :"r"(val) :"r0"
    );
}

实际上函数是由编译器内联的,没关系,代码仍然运行良好。

当我尝试用一​​些存根变量替换硬编码的 r0 时出现问题,以便编译器可以选择最好的寄存器来使用。看起来像这样

void setHW(uint32_t val) {
    uint32_t reg;
    asm volatile (
        mrc 15, 0, %[reg], ...
        orr %[reg], %[reg], %0 
        mcr 15, 0, %[reg], ...
        :[reg]"=r"(reg) :"r"(val) :
    );
}

现在编译器自己选择寄存器但实际上破坏了 setHW 调用函数的值。 在反汇编器中它看起来像

        add r2, r4, r5       ; caller part, r2 contain some intermedia result
        mrc 15, 0, r2, ...   ; inlined setHW(), r2 is choosen as scratch reg
        orr r2, r2, r0 
        mcr 15, 0, r2, ...
        ; caller continue

如您所见,r2 已损坏,一切都崩溃了。

我应该如何定义临时寄存器来避免这种情况?

这样的事情怎么样:

void setHW(uint32_t val) {
    uint32_t reg;
    asm volatile (
        mrc 15, 0, %[reg], ...
        orr %[reg], %[reg], %[val] 
        mcr 15, 0, %[reg], ...
        :[reg]"=&r"(reg) :[val] "r"(val) :
    );
}

请注意 =&r 以修复早期的破坏问题(有关 & 的说明,请参阅 https://gcc.gnu.org/onlinedocs/gcc/Modifiers.html)。