提问人:Zuja Plays 提问时间:4/25/2023 最后编辑:Peter CordesZuja Plays 更新时间:4/25/2023 访问量:138
堆栈帧大小
Stack frame size
问:
如果我正在查看 C 程序的 objdump,这是我的 int 二项式(int n, int k) 函数的 Mips 细分,如果我分配 40 个字节,那就是堆栈帧的大小/大小,还是取决于代码以及其中使用了多少字节(比如它是 16 个字节,因为我只使用 4 个点)。此外,s0 和 s1 等值将存储在堆栈帧中的什么位置?
我有一个测验即将到来,并试图更好地理解 MIPS 功能的细分,因此任何回复都值得赞赏,因为谷歌更令人困惑而不是有帮助。
00400450 <binomial>:
binomial():
400450: 27bdffd8 addiu sp,sp,-40
400454: afbf0024 sw ra,36(sp)
400458: afbe0020 sw s8,32(sp)
40045c: afb1001c sw s1,28(sp)
400460: afb00018 sw s0,24(sp)
400464: 03a0f021 move s8,sp
400468: afc40028 sw a0,40(s8)
40046c: afc5002c sw a1,44(s8)
400470: 8fc20028 lw v0,40(s8)
400474: 1840000b blez v0,4004a4 <binomial+0x54>
400478: 00000000 nop
40047c: 8fc2002c lw v0,44(s8)
400480: 04400008 bltz v0,4004a4 <binomial+0x54>
400484: 00000000 nop
400488: 8fc2002c lw v0,44(s8)
40048c: 8fc30028 lw v1,40(s8)
400490: 0062102a slt v0,v1,v0
400494: 14400003 bnez v0,4004a4 <binomial+0x54>
400498: 00000000 nop
40049c: 0810012c j 4004b0 <binomial+0x60>
4004a0: 00000000 nop
4004a4: afc00010 sw zero,16(s8)
4004a8: 0810014c j 400530 <binomial+0xe0>
4004ac: 00000000 nop
4004b0: 8fc3002c lw v1,44(s8)
4004b4: 8fc20028 lw v0,40(s8)
4004b8: 14620005 bne v1,v0,4004d0 <binomial+0x80>
4004bc: 00000000 nop
4004c0: 24020001 li v0,1
4004c4: afc20010 sw v0,16(s8)
4004c8: 0810014c j 400530 <binomial+0xe0>
4004cc: 00000000 nop
4004d0: 8fc40028 lw a0,40(s8)
4004d4: 0c1000e8 jal 4003a0 <fact>
4004d8: 00000000 nop
4004dc: 00408821 move s1,v0
4004e0: 8fc30028 lw v1,40(s8)
4004e4: 8fc2002c lw v0,44(s8)
4004e8: 00621023 subu v0,v1,v0
4004ec: 00402021 move a0,v0
4004f0: 0c1000e8 jal 4003a0 <fact>
4004f4: 00000000 nop
4004f8: 00408021 move s0,v0
4004fc: 8fc4002c lw a0,44(s8)
400500: 0c1000e8 jal 4003a0 <fact>
400504: 00000000 nop
400508: 02020018 mult s0,v0
40050c: 00001012 mflo v0
...
400518: 0222001a div zero,s1,v0
40051c: 14400002 bnez v0,400528 <binomial+0xd8>
400520: 00000000 nop
400524: 0007000d break 0x7
400528: 00001012 mflo v0
40052c: afc20010 sw v0,16(s8)
400530: 8fc20010 lw v0,16(s8)
400534: 03c0e821 move sp,s8
400538: 8fbf0024 lw ra,36(sp)
40053c: 8fbe0020 lw s8,32(sp)
400540: 8fb1001c lw s1,28(sp)
400544: 8fb00018 lw s0,24(sp)
400548: 27bd0028 addiu sp,sp,40
40054c: 03e00008 jr ra
400550: 00000000 nop
答:
堆栈帧将包含
任何基于内存的局部变量,例如数组
必须保存/恢复才能使用的呼叫保留寄存器。
保存的值属于调用堆栈中更上游的某个调用方
它们被保存和恢复,以便被叫方可以使用这些寄存器,但必须在返回之前恢复它们。这里是 , , .
s8
s1
s0
函数调用后需要的调用杂乱的寄存器
这里是 ,它被嵌套函数调用 (to ) 破坏,但需要其值才能返回给调用者 (of)。
ra
fact
binomial
需要在函数调用中存活的临时变量,或者编译器只想映射到内存的临时变量
这里 16(s8) 是一个变量,它似乎包含最终将成为 v0 中的返回值的内容。
对齐填充,以四舍五入到 8 个字节,从而使堆栈帧与 double 类型的变量很好地对齐,以防某些被调用方将一个变量存储到内存中。
难以解释的随机内容,例如编译器是否希望堆栈大小的 16 位对齐,或者编译器分配了一些未使用的堆栈空间(这不是一个好主意,但也不违法)。
被调用函数参数的空间。
这里的堆栈帧是 40 个字节,也就是 10 个字,它用于存储来自 ra、s8、s1、s0 的值,以及一个(可能是临时的)内存变量,以及被调用方参数的空间(采用一个参数),即使该参数是在 CPU 寄存器中传递的,a0。fact
那么,我数了数,
- S 变量原始值的 3 个字空间(使调用者受益)
- RA 的 1 个字空间(使自己受益)
- 返回值内存变量的 1 字空间(编译器的选择)
- 参数寄存器的 4 个字影子空间
- 1 个字的填充,用于 8 字节堆栈对齐
总共10个字。
此功能用作帧指针,在某些教育环境中很流行,但对于此功能来说,这是一个不必要的设备。请注意,帧指针和堆栈指针在整个函数中都保持相同的值,这使得帧指针非常冗余。s8
此外,s0 和 s1 等值将存储在堆栈帧中的什么位置?
在属于被调用方的新分配(10 个字)堆栈空间中的某个位置。
我们还要注意,a0 和 a1 存储在调用方的堆栈空间中,该空间应该包括所有参数的存储空间,即使实际参数值是在寄存器中传递的。这个函数知道空间必须在那里,并在那里存储其参数,而不是为它们分配新的堆栈空间(这也没关系,尽管更浪费堆栈空间)。
评论
sp