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

GCC环境下Intel语法内联汇编字符串拼接问题求助

问题分析与修复

你的代码核心问题是循环逻辑完全颠倒,导致复制第二个字符串的代码从未执行,同时还存在字符串指令使用错误和冗余的结尾处理问题,以下是具体分析和修复方案:

核心错误点

  • 循环跳转逻辑颠倒:原代码中,当str1还没到结尾(当前字符不为0)时,直接跳转到标签2执行终止逻辑,根本不会进入str2的复制步骤,这就是为什么只能打印第一个字符串。
  • lodsb/stosb使用错误:这两个字符串指令依赖rsi(源指针)和rdi(目的指针)寄存器,但你把str2存在rbx中,完全没初始化rsi,导致lodsb读取的是随机内存,而非str2的内容。
  • 冗余的结尾null处理:复制完str2后,你额外执行dec %%rax再写入null,这会覆盖掉刚复制的str2的终止null,甚至破坏前面的内容。
  • 操作数约束不合理:str2是const char*,用+r(读写)约束不合适,应该用只读的r约束。

修复后的代码(手动指针操作版)

这个版本不用字符串指令,逻辑更直观,避免隐含寄存器的坑:

#include <stdio.h>

void my_strcat(char *str1, const char *str2) {
    __asm__ volatile (
            "mov %[str1], %%rax\n\t"    // rax指向str1起始地址
            "1:\n\t"                     // 循环:找到str1的结尾
            "cmpb $0, (%%rax)\n\t"       // 判断当前字符是否为终止null
            "je 2f\n\t"                  // 找到结尾,跳转到复制逻辑
            "inc %%rax\n\t"              // 未到结尾,指针后移
            "jmp 1b\n\t"                 // 继续循环查找
            "2:\n\t"                     // 开始复制str2
            "mov %[str2], %%rbx\n\t"     // rbx指向str2起始地址
            "3:\n\t"
            "movb (%%rbx), %%al\n\t"     // 从str2读取一个字符到al
            "movb %%al, (%%rax)\n\t"     // 将字符写入str1当前位置
            "cmpb $0, %%al\n\t"          // 判断是否为str2的终止null
            "je 4f\n\t"                  // 是终止符,跳转到结束
            "inc %%rax\n\t"              // 不是终止符,str1指针后移
            "inc %%rbx\n\t"              // str2指针后移
            "jmp 3b\n\t"                 // 继续复制下一个字符
            "4:\n\t"                     // 结束:无需额外加null,已复制str2的终止符
            : [str1] "+r" (str1)
            : [str2] "r" (str2)
            : "rax", "rbx", "al", "memory"
    );
}

int main() {
    char str1[20] = "Hello";
    char str2[20] = " world!";
    my_strcat(str1, str2);
    printf("Concatenated string: %s\n", str1);
    return 0;
}

修复后的代码(字符串指令版)

如果想使用lodsb/stosb,必须正确初始化它们依赖的rsi和rdi寄存器:

#include <stdio.h>

void my_strcat(char *str1, const char *str2) {
    __asm__ volatile (
            "mov %[str1], %%rdi\n\t"    // rdi指向str1(stosb的目的指针)
            "mov %[str2], %%rsi\n\t"    // rsi指向str2(lodsb的源指针)
            "1:\n\t"                     // 循环:找到str1的结尾
            "cmpb $0, (%%rdi)\n\t"
            "je 2f\n\t"
            "inc %%rdi\n\t"
            "jmp 1b\n\t"
            "2:\n\t"                     // 复制str2
            "lodsb\n\t"                  // 从rsi读取字符到al,rsi自动后移
            "stosb\n\t"                  // 将al写入rdi,rdi自动后移
            "testb %%al, %%al\n\t"       // 判断是否为终止null
            "jne 2b\n\t"                 // 非终止符则继续复制
            // 无需额外处理:已复制str2的终止null
            : [str1] "+r" (str1)
            : [str2] "r" (str2)
            : "rdi", "rsi", "al", "memory"
    );
}

int main() {
    char str1[20] = "Hello";
    char str2[20] = " world!";
    my_strcat(str1, str2);
    printf("Concatenated string: %s\n", str1);
    return 0;
}

关键修改说明

  1. 修正循环逻辑:先完整遍历str1找到终止null,再进入str2的复制步骤,确保复制代码能被执行。
  2. 移除错误的字符串指令使用(或正确初始化隐含寄存器):避免因未设置rsi/rdi导致的无效读取。
  3. 简化结尾处理:直接复制str2的终止null,无需额外手动添加,避免破坏已写入的内容。
  4. 调整操作数约束:str2改用只读的r约束,符合const指针的语义。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 08:45:17