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

Ras*_*ash 8 assembly stack

我有一个功能:

void func(int a)
{
    int x = a+2;
}
Run Code Online (Sandbox Code Playgroud)

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

push %ebp
mov %esp, %ebp
sub $0x10, %esp
Run Code Online (Sandbox Code Playgroud)

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

我的猜测:它倾向于以16个字节存储.即如果我需要说20个字节,它将保留32个字节,无论如何.

Ano*_*ous 7

这在很大程度上取决于你的体系结构和编译器标志,所以不可能指向一个单一的东西并在这里说"这一定是它".但是,我可以给你一些你可能会发现有帮助的指示.

首先,考虑堆栈边界.您可能听说过GCC的-mpreferred-stack-boundary = X标志.如果没有,它基本上告诉编译器更喜欢堆栈上的值为2 ^ X字节.然后,您的编译器将尝试优化您的程序,以便这些值尽可能地适合堆栈.另一方面,GCC修饰符(如__packed__)将使编译器尽可能紧密地拟合堆栈中的数据.

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