You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Clang生成的内联汇编代码是否存在错误?

内联汇编在GCC与Clang下的行为差异及问题解决

我在Intel Mac笔记本上,用自行编译的GNU GCC(命令gnucc)和macOS内置Clang编译同一段包含内联汇编的C代码:

  • GCC编译后的程序输出预期值2
  • Clang编译后的程序输出错误的大数值140701838959608

在Compiler Explorer上测试也得到相同差异结果。反汇编Clang生成的二进制文件后发现,本应执行movq %rcx, (%rax)的指令被替换为movq %rax, (%rax),需要确认是Clang的问题还是内联汇编写法有误。

测试代码

#include "stdio.h"

typedef struct num {
    unsigned long long x;
} num;

int main(int argc, char **argv) {
    struct num anum;
    anum.x = 0;
    __asm__("movq %%rax, %0\n" : "=m" (anum.x) : "rax"(2));
    printf("%llu\n",anum.x);
}

Clang生成的二进制反汇编片段

clang-test:    file format mach-o 64-bit x86-64

Disassembly of section __TEXT,__text:

0000000100003f60 <_main>:
100003f60: 55                        pushq  %rbp
100003f61: 48 89 e5                  movq   %rsp, %rbp
100003f64: 48 83 ec 20               subq   $32, %rsp
100003f68: 89 7d fc                  movl   %edi, -4(%rbp)
100003f6b: 48 89 75 f0               movq   %rsi, -16(%rbp)
100003f6f: 48 c7 45 e8 00 00 00 00   movq   $0, -24(%rbp)
100003f77: 48 8d 45 e8               leaq   -24(%rbp), %rax
100003f7b: b9 02 00 00 00            movl   $2, %ecx
100003f80: 48 89 00                  movq   %rax, (%rax)
100003f83: 48 8b 75 e8               movq   -24(%rbp), %rsi
100003f87: 48 8d 3d 16 00 00 00      leaq   22(%rip), %rdi   ## 0x100003fa4 <_printf+0x100003fa4>
100003f8e: b0 00                     movb   $0, %al
100003f90: e8 09 00 00 00            callq  0x100003f9e <_printf+0x100003f9e>
100003f95: 31 c0                     xorl   %eax, %eax
100003f97: 48 83 c4 20               addq   $32, %rsp
100003f9b: 5d                        popq   %rbp
100003f9c: c3                        retq

Disassembly of section __TEXT,__stubs:

0000000100003f9e <__stubs>:
100003f9e: ff 25 5c 00 00 00         jmpq    *92(%rip)       ## 0x100004000 <_printf+0x100004000>

问题原因及解决方法

这是内联汇编约束写法错误导致的问题:

  • 内联汇编的输入约束部分,不能直接写寄存器名"rax",而应该使用编译器规定的约束符。比如要指定rax寄存器,需用"a"(对应rax/eax/ax/al系列寄存器);如果允许编译器自由选择通用寄存器,用"r"即可。
  • 原代码中的"rax"(2)是无效约束,Clang无法正确解析,因此没有将值2放入rax,反而把anum.x的内存地址加载到rax中,执行movq %%rax, %0后,相当于把anum.x的地址写入了自身,最终输出的就是这个地址值(即你看到的大数值)。GCC对这种错误写法做了兼容处理,碰巧将2放入rax,才得到正确结果。

修正后的代码(指定rax寄存器)

#include "stdio.h"

typedef struct num {
    unsigned long long x;
} num;

int main(int argc, char **argv) {
    struct num anum;
    anum.x = 0;
    __asm__("movq %%rax, %0\n" : "=m" (anum.x) : "a"(2)); // 使用"a"约束指定rax寄存器
    printf("%llu\n",anum.x);
}

更通用的写法(让编译器分配寄存器)

#include "stdio.h"

typedef struct num {
    unsigned long long x;
} num;

int main(int argc, char **argv) {
    struct num anum;
    anum.x = 0;
    __asm__("movq %1, %0\n" : "=m" (anum.x) : "r"(2)); // 编译器自动选择寄存器,用%1引用输入值
    printf("%llu\n",anum.x);
}

内容的提问来源于stack exchange,提问作者David

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 12:16:14