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

GCC内联汇编在-O2优化选项下失效的原因及解决方法

GCC -O2优化下内联汇编模拟memcpy无输出的原因分析

问题现象

开启GCC的-O2优化选项时,用内联汇编模拟memcpy的代码输出为空:

dst: 

关闭-O2或使用-O1优化时则正常输出:

dst: 123456789

问题代码示例

以下是出现问题的代码:

#include <stdio.h>

int main() {
    char src[] = "123456789";
    char dst[] = "000000000";

    /* Inline assembly to mimic memcpy */
    __asm__ volatile(
        "rep movsb\n"
        :
        : "D" (dst), "S" (src), "c" (9)
        : "memory"
    );

    printf("dst: %s\n", dst);

    return 0;
}

优化后可行代码

将rep movsb封装为static inline函数后,-O2下可正常运行:

#include <stdio.h>

static inline void *__movsb(void *d, const void *s, size_t n) {
  asm volatile ("rep movsb"
                : "=D" (d),
                  "=S" (s),
                  "=c" (n)
                : "0" (d),
                  "1" (s),
                  "2" (n)
                : "memory");
  return d;
}

int main() {
    char src[] = "123456789";
    char dst[] = "000000000";

    __movsb(dst,src,9);

    printf("dst: %s\n", dst);

    return 0;
}

反汇编显示__movsb已被内联,且当拷贝长度为运行时随机值时,memcpy会被调用,而__movsb仍保持内联。

原因解析

问题核心是内联汇编的寄存器约束声明不完整:

  1. 第一个代码仅将dst、src、计数作为输入约束,但rep movsb指令执行时会修改%rdi(对应dst的寄存器)、%rsi(对应src的寄存器)和%rcx(计数寄存器)的内容,代码却未告知编译器这一点。
  2. -O2优化级别下,GCC会尽可能复用寄存器提升效率。由于编译器不知道这些寄存器已被修改,执行printf时直接复用了已经指向dst+9(字符串末尾)的%rdi寄存器,导致输出空字符串。
  3. 封装后的代码通过"=D"(d)、"=S"(s)、"=c"(n)明确声明这些寄存器是输出约束,告诉编译器寄存器值会被修改;同时用"0"(d)等语法表示输入输出复用同一寄存器。这样编译器会重新加载dst的首地址到寄存器用于printf,不会复用被修改后的寄存器值,因此能正常输出。
  4. 注意:虽然两个代码都加了"memory" clobber(告知编译器内存被修改),但它仅影响内存访问的优化,无法让编译器感知寄存器内容的变化,必须通过输出约束声明寄存器的修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 07:04:58