0x0*_*x00 13 c x86 assembly gcc
在着名的论文"Smashing the Stack for Fun and Profit"中,它的作者采用了C函数
void function(int a, int b, int c) {
char buffer1[5];
char buffer2[10];
}
Run Code Online (Sandbox Code Playgroud)
并生成相应的汇编代码输出
pushl %ebp
movl %esp,%ebp
subl $20,%esp
Run Code Online (Sandbox Code Playgroud)
作者解释说,由于计算机以字大小的倍数对存储器进行寻址,因此编译器在堆栈上保留了20个字节(缓冲区1为8个字节,缓冲区2为12个字节).
我试图重新创建这个例子并获得以下内容
pushl %ebp
movl %esp, %ebp
subl $16, %esp
Run Code Online (Sandbox Code Playgroud)
不同的结果!我尝试了缓冲区1和缓冲区2的各种大小组合,似乎现代的gcc不再将缓冲区大小填充到字大小的倍数.相反,它遵守-mpreferred-stack-boundary选项.
作为一个例子 - 使用纸张的算术规则,对于buffer1 [5]和buffer2 [13],我会在堆栈上保留8 + 16 = 24个字节.但实际上我有32个字节.
这篇论文很古老,自那以后发生了很多事情.我想知道,究竟是什么推动了这种行为的改变?这是向64位机器的转变吗?或者是其他东西?
编辑
代码使用gcc版本4.8.2(Ubuntu 4.8.2-19ubuntu1)在x86_64机器上编译,如下所示:
$ gcc -S -o example1.s example1.c -fno-stack-protector -m32
更改的是SSE,它需要16字节对齐,这在旧的gcc文档中涵盖-mpreferred-stack-boundary = num,其中说明(强调我的):
在Pentium和PentiumPro上,double和long double值应与8字节边界对齐(请参阅-malign-double)或遭受严重的运行时性能损失.在Pentium III上,流式SIMD扩展(SSE)数据类型__m128如果不是16字节对齐则会受到类似的惩罚.
这也是Smashing The Modern Stack For Fun和Profit的论文,它涵盖了另一个现代化的变化,打破了Smashing the Stack for Fun and Profit.