x86汇编实现str2int函数触发Segmentation Fault问题求助
问题定位与修复
段错误根本原因
你遇到的段错误主要是汇编代码编译架构不匹配导致的:在64位系统下,as汇编器默认生成64位目标文件,而你用gcc -m32链接32位C代码时,会出现指令集不兼容,导致程序执行时栈帧混乱、寄存器值异常,最终触发非法内存访问。
其次,代码本身存在两处逻辑问题,虽不直接导致段错误,但会影响功能正确性:
- 未遵循x86 cdecl调用约定,未保存/恢复非易失性寄存器
edi、ebx - 循环条件错误,遗漏处理字符串索引0的字符
- 全局变量
number未重置,多次调用会导致结果累加
修复步骤
1. 正确编译32位汇编代码
编译汇编文件时必须指定--32参数,生成32位目标文件:
as --32 -o string2integer.o string2integer.s as --32 -o count_chars.o count_chars.s gcc -m32 -o test test.c string2integer.o count_chars.o
2. 修正str2int函数代码
以下是修复后的汇编代码,包含寄存器保护、循环逻辑修正和全局变量重置:
#string2integer.s .data number: .long 0 .globl str2int .type str2int, @function str2int: pushl %ebp movl %esp, %ebp # 保存非易失性寄存器(cdecl约定要求) pushl %edi pushl %ebx # 重置全局变量number为0 movl $0, number # 获取字符串地址 movl 8(%ebp), %edi # 调用count_chars获取字符串长度 pushl 8(%ebp) call count_chars addl $4, %esp # 初始化计数器为最后一个字符索引 movl %eax, %ecx decl %ecx # 初始化乘数为1 movl $1, %ebx str2int_lp: # 当计数器小于0时退出循环(处理所有索引从len-1到0) cmpl $-1, %ecx je str2int_end # 读取当前字符并转换为数字 movzbl (%edi,%ecx,1), %eax subl $'0', %eax # 计算当前位的数值并累加 imull %ebx, %eax addl %eax, number # 更新计数器和乘数 decl %ecx imull $10, %ebx jmp str2int_lp str2int_end: # 准备返回值 movl number, %eax # 恢复非易失性寄存器 popl %ebx popl %edi # 销毁栈帧 movl %ebp, %esp popl %ebp ret
3. 验证修复
编译运行后,输入字符串"331"会正确输出331,且多次调用不会出现累加错误,也不会触发段错误。
内容的提问来源于stack exchange,提问作者Umutcan Akyol
相关产品推荐
相关产品推荐

