【问题标题】:Why did this source code allocate 16 bytes?为什么这个源代码分配了 16 个字节?
【发布时间】:2011-11-29 03:12:23
【问题描述】:
(gdb) disas /m main
Dump of assembler code for function main():
2   {
   0x080483f4 <+0>: push   %ebp
   0x080483f5 <+1>: mov    %esp,%ebp
   0x080483f7 <+3>: sub    $0x10,%esp

3       int a = 1;
   0x080483fa <+6>: movl   $0x1,-0x4(%ebp)

4           int b = 10;
   0x08048401 <+13>:    movl   $0xa,-0x8(%ebp)

5           int c;
6           c = a + b;
   0x08048408 <+20>:    mov    -0x8(%ebp),%eax
   0x0804840b <+23>:    mov    -0x4(%ebp),%edx
   0x0804840e <+26>:    lea    (%edx,%eax,1),%eax
   0x08048411 <+29>:    mov    %eax,-0xc(%ebp)

7           return 0;
   0x08048414 <+32>:    mov    $0x0,%eax

8   }
   0x08048419 <+37>:    leave  

注意第三条汇编指令,它分配了 16 个字节而不是预期的 12 个字节。这是为什么?我以为第三行是分配自动变量...

即使我删除了分配,分配仍然是 16 字节。

谢谢。


编辑

// no header. nothing
int main()
{
        int a = 1;
        int b = 10;
        int c;
        c = a + b;
        return 0;
}

g++ -g -o demo demo.cpp


跟进... 我又读了几篇关于堆栈对齐的文章(对不起,我现在正在学习计算机架构和组织类……所以我对此一点都不熟悉)

Stack Allocation Padding and Alignment

我想这是编译器的设置。因此默认情况下,最小值为 16 字节。

如果我们有

int a = 1;
int b = 10;
int c = 10;
int d = 10;
// --
int e = 10;

直到 int d,我们正好有 16 字节,分配仍然是 0x10。但是当我们再给出一个 delectation 时,int e = 10,esp 现在被分配了 32 个字节(0x20)。

这告诉我,堆栈指针 esp 仅用于自动变量。


跟进 2

调用栈和栈帧

每个栈帧

Storage space for all the automatic variables for the newly called function.

The line number of the calling function to return to when the called function returns.

The arguments, or parameters, of the called function.

但是在我们分配 int a 到 int d 之后,它已经占用了我们 16 个字节。 Main 没有函数参数,因此为零。但是线路返回,这些信息哪里去了?

【问题讨论】:

  • 可以看看main()的源代码吗?
  • @Mysticial 是的。我刚刚编辑。谢谢。
  • 要获得第二次编辑的答案,请查看此链接:(en.wikibooks.org/wiki/X86_Disassembly/…) 它准确显示了它的工作原理以及返回地址和其他所有内容的位置。

标签: c++ gdb


【解决方案1】:

虽然我还没有看到main() 的源代码,我相信这是由于堆栈对齐。

根据您的设置,堆栈可能需要对齐到 8 个字节。因此esp 增加了 16 个字节而不是 12 个字节。 (尽管 12 个字节足以容纳所有变量)

在其他系统(使用 SSE 或 AVX)上,堆栈需要对齐到 16 或 32 字节。

【讨论】:

  • +1:如果 main 调用了多个函数,每个函数都期望堆栈对齐。不是每次调整堆栈一点点,变量 12 个字节,然后在函数调用之前再增加 4 个字节,而是预先调整 16 个字节。
  • @Mysticial。谢谢。我刚刚写了后续。你说的对。我相信这是一个编译器设置。
  • 根据您的编辑,看起来堆栈对齐是 16 个字节而不是 8 个字节。 :)
  • @Zan Lynx。嗯,这很有趣。因为在后续中,int a ---> int d 并没有发生“4 个字节”。它仍然分配了最多 16 个字节。我知道在每个函数调用的入口处,我们都有一个堆栈帧,用于存储参数、我们返回的地址、自动变量......
  • @Mysticial 我刚刚完成了这项任务。非常感谢。
【解决方案2】:

没什么特别的 - 前四个字节分配给返回码 :)

【讨论】:

  • 我不这么认为。看我的跟进...我知道返回(返回哪一行)是存储在堆栈帧中的信息之一。
  • 不太可能 - 回报似乎放在 eax 中。
  • @SteveFallows 谢谢。我发布了后续 2。我了解每个堆栈帧存储的内容。但是当我们声明 int a 到 d 时,已经是 16 个字节了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-04-20
  • 1970-01-01
  • 1970-01-01
  • 2018-11-12
  • 1970-01-01
  • 2017-09-04
  • 2018-08-21
相关资源
最近更新 更多