为什么在缓冲区的末尾和保存的帧指针之间有8个字节?

我正在为作业做一个堆叠砸练习,而且我已经完成了作业,但是有一个方面我不明白。

这是目标程序:

#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; } 

以下是在运行Ubuntu 12.04x86虚拟机上禁用ASLR编译命令。

 gcc -ggdb -m32 -g -std=c99 -D_GNU_SOURCE -fno-stack-protector -m32 target1.c -o target1 execstack -s target1 

当我在堆栈中查看这个程序的内存时,我看到buf的地址为0xbffffc40 。 而且,保存的帧指针被存储在0xbffffd48 ,并且返回地址被存储在0xbffffd4c

这些具体的地址是不相关的,但我观察到,即使buf只有长度为256 ,距离0xbffffd48 - 0xbffffc40 = 264 。 象征性地,这个计算是$fp - buf

为什么在buf结尾和堆栈中存储的帧指针之间有8额外的字节?

这里是对foo函数的一些反汇编。 我已经检查过了,但是我没有看到这个内存区域的任何明显的用法,除非它是隐含的(即某些指令的副作用)。

  0x080484ab <+0>: push %ebp 0x080484ac <+1>: mov %esp,%ebp 0x080484ae <+3>: sub $0x118,%esp 0x080484b4 <+9>: mov 0x8(%ebp),%eax 0x080484b7 <+12>: add $0x4,%eax 0x080484ba <+15>: mov (%eax),%eax 0x080484bc <+17>: lea -0x108(%ebp),%edx 0x080484c2 <+23>: mov %edx,0x4(%esp) 0x080484c6 <+27>: mov %eax,(%esp) 0x080484c9 <+30>: call 0x804848c <bar> 0x080484ce <+35>: leave 0x080484cf <+36>: ret 

Solutions Collecting From Web of "为什么在缓冲区的末尾和保存的帧指针之间有8个字节?"

巴西尔Starynkevitch得到提到alignment奖。

事实证明, gcc 4.7.2默认将帧边界对齐到4个字的边界。 在32位模拟硬件上,即16个字节。 由于保存的帧指针和保存的指令指针一起只占用8个字节,所以编译器在buf结束之后再放置8个字节,以便将栈顶与16字节的边界对齐。

使用以下附加编译器标志,8个字节消失,因为8个字节足以对齐到2个字的边界。

 -mpreferred-stack-boundary=2