You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何等量push/pop操作会导致x86-64 NASM程序崩溃?

用push/pop传递NASM函数参数触发Signal 11错误的原因

在WSL Ubuntu环境下编写x86-64 NASM程序,尝试通过push/pop传递函数参数时,运行后触发报错:

Command terminated by signal 11

移除所有push和pop操作后程序可正常运行,相关代码如下:

section .text
        global _start
_start:
mov edx, len  
mov ecx, msg
push ecx
push edx
call println
mov eax, 1
int 0x80

println:
pop edx
pop ecx
mov ebx, 1     
mov eax, 4   
int 0x80        
ret

section .data

msg db "Hello world!",0xa
len equ $ - msg

错误原因

Signal 11是段错误,本质是你破坏了call指令的工作逻辑:

  • 执行call println时,CPU会自动把当前指令的下一条地址(也就是mov eax, 1的地址)压入栈,这个地址是函数执行完后ret要跳转回去的返回地址。
  • 你的println函数开头直接执行pop edx和pop ecx,这两个操作把栈顶的返回地址弹走了:
    按你的push顺序,栈内结构从栈顶到栈底是「返回地址 → edx的值 → ecx的值」,pop edx实际拿到的是返回地址,pop ecx拿到的是原本的edx值。
  • 当执行ret时,CPU会把当前栈顶的ecx值当成返回地址跳转,这个地址不是合法的代码段地址,直接触发段错误。

修正方案

有几种常见的修复方式:

  1. 临时保存返回地址:先把返回地址弹到寄存器保存,用完参数后重新压栈
println:
pop ebx          ; 保存返回地址到ebx
pop ecx          ; 取出真正的ecx参数
pop edx          ; 取出真正的edx参数
mov eax,4
mov ebx,1
int 0x80
push ebx         ; 把返回地址重新压栈
ret
  1. 使用栈帧访问参数(更规范):通过ebp寄存器定位栈内参数
println:
push ebp
mov ebp, esp
mov ecx, [ebp+8]  ; 跳过ebp和返回地址,取第一个参数
mov edx, [ebp+12] ; 取第二个参数
mov eax,4
mov ebx,1
int 0x80
pop ebp
ret 8             ; ret 8 直接平衡栈,替代调用者的add esp,8
  1. 调用者手动平衡栈:函数内直接通过esp偏移访问参数,调用后清理栈
_start:
mov edx, len  
mov ecx, msg
push ecx
push edx
call println
add esp, 8        ; 清理栈上的两个参数
mov eax,1
int 0x80

println:
mov ecx, [esp+4]  ; 跳过返回地址,取第一个参数
mov edx, [esp+8]  ; 取第二个参数
mov eax,4
mov ebx,1
int 0x80
ret

内容的提问来源于stack exchange,提问作者Amukh1

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 08:16:02