为什么堆栈上参数的顺序是第一个参数在最低地址上,第二个在第二低地址上,依此类推
Why is the order of arguments on stack is in such order that the first argument would be on the lowest adress, second on second lowest and so on
我的计算机体系结构教授要求我们解释为什么参数以相反的顺序放入堆栈。
我的意思是说,当我们想要调用一个接受 2 个整数的普通函数时,我们将堆栈扩展至少 24 个字节,以便为寄存器创建一个主页部分 a0 - a3
这样我们就有足够的 space 来存储 ra
寄存器的值并对齐堆栈,以便 sp 位于 8 的倍数的地址上。
为什么寄存器a0
在sp + 0
,寄存器a1
在sp + 4
等等?
我唯一想到的是它只是纯粹的约定,但如果它只是纯粹的约定,没有理由问我反序背后的原因......
如果调用约定在寄存器中传递参数,则根本不需要将它们存储到堆栈。来电者在通话前预留主页space,但由被叫者选择如何使用它。
(进行调试构建的编译器通常会将其参数存储到内存中,但它可以选择做任何它想做的事情)。
调用约定仅在您的参数多于寄存器中时才定义事物:对于这种情况,所有 C 约定都将较早的(最左边的)参数放在较低的地址,因此像 printf
这样的函数不会需要知道总共有多少个参数可以找到,例如第6个。这使得执行 printf("hello\n", 1, 2, 3, 4);
不是错误。 Printf 将永远不会查看第一个参数之后的参数,并且不关心调用者将 4
放在堆栈上。
如果你想在溢出你的寄存器 args 时保持一致(这基本上是 home space 的全部),那么你将它们与第一个 arg 一起存储在最低地址。
我不是 MIPS 调用约定方面的专家。由于 jal
不修改 $sp
,我猜被调用者 可以 负责保留 "home space".
但是,如果被叫方预订了家 space,那么这只是他们可以根据需要做的一个可选的事情,不需要特殊的名字!
这在 Windows x64 中有所不同,例如,call
指令将 return 地址压入堆栈,因此 是 重要的是调用者在调用 space 之前保留影子 以便被调用者可以创建一个连续的参数数组。
但由于 MIPS jal
在 $ra
中传递了 return 地址,而不是在堆栈中,因此没有理由将其纳入调用约定。
我的计算机体系结构教授要求我们解释为什么参数以相反的顺序放入堆栈。
我的意思是说,当我们想要调用一个接受 2 个整数的普通函数时,我们将堆栈扩展至少 24 个字节,以便为寄存器创建一个主页部分 a0 - a3
这样我们就有足够的 space 来存储 ra
寄存器的值并对齐堆栈,以便 sp 位于 8 的倍数的地址上。
为什么寄存器a0
在sp + 0
,寄存器a1
在sp + 4
等等?
我唯一想到的是它只是纯粹的约定,但如果它只是纯粹的约定,没有理由问我反序背后的原因......
如果调用约定在寄存器中传递参数,则根本不需要将它们存储到堆栈。来电者在通话前预留主页space,但由被叫者选择如何使用它。
(进行调试构建的编译器通常会将其参数存储到内存中,但它可以选择做任何它想做的事情)。
调用约定仅在您的参数多于寄存器中时才定义事物:对于这种情况,所有 C 约定都将较早的(最左边的)参数放在较低的地址,因此像 printf
这样的函数不会需要知道总共有多少个参数可以找到,例如第6个。这使得执行 printf("hello\n", 1, 2, 3, 4);
不是错误。 Printf 将永远不会查看第一个参数之后的参数,并且不关心调用者将 4
放在堆栈上。
如果你想在溢出你的寄存器 args 时保持一致(这基本上是 home space 的全部),那么你将它们与第一个 arg 一起存储在最低地址。
我不是 MIPS 调用约定方面的专家。由于 jal
不修改 $sp
,我猜被调用者 可以 负责保留 "home space".
但是,如果被叫方预订了家 space,那么这只是他们可以根据需要做的一个可选的事情,不需要特殊的名字!
这在 Windows x64 中有所不同,例如,call
指令将 return 地址压入堆栈,因此 是 重要的是调用者在调用 space 之前保留影子 以便被调用者可以创建一个连续的参数数组。
但由于 MIPS jal
在 $ra
中传递了 return 地址,而不是在堆栈中,因此没有理由将其纳入调用约定。