C++ 为什么缓冲区的结尾和保存的帧指针之间有8个字节?
我正在做一个课程作业的堆叠粉碎练习,我已经完成了作业,但有一个方面我不明白 以下是目标计划:C++ 为什么缓冲区的结尾和保存的帧指针之间有8个字节?,c++,c,linux,gcc,stack-overflow,C++,C,Linux,Gcc,Stack Overflow,我正在做一个课程作业的堆叠粉碎练习,我已经完成了作业,但有一个方面我不明白 以下是目标计划: #include <stdio.h> #include <stdlib.h> #include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int bar(char *arg, char *out)
{
strcpy(out, arg);
return 0;
}
void foo(char *argv[])
{
char buf[256];
bar(argv[1], buf);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target1: argc != 2\n");
exit(EXIT_FAILURE);
}
foo(argv);
return 0;
}
当我查看堆栈上这个程序的内存时,我看到buf
的地址是0xbfffc40
。此外,保存的帧指针存储在0xbfffd48
,返回地址存储在0xbfffd4c
这些特定地址并不相关,但我观察到,即使buf
只有长度256
,距离0xbffffd48-0xbffffc40=264
。从符号上讲,此计算是$fp-buf
为什么在buf
的结尾和堆栈上存储的帧指针之间有8个
额外字节?
下面是对函数foo
的一些反汇编。我已经检查过了,但我没有看到该记忆区域有任何明显的用途,除非它是隐式的(即某些指令的副作用)
0x080484ab:推送%ebp
0x080484ac:mov%esp,%ebp
0x080484ae:低于$0x118,%esp
0x080484b4:mov 0x8(%ebp),%eax
0x080484b7:添加$0x4,%eax
0x080484ba:mov(%eax),%eax
0x080484bc:lea-0x108(%ebp),%edx
0x080484c2:mov%edx,0x4(%esp)
0x080484c6:mov%eax,(%esp)
0x080484c9:调用0x8048C
0x080484ce:离开
0x080484cf:ret
Basile Starynkevitch因提及对齐而获奖
结果是,gcc4.7.2
默认将框架边界与4字边界对齐。在32位模拟硬件上,即16字节。由于保存的帧指针和保存的指令指针一起只占用8个字节,编译器在buf
结束后再放入8个字节,以将堆栈帧的顶部与16字节边界对齐
-mpreferred-stack-boundary=2
使用以下附加编译器标志,8个字节将消失,因为8个字节足以对齐到2字边界
-mpreferred-stack-boundary=2
因为帧通常与16字节对齐(或者可能是8字节,我忘记了细节)。@BasileStrynkevitch,地址0xbffffc40
已经与16字节对齐,256肯定是16的倍数。该区域用于存储寄存器吗?'buf'不包含地址。它有一个地址。@MantoshKumar,请注意编译器标志-fno stack protector
。
-mpreferred-stack-boundary=2