The book I’m reading says that this function has a local variable. It also says that having a local variable for this function is important because it’s recursive. Maybe I’m just blind or I don’t understand how local variables work in assembly, but I don’t see it.
.type factorial, @function
factorial:
push %rbp # Save old base pointer.
mov %rsp, %rbp # Copy stack pointer to base pointer.
mov 16(%rbp), %rax # Save the argument in %rax.
cmp $1, %rax # End of the factorial.
je end_factorial
dec %rax # Decrement %rax.
push %rax # Push onto stack for next call to factorial.
call factorial
mov 16(%rbp), %rbx # %rax has return value, so load arg into %rbx.
imul %rbx, %rax # Multiply that by result of last call to factorial.
end_factorial:
# Restore stack pointer and base pointer to where they were
# before function call.
mov %rbp, %rsp
pop %rbp
ret
Can registers be considered local variables? I though local variables were implemented with something like sub $8, %rsp.
Local variables are not defined through their implementation, but by their semantics.
A definition
A variable is local, if every invocation of the function gets its own independent value for that variable, that’s why you could say that the value of the variable is “local to the function”.
Since this behavior can be achieved by using registers, that’s a perfectly valid implementation.
Saving and restoring local variables
However, since certain registers are considered caller-saved, the values may have to be put on the stack before calling nested functions, otherwise the values would be lost. Upon returning to the original function from the nested call, the value can then be restored into the register from the stack.
As has already been mentioned, a accessing a register is much faster than accessing the stack. Thus, they are preferred to main memory whenever possible.
However, I do not know why it couldn’t just do
imul 16(%rbp), %raxwithout the additional move operation. After all, theimulinstruction allows the source operand to be in-memory.