我正在学习 ARM 内联汇编,并对一个非常简单的函数感到困惑:将 x
的值分配给 y
(两者都是 int
类型),在arm32 和arm64 上为什么需要不同的clobber 描述?
这是代码:
#include <arm_neon.h>
#include <stdio.h>
void asm_test()
{
int x = 10;
int y = 0;
#ifdef __aarch64__
asm volatile(
"mov %w[in], %w[out]"
: [out] "=r"(y)
: [in] "r"(x)
: "r0" // r0 not working, but r1 or x1 works
);
#else
asm volattile(
"mov %[in], %[out]"
: [out] "=r"(y)
: [in] "r"(x)
: "r0" // r0 works, but r1 not working
);
#endif
printf("y is %d\n", y);
}
int main() {
arm_test();
return 0;
}
在我的 root Android 手机上进行测试,对于 arm32,r0
生成正确的结果,但 r1
不会。对于arm64,r1
或x1
生成正确的结果,而r0
不会。为什么在arm32和arm64上它们不同?具体规则是什么?在哪里可以找到它?
最佳答案
ARM/AArch64 语法为 mov dst, src
仅当编译器恰好为 "=r"
输出和 "r"
输入选择相同的寄存器时,您的 asm 语句才有效(或类似的情况,给定x
的额外副本漂浮在周围)。
不同的 clobbers 只是扰乱编译器的寄存器分配选择。查看生成的 asm(gcc -S
或 https://godbolt.org/ ,尤其是使用 -fverbose -asm
。)
由于约束与模板字符串中的指令不匹配而导致的未定义行为仍然可能有效;永远不要仅仅因为 asm 语句与一组编译器选项和周围代码一起工作就认为它是正确的。
顺便说一句,x86 AT&T 语法确实使用mov src, dst
,并且许多 GNU C 内联汇编示例/教程都是为此编写的。汇编语言特定于 ISA 和工具链,但许多体系结构都有一条名为 mov
的指令。看到 mov
并不意味着这是一个 ARM 示例。
此外,您实际上不需要 mov
指令来使用内联汇编来复制有效的。只需告诉编译器您希望输入位于它为输出选择的同一寄存器中,无论发生什么情况:
// not volatile: has no side effects and produces the same output if the input is the same; i.e. the output is a pure function of the input.
asm (""
: "=r"(output) // pick any register
: "0"(input) // pick the same register as operand 0
: // no clobbers
);
关于gcc - 关于 ARM 内联装配的不同 clobber 描述的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65056624/