【发布时间】:2016-07-21 01:53:41
【问题描述】:
我无法理解内联汇编程序的一些问题。
我有一个内联汇编器的功能。在 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 已损坏,一切都崩溃了。
我应该如何定义暂存器以避免这种情况?
【问题讨论】:
-
当您添加
[reg]时,val 不再是%0,而是变成了%1。 -
@DavidWohlferd,是的,谢谢。顺便说一句
[reg]"=r"(reg)仍然无法正常工作。在某些情况下,编译器对val和reg使用相同的寄存器,所以我得到mrc r3...; orr r3, r3, r3; mcr r3...;。[reg]"+r"(reg)实际上解决了问题,但现在编译器显示错误'reg' is used uninitialized...并且有必要将转储值分配给reg并出现额外的指令。能修好吗? -
我知道你已经解决了,但是在第一个代码块中,我相信你遇到的问题是根据 ARM EABI 调用约定,函数的第一个参数将是在
r0中,因此该代码可能会破坏uint32_t val和mrc 15, 0, r0, ...。同样,在 ARM EABI 中,r4-8,r10,r11被认为是“变量寄存器”,所以我认为如果你使用其中之一,你会很好。 -
@rjp ,1) 问题不在于第一个块。 2)当
r0被选中编译器将在asm volatile987654343 @之前保留值@并在后面恢复。 span>
标签: gcc assembly arm inline-assembly