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; }
关键修改说明
- 修正循环逻辑:先完整遍历
str1找到终止null,再进入str2的复制步骤,确保复制代码能被执行。 - 移除错误的字符串指令使用(或正确初始化隐含寄存器):避免因未设置
rsi/rdi导致的无效读取。 - 简化结尾处理:直接复制
str2的终止null,无需额外手动添加,避免破坏已写入的内容。 - 调整操作数约束:
str2改用只读的r约束,符合const指针的语义。
内容的提问来源于stack exchange,提问作者Sebastien Fnt
相关产品推荐
相关产品推荐

