1

If I'm looking at the objdump of a C program and this is the Mips breakdown of my int binomial(int n, int k) function, if I allocate the 40 bytes, is that how large/the size of the stack frame or does it depend on the code and how many are used within(like would it be 16 bytes since I only use 4 spots). Also where would values like s0 and s1 be stored in the stack frame?

I have a quiz coming up and am trying to better understand the breakdown of MIPS functions, so any responses are appreciated as google has been more confusing then helpful.

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
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Zuja Plays
  • 11
  • 2
  • This function is one of many called by main. I'm wondering what the size of the stack frame is though for this function. – Zuja Plays Apr 25 '23 at 02:42
  • The adjustment to `sp` should serve as an indicator, where it looks like the stack grows in the "downward" direction in this case. Have you tried mapping out the layout of the stack here? – tadman Apr 25 '23 at 02:43

1 Answers1

2

A stack frame will contain

  • any memory-based local variables, such as arrays

  • call-preserved registers that must be saved/restored in order to be used.

    the values being saved belong to some caller further up the call stack

    they are saved & restored so that the callee can use those registers, and yet must restore them before returning.  Here those are s8, s1, s0.

  • call-clobbered registers that are needed after a function call

    Here that is ra, which is clobbered by a nested function call (to fact) but whose value is needed in order to return to caller (of binomial).

  • temporary variables that either need to survive a function call or the compiler just wants to map to memory

    here 16(s8) is a variable that appears to hold what will ultimately become the return value in v0.

  • alignment padding, to round up to 8 bytes, which keeps the stack frame nicely aligned for variables of type double, in case some callee stores one to memory.

  • random stuff hard to account for, such as if the compiler wants 16-bit alignment of the stack size, or, the compiler allocates some otherwise unused stack space (not a great idea, but also not illegal).

  • space for parameters of called functions.


Here the stack frame is 40 bytes aka 10 words, and it is used to store values from ra, s8, s1, s0, as well as one (perhaps temporary) memory variable, and space for the callee's argument (fact taking one parameter), even though the parameter is passed in a CPU register, a0.

I count, then,

  • 3 words of space for s variables' original values (to benefit callers)
  • 1 word of space for ra (to benefit self)
  • 1 word of space for return value memory variable (compiler's choice)
  • 4 words of shadow space for argument registers
  • 1 word of padding for 8-byte stack alignment

For a total of 10 words.


This function is using s8 as a frame pointer, which is popular in some educational settings, but is an unnecessary device for this function.  Let's note that the frame pointer and the stack pointer both hold the same value throughout the function making the frame pointer quite redundant.


Also where would values like s0 and s1 be stored in the stack frame?

Somewhere in the newly allocated (10 words of) stack space belonging to the callee.

Let's also note that a0 and a1 are being stored in the caller's stack space, which is supposed to include storage space for all the parameters, even when the actual parameter values are passed in registers.  This function knows that the space must be there, and is storing its parameters there instead of allocating new stack space for them (which would be ok as well, though more wasteful of stack space).

Erik Eidt
  • 23,049
  • 2
  • 29
  • 53
  • 1
    Related: [Why does GCC allocate more space than necessary on the stack, beyond what's needed for alignment?](https://stackoverflow.com/q/63009070) - It just does that sometimes, longstanding GCC missed-optimization bug. – Peter Cordes Apr 25 '23 at 05:32