Christophe De Troyer
Christophe De Troyer

Reputation: 2922

Return address in assembly

Allright, given the program below. I can't seem to get my head around the return address.

This is how I currently see it:

  1. We push 4 as parameter onto the stack. Meaning that our %esp increases by 4.
  2. We call factorial
    1. Push caller basepointer onto stack, so %esp increases by 4 again
    2. Move the old stackpointer into the new basepointer (%ebp)
    3. Take out the parameter pushed on the stack by the caller 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

Answers (1)

Alexis Wilke
Alexis Wilke

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

Related Questions