【问题标题】:Stack contents during a function call在函数调用期间堆栈内容
【发布时间】:2014-01-31 13:15:16
【问题描述】:

我试图了解在函数调用期间堆栈上会出现什么。

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

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

【问题讨论】:

标签: assembly stack function-call


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    main的前三行

    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 并退出程序。

    【讨论】:

      猜你喜欢
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 1970-01-01
      • 1970-01-01
      • 2019-11-22
      • 2016-12-17
      • 1970-01-01
      相关资源
      最近更新 更多