函数调用如何在x86 32中工作?

我正在从Jonathan Bartlett的“从头开始编程”一书中学习GNU程序集。

在讨论函数调用和堆栈的主题时,我无法理解它的工作原理。

以下是书中的内容:

在执行一个函数之前,一个程序按照它们记录的相反顺序将函数的所有参数压入堆栈。 然后程序发出一个呼叫指令,指示它希望启动哪个功能。 调用指令有两件事。 首先将下一条指令(返回地址)的地址推入堆栈。 然后它修改指令指针(%eip)以指向函数的开始。 所以,在函数启动的时候,堆栈看起来像这样(堆栈的“顶部”在这个例子的底部):

Parameter #N
...
Parameter 2
Parameter 1
Return Address <--- (%esp)

函数的每个参数都被压入堆栈,最后返回地址就在那里。 现在函数本身有一些工作要做。

它所做的第一件事是通过执行pushl%ebp来保存当前的基址指针寄存器%ebp。 基指针是用于访问函数参数和局部变量的特殊寄存器。 接下来,它通过执行movl%esp,%ebp将堆栈指针复制到%ebp。 这允许您可以从基指针访问函数参数作为固定索引。 你可能会认为你可以使用这个堆栈指针。 然而,在你的程序中,你可能会对堆栈做其他事情,比如将参数传递给其他函数。 将堆栈指针复制到函数开头的基址指针中,可以让您始终知道参数的位置(以及我们将看到的局部变量),即使您可能正在将堆栈中的东西打开或关闭。 %ebp将始终是堆栈指针位于函数开头的位置,因此它或多或少是对堆栈帧的常量引用(堆栈帧由函数中使用的所有堆栈变量组成,包括参数,本地变量和返回地址)。

在这一点上,堆栈看起来像这样:

Parameter #N <--- N*4+4(%ebp)
...
Parameter 2 <--- 12(%ebp)
Parameter 1 <--- 8(%ebp)
Return Address <--- 4(%ebp)
Old %ebp <--- (%esp) and (%ebp)

如您所见,可以使用%ebp寄存器使用基址指针寻址模式访问每个参数。

我可以在第二段后简要介绍作者想要告诉的内容。 我明显在%esp,%ebp寄存器和%ebp在这里工作之间混淆。 任何帮助,高度赞赏。


在第二个图中,有“旧的%ebp <---(%esp)和(%ebp)”。 这是什么意思 ?

这意味着保存的%ebp值(函数保存/恢复的调用者的值)由%esp和此时的新%ebp指向。

您只需运行push %ebp ,即esp -= 4并将%ebp存储到(%esp) 。 这样可以节省调用者的%ebp以便以后恢复。

然后,你跑mov %esp, %ebp成立%ebp作为帧指针。 所以%ebp = %esp ,他们都指着你推的最后一件事。

链接地址: http://www.djcxy.com/p/80389.html

上一篇: How do function calls work in x86 32

下一篇: Behaviour of EBP and ESP in stack during 2 function calls