IA-32汇编(AT&T语法)函数返回调用者后触发段错误求助
IA-32汇编(AT&T语法)函数返回调用者后触发段错误求助
老哥,我看你这个段错误大概率是栈平衡没处理到位导致的,毕竟IA-32汇编里栈指针错位的话,ret指令取返回地址时会拿到非法值,直接触发段错误。先把你贴的代码完整放出来方便分析:
.globl counteq counteq: pushl %ebp movl %esp, %ebp pushl %ebx subl $4, %esp movl $0, -4(%ebp) movl 8(%ebp), %eax movl 12(%ebp), %ecx movl 16(%ebp), %edx
我之前写AT&T风格的IA-32汇编时也踩过类似的坑,给你列几个最可能的问题点:
- 局部变量空间没回收:你用
subl $4, %esp给局部变量分配了4字节空间,但如果函数返回前没执行addl $4, %esp回收这部分空间,栈指针位置就会错位,导致后续恢复ebp和取返回地址时出错。 - 非易失性寄存器没恢复:
ebx属于IA-32调用约定里的非易失性寄存器,你开头pushl %ebx保存了它,但返回前必须执行popl %ebx恢复,不然调用者的ebx寄存器值被破坏,后续操作很可能出问题,甚至间接导致栈错误。 - 栈帧恢复不完整:函数结尾必须严格按照栈帧创建的逆过程恢复:先把栈指针恢复到ebp的位置(
movl %ebp, %esp),再弹出之前保存的ebp(popl %ebp),最后执行ret返回。少了这几步,栈指针和基址指针位置完全不对,ret肯定会跳错地址。
给你补一个正确的函数结尾示例,你可以对照着补全你的代码:
# 这里放你的循环计算逻辑,最终把返回值放到%eax里(IA-32 cdecl约定返回值在eax) addl $4, %esp # 回收局部变量的4字节空间 popl %ebx # 恢复之前保存的ebx寄存器 movl %ebp, %esp # 把栈指针恢复到ebp的位置 popl %ebp # 恢复调用者的ebp寄存器 ret # 返回调用者,此时栈上正好是返回地址
另外你也可以顺手检查下:
- 函数参数的访问是否正确:8(%ebp)是第一个参数,12(%ebp)第二个,16(%ebp)第三个,这部分你写的没问题,但如果传入的参数是无效指针,访问时也会触发段错误,但你说返回后才出错,所以这个概率相对小。
- 编译链接时的选项是否正确:比如得用
gcc -m32编译32位程序,要是误用了64位编译选项,也可能出现奇怪的栈错误。
内容来源于stack exchange




