i386汇编实现C可调用的字符串字符计数功能出现死循环如何修复?
问题排查与修复方案
你的代码死循环的核心原因是没有正确递增字符串指针,同时还存在几处汇编语法和调用约定的错误,具体问题和修复点如下:
存在的问题
- 指针未递增导致死循环:你当前的
incb %bl修改的是从字符串中读取到的当前字符值,而非指向字符串的指针%esi,导致每次循环永远读取字符串的第一个字符,永远无法走到结束符\0
- 指针未递增导致死循环:你当前的
- AT&T汇编立即数语法错误:
cmp 0, %bl中的立即数0缺少$前缀,会被识别为内存地址0而非数字0,同时指令未指定操作长度后缀,可能产生预期外的行为
- AT&T汇编立即数语法错误:
- 未遵循cdecl调用约定保存寄存器:
%esi属于32位C调用约定中被调用者需保留的寄存器,你直接修改未做栈保存,会导致调用该函数的上层C程序运行异常
- 未遵循cdecl调用约定保存寄存器:
- 冗余栈空间分配:
subl $12, %esp分配的12字节栈空间没有被使用,属于冗余代码
- 冗余栈空间分配:
修复后的完整代码
.text .global count count: pushl %ebp # 构建栈帧 movl %esp, %ebp pushl %esi # 保存被调用者需保留的esi寄存器 movl $0, %eax # 初始化计数器(返回值存在eax中) movl 8(%ebp), %esi # 取第一个参数:字符串指针string movb 12(%ebp), %ch # 取第二个参数:待匹配字符c,存到ch避免和后面的bl冲突 check: movb (%esi), %bl # 读取当前指针指向的字符 cmpb $0, %bl # 判断是否是字符串结束符\0 je done # 到结尾则退出 cmpb %ch, %bl # 对比当前字符和目标字符 je found # 匹配则计数器+1 back: incl %esi # 指针递增,指向下一个字符(核心修复点) jmp check found: addl $1, %eax # 计数器+1 jmp back # 回到公共的指针递增逻辑 done: popl %esi # 恢复esi寄存器 movl %ebp, %esp # 销毁栈帧 popl %ebp ret .end
修复说明
- 删掉了冗余的栈空间分配代码
- 增加了
%esi的入栈保存和出栈恢复逻辑,符合cdecl调用约定 - 把
incb %bl替换为incl %esi,每次循环正确移动字符串指针 - 给所有字节操作的cmp指令加上了
b后缀,立即数加上了$前缀,符合AT&T汇编语法 - 拆分出公共的指针递增逻辑,避免重复写相同代码
内容的提问来源于stack exchange,提问作者leaTheBest
相关产品推荐
相关产品推荐

