我正在从 Jonathan Bartlett 的《Programming from ground up》一书中学习 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
这意味着已保存%ebp
值(函数保存/恢复的调用者的值)由两者都指向%esp
和你的新%ebp
在那时候。
你刚刚跑了push %ebp
,这做到了esp -= 4
并存储%ebp
to (%esp)
。这可以节省呼叫者的%ebp
以便您稍后可以恢复它。
然后你跑了mov %esp, %ebp
建立%ebp
作为帧指针。所以%ebp = %esp
,并且它们都指向您最后推动的东西。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)