好吧,鉴于以下计划。我似乎无法理解回程地址。
这就是我目前看到的:
4
作为参数推送到堆栈中。这意味着我们的%esp
增加了4。factorial
%esp
再次增加4 %ebp
)movl 8(%ebp), %eax
因此,当我们输入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
答案 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