汇编语言写入数组遇Segmentation fault错误,求问题原因及解决方法
问题分析与修复方案
你的汇编代码存在几个关键错误,直接导致了段错误,逐个拆解说明:
1. 直接用内存符号做比较操作
cmp %ecx, array_len这行是核心错误之一:array_len是.data段中分配的内存地址,而非存储在该地址里的长度数值。你需要先把array_len中的值加载到寄存器,再和循环计数器ecx比较:
movl array_len, %edx # 将数组长度从内存读取到edx寄存器 cmp %ecx, %edx je l_exit
2. scanf调用的参数逻辑错误
C标准库的scanf需要传入格式串和存储输入值的地址两个参数,你当前只压入了格式串,缺少存储地址。另外,你用pushl %eax保存寄存器的时机完全错误——scanf会直接覆盖eax(返回成功读取的元素个数),正确的调用方式应该是:
# 替换原循环内的scanf调用代码 leal (%edi, %ecx, 4), %ebx # 计算当前数组元素的内存地址 pushl %ebx # 压入存储输入值的地址 pushl $inputFormat call scanf addl $8, %esp # 手动平衡栈,替代两次无意义的popl
用addl $8, %esp清理栈比两次popl更简洁,也避免了错误覆盖寄存器。
3. 错误理解scanf的返回值
scanf不会把输入的数值存在eax里——eax返回的是成功读取的元素数量,输入的数值会直接写入你传入的地址中。你之前的movl %eax, (%edi, %ecx, 4)完全逻辑错误,要么直接让scanf把值写入数组元素地址(如上面的代码),要么先存在临时变量再转存。
修复后的循环完整代码
xorl %ecx, %ecx lea array, %edi movl array_len, %edx # 提前加载数组长度到寄存器,避免每次循环都读内存 l_loop: cmp %ecx, %edx je l_exit # 调用scanf写入当前数组元素 leal (%edi, %ecx, 4), %ebx pushl %ebx pushl $inputFormat call scanf addl $8, %esp # 可选:检查scanf是否成功读取,避免输入错误导致死循环 cmpl $1, %eax jne l_exit incl %ecx jmp l_loop l_exit: # 这里添加程序退出逻辑,比如ret
额外注意事项
- 栈平衡:调用C函数后,要么用
addl $n, %esp(n为参数总字节数),要么用pop清理栈,不要混用导致栈错位。 - 寄存器保护:ebx、esi、edi属于非易失性寄存器,调用C函数前需要手动push到栈保存,调用后再pop恢复,避免被C函数破坏。
内容的提问来源于stack exchange,提问作者Iustin
相关产品推荐
相关产品推荐

