MIPS的堆栈导致我的大脑溢出

时间:2014-07-15 18:34:26

标签: c assembly stack mips callstack

我绝对无法理解MIPS'堆。通过减去 $ sp 寄存器来分配堆栈上的空间,堆栈在程序的方向上增长,当它增长太多时,它会通过覆盖(或至少尝试)程序而溢出。一旦执行了该功能,我必须通过添加我先减去的相同值来移除堆栈。这对我来说都很好。但有人告诉我,当我保存参数时,我必须分配四个空格,对应于四个第一个参数( $ a0- $ a3 ),并且永远不要使用它们(如所述{ {3}})。为什么?此外,当我构建堆栈时,我必须保存额外的参数。我应该保存"而不是额外的"争论呢? 例如这个C程序的集合:

void f (int x, int y, int z) {
    int array[5], a, b;

    if (x >= y && x != z)
        g(x+1, y+2, z+3, 4, 5);
    else
        h(x-1, y-2, z-3, 4, 5, 6, 7);

    while (z != 0)
        x++
}

我应该在各自的筹码位置保存 $ a0- $ a3 吗?我应该将它们保存在 $ s0- $ s3 中吗?如果我没有部分,我应该保存吗?

3 个答案:

答案 0 :(得分:3)

参数以这种方式传递只是一种惯例。如果你编写了一个程序而你的一个函数正在调用你编写的另一个函数,那么你也可能决定将所有参数传递给堆栈(而不是$ a0- $ a3)或做任何不同的事情......

但是当你调用一个不是你编写的函数(例如一个由C编译器生成的函数)或者你的函数被这样的函数调用时,你必须假设你没有编写的函数的行为就像这里描述的那样

  

当我保存参数时,我必须分配四个空格,对应于四个第一个参数($ a0- $ a3)并且从不使用它们(如此处所述)。为什么呢?

早期的MIPS处理器是专为高端计算机设计的,因此这些惯例背后的主要目标是速度而非可用性。

我只是在想这个“奇怪的”约定:在很多情况下,这个约定会生成最快的代码。所以这就是原因。

  

我是否应该保存“不是额外的”参数?

你可以这样做;但是,您调用的函数将忽略存储在那里的数据。

当编写自己的编译器(我已经做过)时,在堆栈中存储“非额外参数”时应该会容易得多 - 所以这可能是理由。

答案 1 :(得分:2)

来自Wikipedia

的MIPS调用约定
  

32位MIPS最常用的1调用约定是O32 [2] ABI,它将前四个参数传递给寄存器$ a0- $ a3中的函数;后续参数在堆栈上传递。如果被调用者需要保存其参数,则堆栈上的空间保留为$ a0- $ a3,但调用者不会将寄存器存储在那里。返回值存储在寄存器$ v0中;第二个返回值可以存储在$ v1中。

您可以修改$t0,... $t9寄存器而不将它们保存在堆栈中,但可以通过代码调用的任何函数修改它们。如果您需要使用$s0,...,$s7,则必须将它们保存在堆栈中并在返回之前将其还原。

答案 2 :(得分:1)

以下是密切关注热门答案的链接:

取自:Frame Pointer Explanation