为啥我的编译器保留的空间比函数堆栈帧所需的空间多?

Posted

技术标签:

【中文标题】为啥我的编译器保留的空间比函数堆栈帧所需的空间多?【英文标题】:Why is my compiler reserving more space than required for a function stack frame?为什么我的编译器保留的空间比函数堆栈帧所需的空间多? 【发布时间】:2013-10-29 11:20:34 【问题描述】:

我有一个函数:

void func(int a)

    int x = a+2;

在汇编代码中,在函数prolog中:

push %ebp
mov %esp, %ebp
sub $0x10, %esp

代码只需要为 x 预留空间,即 4 个字节。但它保留了 16 个字节。这是为什么 ?我一直认为它会预留比所需更多的空间。

我的猜测:它倾向于以 16 个字节存储。也就是说,如果我需要说 20 个字节,无论如何它都会保留 32 个字节。

【问题讨论】:

看来我的猜测是错误的,因为在这个链接中,这个人只需要 16 字节空间,但保留了 32 字节。 ***.com/questions/13430540/… ***.com/questions/4175281/… 的可能重复项。 对不起,为了简单,我没有多加1行,原来的代码在“sub”行之前多了1行:和0xfffffff0, %esp所以在分配空间之前就完成了对齐. 您不仅需要对齐一次,还需要保持对齐。也就是说,一旦您确保它是对齐的,只需对其进行调整以使其保持对齐。因此额外的空间。 对 - 如果你对齐它,然后只添加四个字节,你只是再次将它抛出不对齐。 【参考方案1】:

这在很大程度上取决于您的体系结构和编译器标志,因此不可能在这里指向单一事物并说“这一定是它”。不过,我可以给你一些建议,你可能会觉得有帮助。

首先,考虑堆栈边界。您可能听说过 GCC 的 -mpreferred-stack-boundary=X 标志。如果不是,它基本上会告诉您的编译器希望您在堆栈上的值每个为 2^X 字节。然后,您的编译器将尝试优化您的程序,以使这些值尽可能适合堆栈。另一方面,像 __packed__ 这样的 GCC 修饰符会使编译器尽量将数据放入栈中。

还有堆栈保护器。基本上,GCC 会在堆栈上放置虚拟值,以确保缓冲区溢出除了对您的程序造成段错误之外不会造成任何伤害(这并不有趣,但比攻击者控制指令指针更好)。您可以轻松地尝试一下:使用任何最新版本的 GCC 并让用户溢出缓冲区。您会注意到程序退出时会显示一条消息,即“检测到堆栈粉碎,已终止”。尝试用-fno-stack-protector编译你的程序,堆栈上分配的本地内存可能会更小。

【讨论】:

注意:这个答案与我在此处给出的答案的前半部分相同:***.com/questions/19736213/… 我不会认为它是重复的,但您可能会发现它仍然有用。

以上是关于为啥我的编译器保留的空间比函数堆栈帧所需的空间多?的主要内容,如果未能解决你的问题,请参考以下文章

为啥编译器保留一点堆栈空间而不是整个数组大小?

为啥编译器保留一点堆栈空间而不是整个数组大小?

为啥每次递归都使用这么多的堆栈空间?

为啥要为局部变量保留堆栈空间?

函数所需的堆栈空间是否会影响C / C ++中的内联决策?

在进行 C 到 Intel x86 程序集转换时,堆栈上的数组分配占用的空间超过了所需的空间 [重复]