Simple assembly program



I am trying to understand this basic Assembly program that is based on the
following C code (the recursive factorial function):

int fact (int n)
{
if (n < 1) return 1;
else return (n * fact(n-1));
}

convertered to assembly:

1 fact:
2 addi $sp, $sp, -8 # adjust stack for 2 items
3 sw $ra, 4($sp) # save return address
4 sw $a0, 0($sp) # save argument n
5
6 slti $t0, $a0, 1 # test for n < 1
7 beq $t0, $zero, L1 # if n >= 1 goto L1
8
9 addi $v0, $zero, 1 # return 1
10 addi $sp, $sp, 8 # pop 2 items off stack
11 jr $ra # return to where?? (book says after jal)
12
13 L1:
14 addi $a0, $a0, -1 # decrement n with 1.
15 jal fact # call fact with updated n
16
17 lw $a0, 0($sp) # return from jal, restore argument n
18 lw $ra, 4($sp) # restore return address
19 addi $sp, $sp, 8 # pop 2 items on stack
20
21 mul $v0, $a0, $v0 # return n*fact (n-1)
21 jr $ra # return to caller.


1) In line 3 the return address that is save is the one that is needed to
return to the procedure that called fact in the first place, correct?

2) each time fact is called in line 15 the stack is adjusted for 2 items,
return address is saved etc. That means that if I call fact with n = 4 the
stack pointer will in the end point to 4*-8 = -32!?

3) The book says that the jr instruction in line 11 jumps to the instruction
after jal (line 17). But what if the first time fact is called the jump to
L1 is not taken ($a0 contains 0), would it not jump to the procedure that
called fact in the first place, since $ra has not been changed by a JAL
call.

4) When it gets to line 17 after various calls to fact i can't see how $v0
in line 21 can contain anything else that 0 since $a0 is 0 and $v0 is 1...
.