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

C调用约定中栈参数的移除方式:对esp加8的疑问

关于x86汇编中add esp,8移除栈参数的疑惑解答

你说得没错,栈中原来分配的参数空间物理上仍然存在,内存里的参数值也不会自动消失。这里的“移除参数”是逻辑层面的操作,核心是通过调整栈顶寄存器esp,让栈的有效区域跳过这些参数,具体细节如下:

栈的核心工作逻辑

x86架构中栈是向下生长的:push指令会先把esp减4(32位环境),再把数据写入esp指向的地址;pop则是先读取esp指向的数据,再把esp加4。栈的有效范围由esp(栈顶)和ebp(栈底,可选)共同界定,超出esp上方的内存(更高地址)不属于当前栈的有效区域。

结合你的代码看add esp,8的作用

我们一步步拆解调用AddTwo时的栈变化(假设初始esp=0x1000):

  1. push 6 → esp=0x0FFC,[0x0FFC]=6
  2. push 5 → esp=0x0FF8,[0x0FF8]=5
  3. call AddTwo → 把返回地址压栈,esp=0x0FF4
  4. 进入AddTwo执行完ret后,esp回到0x0FF8(ret会弹出返回地址到eip,esp加4)
  5. 执行add esp,8 → esp=0x0FF8+8=0x1000,回到调用AddTwo前的初始位置

此时,原来存储参数5和6的内存0x0FF8、0x0FFC依然存在,但esp已经指向更高的地址,后续的栈操作(比如push、call)会直接覆盖这些旧参数的空间,程序不会再把它们当作栈的有效数据处理——这就是“移除参数”的实际含义。

为什么必须执行这个操作?

如果不执行add esp,8,esp会停在0x0FF8,后续Example1的ret指令会错误地把参数5当作返回地址弹出,直接导致程序崩溃。调整esp是为了让栈恢复到调用前的状态,保证后续栈操作的正确性。

格式化后的示例代码

调用方代码:

Example1 PROC
   push 6
   push 5
   call AddTwo
   add esp,8 ; 逻辑上移除栈中的参数
   ret
Example1 ENDP

被调用方代码:

AddTwo PROC
   push ebp
   mov ebp,esp ; 建立栈帧
   mov eax,[ebp + 12] ; 取第二个参数(6)
   add eax,[ebp + 8] ; 取第一个参数(5),相加后存到eax
   pop ebp
   ret
AddTwo ENDP

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 17:10:27