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
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 (tofact) but whose value is needed in order to return to caller (ofbinomial).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 (
facttaking one parameter), even though the parameter is passed in a CPU register, a0.I count, then,
For a total of 10 words.
This function is using
s8as 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.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).