首页 > 解决方案 > 为什么堆栈上参数的顺序是这样的顺序,即第一个参数位于最低地址,第二个位于第二低地址,依此类推

问题描述

我的计算机体系结构教授要求我们解释为什么参数以相反的顺序放入堆栈。

我的意思是说,当我们想要调用一个接收 2 个整数的普通函数时,我们将堆栈扩展至少 24 个字节,以便我们为寄存器创建一个 home 部分,a0 - a3以便我们有足够的空间来存储寄存器的值ra并对齐堆栈,使 sp 位于 8 的倍数的地址上。

为什么 register a0is at sp + 0, register a1atsp + 4等?

我唯一想到的是它只是纯粹的约定,但如果它只是纯粹的约定,没有理由问我参数顺序相反的原因......

标签: assemblyparameter-passingmipscalling-convention

解决方案


如果调用约定在寄存器中传递参数,则根本不需要将它们存储到堆栈。呼叫者在呼叫之前保留家庭空间,但由被呼叫者选择如何使用它。

(进行调试构建的编译器通常会将其参数存储到内存中,但它可以选择做任何它想做的事情)。

调用约定仅在您的参数多于寄存器中时才定义事物:在这种情况下,所有 C 约定都将较早(更左)的 args 放在较低的地址,因此函数之类printf的不需要知道总共有多少个 args找到例如第 6 个。这使得它不是一个错误printf("hello\n", 1, 2, 3, 4);。Printf 将永远不会查看第一个之后的 args,并且不在乎调用者是否将 a 放入4堆栈。

如果您希望在溢出寄存器 args 时保持一致(这基本上是家庭空间的全部点),那么您可以将它们与第一个 arg 一起存储在最低地址。


我不是 MIPS 调用约定方面的专家。由于jal不修改$sp,我猜被调用者可能负责保留“家庭空间”。
但是,如果被调用者保留家庭空间,那么这只是他们可以根据需要做的可选事情,并且不需要特殊的名称!

这在 Windows x64 中有所不同,例如,call指令将返回地址压入堆栈,因此调用者在调用之前保留影子空间非常重要,以便被调用者可以创建一个连续的 args 数组。

但是由于 MIPSjal将返回地址传递到 中$ra,而不是在堆栈中,因此没有理由将其烘焙到调用约定中。


推荐阅读