装配中的返回地址

时间:2014-04-19 21:21:01

标签: assembly

好吧,鉴于以下计划。我似乎无法理解回程地址。

这就是我目前看到的:

  1. 我们将4作为参数推送到堆栈中。这意味着我们的%esp增加了4。
  2. 我们致电factorial
    1. 将调用者basepointer推送到堆栈,因此%esp再次增加4
    2. 将旧的stackpointer移动到新的basepointer(%ebp
    3. 取出调用者movl 8(%ebp), %eax
    4. 在堆栈中推送的参数
  3. 因此,当我们输入factorial时,%esp指向堆栈的顶部,即4

    我们将旧的basepointer推到堆栈上,所以现在%esp指向我们的旧basepointer。

    我们将stackpointer值复制到basepointer寄存器(%ebp)。

    这意味着当前%esp%ebp指向堆栈顶部,其中包含旧的%ebp值。

    这就是堆栈应该是这样的:

    ################
    # Parameter: 4 #
    #--------------#
    # Old %ebp     # <-- %esp, %ebp point here
    #--------------#
    

    因此,要获取参数值,我们可以使用basepointer访问来访问它。我们知道%ebp指向旧%ebp值,因此我们需要使用字大小减去它,为4。

    所以,我认为这会将价值转化为%eax

    movl 4(%ebp), %eax
    

    但是,示例中使用的偏移量是8.返回地址是否隐式添加到堆栈中?

    如果是这样,我不应该使用旧%ebp作为基础来解决它吗?

    .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
    

1 个答案:

答案 0 :(得分:1)

您的代码中似乎存在错误。递归调用推送,调用和永不弹出。在主调用中,你有一个4的子堆栈指针...虽然在你的情况下你想在eax中弹出它(你不想从该调用中修改它。)

###################################
# Recursive call
###################################
# Push parameter.
pushl %eax
call factorial
popl %eax    <-- this missing, right?
###################################

话虽这么说,500 - 内部服务器错误给了你正确的答案,呼叫推送程序将返回的IP地址。

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