aarch64 g++:__asm中的MOV只移动64位值的低32位

aarch64 g++: MOV in __asm only moves lower 32 bits of a 64-bit value

本文关键字:64位 移动 32位 MOV g++ asm 中的 aarch64      更新时间:2024-05-23

我正在使用arch64-linux-gnu-g++(版本7.5.0(和标准集C++17为aarch64机器交叉编译代码。我的代码包括以下内容:

uint64_t inRef = 0x ... ;  
...  
__asm("MOV X8, %[input_i];"  
:  
: [input_i] "r" (inRef)  
: "x8"  
);

我正在将值打包到inRef中,并试图让寄存器X8保存inRef的值,以便稍后在程序中处理。当我打印inRef的值时,我可以确认它确实包含64位值。

然而,我在程序执行中看到的是,实际上只有inRef的底部32位被传递给X8,尽管inRef是uint64_t,X8作为aarch64系统的一部分,也是64位。我已经尝试过查看约束字符("r"(,但根据文档,这应该指64位寄存器[1]。我还尝试使我的代码更加明确,如[2]所示,并使用以下内容:

register std::uint64_t x7 asm("x7") = 0x ... ;  
...  
__asm__ volatile("MOV X8, %[input_i];"  
:   
: [input_i] "r" (x7)  
: "x8"  
);   

不幸的是,同样的错误也发生了。我已经验证了我的机器实际上是一台aarch64机器,它的X寄存器确实是64位的,所以我怀疑问题可能在代码或编译中。总之,如何将aarch64中的整个64位变量移动到寄存器中?

参考文献:
[1]http://infocenter.arm.com/help/topic/com.arm.doc.100067_0610_00_en/qjl1517569411293.html
[2] 安卓工作室64位嵌入式ARM组件

您所做的实际上看起来是正确的。

对于简单的asm包含,您可以使用引用%0%1等变量的"索引"。Number是clobber列表中变量的索引

void f0 (void* self, uint64_t ref) 
{
asm volatile("mov x8, %0" :: "r" (ref) : "x8");
}

在某些情况下,您可能希望强制64位寄存器使用属性%x0表示64位寄存器,或%w0表示32位寄存器。当32位的值被强制输入64b寄存器时,这是一种有用的情况。

void f1 (void* self, uint64_t ref)
{
asm volatile("mov x8, %x0" :: "r" (ref) : "x8");
// asm volatile("mov w9, %0" :: "r" (ref) : "x9"); <-- 'mov w9, x1' is generated, that's unsupported op
asm volatile("mov w9, %w0" :: "r" (ref) : "x9"); <-- this is fine
}

或者尽量在clobber中使用name。x/w属性仍然可以使用

void f2 (void) 
{
uint64_t ref{0xdeadbeefdeadbeef};  
asm volatile("mov x8, %x[val]" ::[val] "r" (ref) : "x8");
}

Godbolt上相同:https://godbolt.org/z/z6vKqx6bT