对 arm 内联汇编的不同 clobber 描述的混淆

Confusion about different clobber description for arm inline assembly

我正在学习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 phone 上测试,对于 arm32,r0 生成正确的结果,但 r1 不会。对于 arm64,r1x1 生成正确的结果,而 r0 不会。为什么在 arm32 和 arm64 上它们不同?具体规则是什么,在哪里可以找到?

ARM / AArch64 语法是 mov dst, src

你的 asm 语句只有在编译器恰好为 "=r" 输出和 "r" 输入选择相同的寄存器时才有效(或者类似的,给定额外的 x 浮动副本左右)。

不同的破坏者只会扰乱编译器的寄存器分配选择。查看生成的 asm(gcc -Shttps://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
    );