在函数调用期间堆叠内容
我试图理解函数调用期间堆栈中将出现什么。
据我所知,在调用另一个函数之前,被调用者的参数(如果有的话),调用者的返回地址和基地址将被压入堆栈。
所以,我写了一个简单的C程序
#include <stdio.h>
void
foo()
{
}
int
main()
{
foo();
return 0;
}
并且相应的分解机器码是
08048334 <foo>:
8048334: 55 push %ebp
8048335: 89 e5 mov %esp,%ebp
8048337: c9 leave
8048338: c3 ret
08048339 <main>:
8048339: 55 push %ebp
804833a: 89 e5 mov %esp,%ebp
804833c: 83 ec 08 sub $0x8,%esp
804833f: 83 e4 f0 and $0xfffffff0,%esp
8048342: b8 00 00 00 00 mov $0x0,%eax
8048347: 83 c0 0f add $0xf,%eax
804834a: 83 c0 0f add $0xf,%eax
804834d: c1 e8 04 shr $0x4,%eax
8048350: c1 e0 04 shl $0x4,%eax
8048353: 29 c4 sub %eax,%esp
8048355: e8 da ff ff ff call 8048334 <foo>
804835a: b8 00 00 00 00 mov $0x0,%eax
804835f: c9 leave
8048360: c3 ret
8048361: 90 nop
8048362: 90 nop
8048363: 90 nop
虽然foo()的代码有意义,但我无法理解main的()代码。 为什么有这么多的操作? 我只在main()中期待以下操作
1. Push the frame pointer
2. Call foo (which will inturn save the return address)
有人可以解释我的main()的代码吗? 谢谢!
在x86上(您可能已将其标记为),ABI(应用程序二进制接口)要求在调用函数时将堆栈对齐到某个边界(本例中为16个字节)。 所以当main()
想要调用foo()
,它首先必须调整堆栈指针。
主要的前三行
8048339: 55 push %ebp
804833a: 89 e5 mov %esp,%ebp
804833c: 83 ec 08 sub $0x8,%esp
被称为函数序言。 这组指令将基指针压入堆栈,然后为基指针分配当前堆栈的值,从而创建一个新的堆栈帧。 然后减少堆栈指针以为函数的局部变量保留空间(您没有,但由于调用约定仍然完成)。 下一条指令
804833f: 83 e4 f0 and $0xfffffff0,%esp
将堆栈与下一个较低的16字节边界对齐。 以下说明
8048342: b8 00 00 00 00 mov $0x0,%eax
8048347: 83 c0 0f add $0xf,%eax
804834a: 83 c0 0f add $0xf,%eax
804834d: c1 e8 04 shr $0x4,%eax
8048350: c1 e0 04 shl $0x4,%eax
8048353: 29 c4 sub %eax,%esp
已经在SE上出现了几次(这里,正如Paul R所指出的,在这里,以及在这里)。 这个例程似乎在堆栈上预留了额外的空间,但是却以一种奇怪无效的方式进行。 这部分可能取决于gcc版本和操作系统,似乎没有必要。
其余指令调用foo并退出程序。
链接地址: http://www.djcxy.com/p/80373.html上一篇: Stack contents during a function call
下一篇: based virtual machine function call/return implementation issues