【发布时间】:2018-10-09 18:38:27
【问题描述】:
在Assembly Language, Seventh Edition for x86 Processors by Kip Irvine 的第 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指令提供了一个整数参数,该参数在返回调用过程后又向ESP 加8。整数必须等于过程参数占用的堆栈空间: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 调用约定允许子例程声明可变数量的参数。调用者可以决定它将传递多少个参数。
【问题讨论】:
-
答:嗯,显然是的?调用约定确实定义了子程序应该如何返回(即使用什么机制来给子程序返回点)以及 CPU 应该处于什么状态,因此子程序末尾的清理代码与调用约定相关(尽管您可以如果您发现一些更适合您的情况的方法,例如跳到其他子程序的尾部而不是调用它等,也可以以替代方式实现它。)=所以我不确定问题是什么,确切地说是什么预期答案?
-
问题是什么? STDCALL 和 CDECL 在概念上 之间的主要区别在于 CDECL 允许使用 var args 并且 STDCALL 按 调用者 预期 处理参数,而 CDECL 处理caller 使用的它们(是的,早期的 C 允许这样做)。
标签: x86 x86-64 calling-convention stdcall cdecl