在函数调用期间堆栈内容

时间:2014-01-12 21:11:38

标签: assembly stack function-call

我正在尝试了解函数调用期间堆栈中将出现的内容。

据我所知,在调用另一个函数之前,调用者的参数(如果有的话),调用者的返回地址和基地址将被压入堆栈。

所以,我写了一个简单的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()的代码吗?谢谢!

2 个答案:

答案 0 :(得分:0)

在x86上(您可能将其标记为),ABI(应用程序二进制接口)要求在调用函数时将堆栈与某些边界(在本例中为16个字节)对齐。因此,当main()想要调用foo()时,首先必须对齐堆栈指针。

答案 1 :(得分:0)

主要的前三行

8048339:   55                      push   %ebp
804833a:   89 e5                   mov    %esp,%ebp
804833c:   83 ec 08                sub    $0x8,%esp

被称为function prologue。这组指令将基指针推送到堆栈,然后为基指针分配当前堆栈的值,从而创建新的堆栈帧。然后减少堆栈指针以为函数的局部变量保留空间(由于调用约定,您仍然没有这样做但仍然完成)。下一条指令

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上出现了几次(here,如Paul R所指出的,以及hereagain here)。这个例程似乎在堆栈上保留了额外的空间,但是以一种奇怪的无效方式执行此操作。本节可能取决于gcc版本和操作系统,似乎没有必要。

其余的指令调用foo并退出程序。