栈帧大小

问题描述 投票:0回答:1

如果我正在查看 C 程序的 objdump,这是我的 int binomial(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
c assembly mips
1个回答
0
投票

栈帧将包含

  • 任何基于内存的局部变量,例如数组

  • 必须保存/恢复才能使用的呼叫保留寄存器。

    保存的值属于调用堆栈更上层的某个调用者

    它们被保存和恢复,以便被调用者可以使用这些寄存器,但必须在返回之前恢复它们。这些是

    s8
    ,
    s1
    ,
    s0
    .

  • 函数调用后需要调用破坏的寄存器

    这里是

    ra
    ,它被嵌套函数调用(对
    fact
    )破坏,但需要其值才能返回调用者(
    binomial
    )。

  • 需要在函数调用中存活或编译器只想映射到内存的临时变量

    这里的 16(s8) 是一个变量,它似乎保存了最终将成为 v0 中的返回值的内容。

  • 对齐填充,最多四舍五入到 8 个字节,这使堆栈帧很好地对齐双精度类型的变量,以防某些被调用者将一个存储到内存中。

  • 难以解释的随机因素,例如编译器是否需要堆栈大小的 16 位对齐,或者编译器分配了一些未使用的堆栈空间(这不是一个好主意,但也不违法)。

  • 被调用函数的参数空间。


这里的堆栈帧是 40 个字节,也就是 10 个字,它用于存储 ra、s8、s1、s0 的值,以及一个(可能是临时的)内存变量,以及被调用者参数的空间(

fact
一个参数),即使该参数是在 CPU 寄存器中传递的,a0.

我数,那么,

  • s变量原值3个字的空格(方便调用者)
  • 1个词的空间为ra(有益于自己)
  • 返回值内存变量的 1 个字空间(编译器的选择)
  • 参数寄存器的阴影空间的 4 个字
  • 1 个填充字用于 8 字节堆栈对齐

总共10个字。


此功能使用

s8
作为框架指针,这在一些教育设置中很流行,但对于此功能来说是一个不必要的设备。请注意,帧指针和堆栈指针在整个函数中都保持相同的值,这使得帧指针非常冗余。


此外,像 s0 和 s1 这样的值将存储在堆栈帧中的什么位置?

属于被调用者的新分配的(10 个字的)堆栈空间中的某处。

还要注意 a0 和 a1 存储在调用者的堆栈空间中,该空间应该包括所有参数的存储空间,即使实际参数值在寄存器中传递也是如此。这个函数知道空间必须在那里,并且将它的参数存储在那里而不是为它们分配新的堆栈空间(这也可以,尽管更浪费堆栈空间)。

© www.soinside.com 2019 - 2024. All rights reserved.