Reputation: 2922
Allright, given the program below. I can't seem to get my head around the return address.
This is how I currently see it:
4
as parameter onto the stack. Meaning that our %esp
increases by 4.factorial
%esp
increases by 4 again%ebp
)movl 8(%ebp), %eax
So, when we enter factorial
, %esp
is pointing to the top of the stack, which is 4
.
We push our old basepointer onto the stack, so now %esp
points to our old basepointer.
We copy the stackpointer value to the basepointer register (%ebp
).
This means that currently %esp
, %ebp
are pointing to the top of the stack, which holds the old %ebp
value.
This is what the stack should look like:
################
# Parameter: 4 #
#--------------#
# Old %ebp # <-- %esp, %ebp point here
#--------------#
So, to get the parameter value we could access it using basepointer accessing. We know %ebp
points to the old %ebp
value, so we need to decrement it with the word size, being 4.
So, I thought this would get the value into %eax
:
movl 4(%ebp), %eax
However, the offset used in the example is 8. Is the return address something that is implicitly added to the stack?
If so, shouldn't I address it using the old %ebp
as a base?
.section .data
.section .text
.globl _start
.globl factorial
_start:
# Push the parameter.
pushl $4
call factorial
# Decrease the stackpointer to scrub
# the parameter pushed before.
addl $4, %esp
# Move the result of the function
# that is stored in %eax to %ebx
# so we can return it.
movl %eax, %ebx
# Exit stuff.
movl $1, %eax
int $0x80
.type factorial, @function
factorial:
###################################
# Standard function stuff.
###################################
# Save caller basepointer.
pushl %ebp
# Set callee basepointer to stackpointer.
movl %esp, %ebp
###################################
# Fetch the first parameter and put
# it in register %eax.
movl 8(%ebp), %eax
# If parameter is 1 return 1
cmpl $1, %eax
je end_factorial
# Decrease our parameter.
decl %eax
###################################
# Recursive call
###################################
# Push parameter.
pushl %eax
call factorial
###################################
# We stored our own input on the stack
# (pushl %eax). So we take that back
# to multiply it with the result of the
# recursive call which is stored in %eax
movl 8(%ebp), %ebx
# Multiply the result with
# with our own parameter.
imull %ebx, %eax
end_factorial:
# Default function exit stuff
movl %ebp, %esp
popl %ebp
ret
Upvotes: 0
Views: 1142
Reputation: 20828
There seems to be a bug in your code. The recursive call pushes, calls, and never pops. In the main call, you have a sub of 4 of the stack pointer... although in your case you want to pop it back out in eax (which you don't want modified from that call.)
###################################
# Recursive call
###################################
# Push parameter.
pushl %eax
call factorial
popl %eax <-- this missing, right?
###################################
That being said, 500 - Internal Server Error gave you the right answer, the call pushes the IP address where the program will return.
Instructions Stack
push $4 00 0000:0004
call factorial 00 <IP after call>
04 0000:0004
push %ebp 00 old ebp
04 <IP after call>
08 0000:0004
Upvotes: 1