
通过文档上逐步深入的四个例子,我对栈帧有了更全面的理解:
栈帧是运行时逐步产生的,而不是在调用其他函数那一刻产生的,对于以下例子
int g( int x, int y ) {
int a[32];
... (calculate using x, y, a);
a[1] = f(y,x,a[2],a[3],a[4]);
a[0] = f(x,y,a[1],a[2],a[3]);
return a[0];
}
现在研究g的栈帧,
蓝色区域用来存此函数的局部变量,如a,会占32个word,也就是128个byte
深绿色区域存储当前函数的返回地址,如果当前函数没有调用其他函数,此区域可以没有
浅绿色区域,当函数g内部逻辑要用到 $s 寄存器时,才会在用之前存储好之前的寄存器值(保留现场)
黄色区域,当第一次调用f时,存储参数,无论用不用寄存器传递,都要在栈帧中存。只要调用其他函数,黄色区域必有四个word,但这四个word是空的,只是为了后序f中可能用到而预留的。
灰色区域,用于padding,使得栈帧大小是8的倍数。
当调用完第一次f之后,会重新构建黄色区域的arg4,重新构建四个 $a 寄存器。
容易混淆的点是:
-
栈帧不是调用时的,而是运行时的
-
栈帧在调用结束时销毁,指的是被调用的函数的栈帧,如上例子,调用f后f会有自己的栈帧,f运行结束自己的栈帧会销毁,而g的栈帧在最后g运行结束才会销毁