You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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

火山引擎 最新活动