在着名的论文"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