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

内嵌汇编实现string_cmp异常排查:始终返回1问题求助

内嵌汇编实现string_cmp的问题排查与修复

尝试用内嵌汇编实现string_cmp函数判断两个字符串是否相等,当前实现无论字符串是否相等都返回1,需排查问题,包括条件跳转指令的选择,以及非空字符串与空字符串对比的场景问题。

用户当前实现代码:

int string_cmp(const char* str1, char* str2) {
int res;

asm volatile (
    "loop1:"
        "mov (%[s1]), %%rsi\n"   // Move the source address to rsi
        "mov (%[s2]), %%rdx\n" //I wanted a name register but i couldnt initialsied rdx for some reason and %0 cannot be tested
        "inc %[s1]\n"
        "inc %[s2]\n" //check for end of a string then comp last char
        "test %%rsi, %%rdx\n"
        "jl neg\n"
        "jg pos\n"
        "cmp $0, %%rsi\n"
        "jne loop1\n"
        "je zero\n"

    "pos:"
        "mov $1, %%eax\n"
        "jmp fin\n"

    "zero:"
        "mov $0, %%eax\n"
        "jmp fin\n"

    "neg:"
        "mov $0xFFFFFFFF, %%eax\n"
        "jmp fin\n"

    "fin:"



    // Continue with the string copy using appropriate instructions
: "=a" (res)
: [s1] "r" (str1), [s2] "r" (str1) //need to initiate variables somewhere
: "%rsi"  // Use these as needed //clobbbered
);
return res;
}

问题根源分析

  • 致命输入参数错误:输入操作数中[s2] "r" (str1)把str2误写为str1,导致两个指针始终指向同一个字符串,这是返回结果异常的核心原因。
  • test指令误用:test %%rsi, %%rdx是对两个寄存器做按位与运算,仅能判断值是否为0,完全无法实现两个字符的大小比较,必须用cmp指令替代。
  • 寄存器宽度不匹配:mov (%[s1]), %%rsi将8位的char加载到64位寄存器rsi中,高位残留的旧数据会干扰后续判断,应改用8位寄存器(如sil、dl)存储字符。
  • 条件跳转逻辑错误:test指令之后用jl/jg跳转完全错误,这类指令基于有符号数大小判断,但test的结果仅影响零标志、符号标志,无法反映两个字符的大小关系。正确做法是用cmp指令后搭配对应跳转:
    • 无符号字符(符合C标准strcmp的默认行为):用jb(小于跳转)、ja(大于跳转);
    • 有符号字符:用jl(小于跳转)、jg(大于跳转)。
  • 指针递增时机错误:先递增指针再判断字符串结束,会跳过最后一个空字符,无法正确识别两个字符串同时结束的场景。
  • Clobber列表不全:代码中修改了rdx但未在Clobber列表声明,且s1/s2被inc修改,应使用"+r"(输入输出操作数)而非"r",否则编译器可能优化掉修改操作。

修复后的代码

int string_cmp(const char* str1, const char* str2) {
    int res;

    asm volatile (
        "loop1:\n"
            // 加载8位字符到低8位寄存器,避免高位数据干扰
            "movb (%[s1]), %%al\n"
            "movb (%[s2]), %%dl\n"
            // 先比较当前字符
            "cmp %%dl, %%al\n"
            // 字符不等时跳转分支
            "jb neg\n"
            "ja pos\n"
            // 判断是否到达字符串末尾
            "test %%al, %%al\n"
            "jz zero\n"
            // 未结束则递增指针继续循环
            "inc %[s1]\n"
            "inc %[s2]\n"
            "jmp loop1\n"

        "pos:\n"
            "mov $1, %%eax\n"
            "jmp fin\n"

        "zero:\n"
            "mov $0, %%eax\n"
            "jmp fin\n"

        "neg:\n"
            "mov $-1, %%eax\n" // 直接用$-1更清晰,等价于0xFFFFFFFF
            "jmp fin\n"

        "fin:\n"
        : "=a" (res), [s1] "+r" (str1), [s2] "+r" (str2) // s1/s2被修改,使用+r标记
        : // 无额外输入参数
        : "%dl" // 声明被修改的寄存器
    );
    return res;
}

修复说明

  1. 修正输入参数错误,让s2正确绑定str2;
  2. 改用8位寄存器存储字符,避免高位数据干扰;
  3. 调整逻辑顺序:先比较字符,再判断是否到达字符串末尾,符合正常的字符串比较流程;
  4. 用cmp指令实现字符比较,搭配jb/ja完成无符号大小判断,对齐C标准strcmp的行为;
  5. 用"+r"标记被修改的指针变量,通知编译器变量会被修改;
  6. 用$-1替代$0xFFFFFFFF,提升代码可读性。

内容的提问来源于stack exchange,提问作者shinny.dogma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 07:27:38