gcc - 关于 ARM 内联装配的不同 clobber 描述的混淆

标签 gcc arm inline-assembly arm64

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

最佳答案

ARM/AArch64 语法为 mov dst, src

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

不同的 clobbers 只是扰乱编译器的寄存器分配选择。查看生成的 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
    );

关于gcc - 关于 ARM 内联装配的不同 clobber 描述的混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65056624/

相关文章:

c++ - 有没有办法从 GCC 获取字符串文字?

c - 是什么让这个结构不完整?

c - 是否可以访问 C 中的 32 位寄存器?

gcc - cygwin 中 gcc 的正确包名是什么?

c - 对 `main' 和 _sbrk 的 undefined reference - 自己的静态库中的启动代码

linux - 是否可以在线程之间共享一个寄存器?

c++ - 在非操作系统 Arm 板上使用 'fopen'

c - 在 core_cm4.h 上,为什么会有类似 ((uint32_t)(int32_t)IRQn) 的转换?

c - ASM 内联调用 C 外部函数

visual-c++ - Visual C++ 中是否有 X64 固有的 8 位原子 CAS (cmpxchg)?