在Kip Irvine 的Assembly Language, Seventh Edition for x86 Processors中,第 325 页,它在8.2.4 32-Bit Calling Conventions下说,
C 调用约定... C 调用约定以一种简单的方式解决了清理运行时堆栈的问题:当程序调用子例程时,它会在
CALL
指令后面加上一条语句,将值添加到堆栈指针 (ESP
) 等于到子程序参数的组合大小。这是一个示例,其中两个参数(5 和 6)在执行CALL
指令之前被压入堆栈,Example1 PROC push 6 push 5 call AddTwo add esp, 8 ret Example1 ENDP
因此,用 C/C++ 编写的程序总是在子程序返回后从调用程序的堆栈中删除参数。
它继续说
STDCALL 调用约定从堆栈中删除参数的另一种常用方法是使用名为 的约定
STDCALL
。在下面的AddTwo
过程中,我们为指令提供一个整数参数,RET
在返回调用过程后,它又将 8 加到 ESP 中。整数必须等于过程参数占用的堆栈空间字节数:AddTwo PROC push ebp mov ebp,esp mov eax,[ebp+12] add eax,[ebp+8] pop ebp ret 8 AddTwo ENDP
应该指出的是
STDCALL
,像 C 一样,以相反的顺序将参数压入堆栈。通过在RET
指令中包含参数,STDCALL
减少了为子程序调用生成的代码量(通过一条指令),并确保调用程序永远不会忘记清理堆栈。另一方面,C 调用约定允许子例程声明可变数量的参数。调用者可以决定它将传递多少个参数。