有一些调用约定(例如pascal
,stdcall
),但就我而言,C 确实使用cdecl
(C 声明)。这些约定中的每一个在调用者将参数加载到堆栈上的方式上都略有不同,分别由哪个(调用者/被调用者)进行清理。
谈到清理,这是我的问题。我不明白:有三种不同的东西吗?
- 堆栈清洁
- 将指针移回倒数第二个堆栈帧
- 堆栈恢复
或者我应该怎么看他们?
此外,这个问题的目标基本上是可变参数函数如何在调用 Pascal 等约定或被stdcall
调用者应该清除/清理/恢复(我不知道哪个操作)堆栈的地方工作 - 但他不知道有多少参数它会收到。
编辑
为什么将参数压入堆栈的顺序如此重要?您仍然有第一个参数(不是来自省略号的稳定参数),它为您提供有关 - 例如 - 变量参数数量的信息。还有一个“守护者”可以添加到省略号标点符号中,并且可以用作变量部分结束的标记,独立于调用约定。在这个链接中,为什么调用者和被调用者都应该恢复这些寄存器的值,如果他们在搞砸之前都保存了他们的状态?不应该只有其中一个(例如调用者)在调用函数之前将它们保存在堆栈中,仅此而已?另外,在同一个链接上
“因此,堆栈指针 ESP 可能会上下波动,但 EBP 寄存器保持固定。这很方便,因为这意味着我们始终可以将第一个参数称为 [EBP + 8],而不管在其中完成了多少推送和弹出操作功能。”
推送变量和局部变量在内存中是连续的。使用 EBP 推荐他们的优势在哪里?即使堆栈大小发生变化,它们之间也永远不会有一些动态偏移。
我读过的材料之一是这个网站(只是开始),以便更好地了解stack frame的确切含义。然后我继续阅读并找到了这些堆栈概述和调用堆栈教程,但他们不知何故错过了我需要的部分。当你调用函数时到底发生了什么(我不明白指令“调用地址”后跟a push
堆栈上的下一个指令值,这意味着返回值)。谁控制退货地址?呼叫者,召集者?被调用者?当被调用者返回时,程序继续执行一条指令,该指令是从寄存器读取操作还是什么?