关于手臂内联装配的不同 clobber 描述的混淆

Hax*_*raZ 2 gcc arm inline-assembly arm64

我正在学习ARM内联汇编,并且对一个非常简单的函数感到困惑:将值分配给xto 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;
}
Run Code Online (Sandbox Code Playgroud)

在我的 root Android 手机上进行测试,对于arm32,r0生成正确的结果,但r1不会。对于arm64,r1或者x1生成正确的结果,但r0不会。为什么在arm32和arm64上它们不同?具体规则是什么?在哪里可以找到?

Pet*_*des 5

ARM / AArch64 语法是mov dst, src

"=r"仅当编译器恰好为输出和输入选择相同的寄存器"r"(或类似的东西,给定额外的x浮动副本)时,您的 asm 语句才有效。

不同的破坏者只会扰乱编译器的寄存器分配选择。 查看生成的 asm(gcc -S或在https://godbolt.org/上,尤其是使用-fverbose-asm.)

由于约束与模板字符串中的指令不匹配而导致的未定义行为仍然可能有效;永远不要仅仅因为 asm 语句与一组编译器选项和周围代码一起工作就认为它是正确的。


顺便说一句,x86 AT&T 语法确实使用mov src, dst,并且许多 GNU C 内联汇编示例/教程都是为此编写的。汇编语言特定于 ISA 和工具链,但许多体系结构都有一条名为mov. 看到 amov并不意味着这是 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
    );
Run Code Online (Sandbox Code Playgroud)