如何在NASM中实现strncmp?计数跳转异常问题排查
问题分析与修复
你的my_strncmp函数中cmp rdx, rcx无法触发跳转的核心原因是rdx寄存器被后续指令意外修改,同时还有几处逻辑和拼写错误,以下是具体问题和修复方案:
核心问题点
- rdx寄存器被覆盖:你用
mov dh, byte [rdi]和mov dl, byte [rsi]存储字符,但dh/dl是rdx寄存器的高8位/低8位,这会直接改写传入的第三个参数(最大比较长度),导致cmp rdx, rcx的比较完全失效。 - 标签拼写错误:
.retrun_2少写了一个t,应该是.return_2,错误的标签会导致跳转异常。 - 循环逻辑顺序不合理:当前逻辑在递增计数后才比较字符,且字符结束判断的时机不对,同时不符合
strncmp的标准行为。 - 返回值不符合规范:标准
strncmp返回的是第一个不同字符的差值(str1[i] - str2[i]),而非固定的1/-1。
修复后的汇编代码
section .text global my_strncmp my_strncmp: mov rcx, 0 ; 初始化计数器 .next: cmp rcx, rdx ; 先判断是否已经比较了rdx个字符 je .return_equal ; 达到最大长度,返回0 mov al, byte [rdi] ; 用al存储第一个字符串的当前字符(不破坏rdx) mov bl, byte [rsi] ; 用bl存储第二个字符串的当前字符 cmp al, 0 ; 检查第一个字符串是否结束 je .return_diff cmp bl, 0 ; 检查第二个字符串是否结束 je .return_diff cmp al, bl ; 比较当前字符 jne .return_diff ; 字符不同,返回差值 ; 字符相同,继续下一个 inc rcx inc rdi inc rsi jmp .next .return_equal: mov rax, 0 ret .return_diff: sub rax, rax ; 清空rax mov al, byte [rdi] sub al, byte [rsi] ; 计算差值:str1[i] - str2[i] ; 符号位会自动扩展到rax的高位,符合int返回值要求 ret
修复说明
- 保护rdx寄存器:改用
al和bl存储字符,避免修改作为参数传入的rdx,确保cmp rcx, rdx的比较始终基于原始的最大长度参数。 - 修正标签拼写:移除错误的标签定义,同时简化返回逻辑,用统一的差值计算代替固定返回值。
- 调整循环顺序:先判断是否达到最大比较长度,再处理字符比较,符合
strncmp的逻辑——最多比较n个字符,不管字符串是否结束。 - 遵循标准返回值:通过
sub al, byte [rsi]计算字符差值,利用x86的符号扩展特性,让rax自动成为正确的int返回值。
测试验证
用你的C测试代码调用修复后的函数:
#include <stdio.h> extern int my_strncmp(const char *str1, const char *str2, size_t n); int main(){ printf("%d\n", my_strncmp("string2", "string1", 3)); // 前3个字符相同,返回0 printf("%d\n", my_strncmp("string2", "string1", 7)); // 第7个字符'2'-'1'=1,返回1 return 0; }
编译运行后会得到符合预期的结果,且最大长度的判断逻辑正常生效。
内容的提问来源于stack exchange,提问作者Kings man
相关产品推荐
相关产品推荐

