为什么有一个缓冲的结束和保存的帧指针之间的8个字节? [英] Why are there 8 bytes between the end of a buffer and the saved frame pointer?
问题描述
我做了一个课程堆栈溢出的锻炼,我已经完成了任务,但有一个方面,我不明白。
下面是目标程序:
的#include<&stdio.h中GT;
#包括LT&;&stdlib.h中GT;
#包括LT&;&string.h中GT;INT栏(字符*阿根廷,字符*出)
{
的strcpy(出,ARG);
返回0;
}无效美孚(字符* argv的[])
{
焦炭BUF [256];
酒吧(ARGV [1],BUF);
}INT主(INT ARGC,CHAR *的argv [])
{
如果(的argc!= 2)
{
fprintf中(标准错误,目标1:ARGC = 2 \\ n);
出口(EXIT_FAILURE);
}
富(ARGV);
返回0;
}
下面是用于编译的命令,运行的Ubuntu 12.04的
与 86
虚拟机 ASLR
禁用。
gcc的-ggdb -m32 -g -std = C99 -D_GNU_SOURCE -fno-堆栈保护-m32 target1.c -o目标1
execstack -s目标1
当我看着堆在这个程序的内存,我看到 BUF
的地址为 0xbffffc40
。此外,保存的帧指针存储在 0xbffffd48
,返回地址存储在 0xbffffd4c
。
这些具体的地址是不相关的,但我观察到,即使 BUF
只有长度 256
的距离 0xbffffd48 - 0xbffffc40 = 264
。象征性的,这种计算是 $ FP - BUF
为什么有 8
BUF
的结束和对存储的帧指针之间额外字节栈?
下面是函数的一些拆卸富
。我已经分析过了,但我没有看到,内存区域的任何明显的使用,除非它是隐式的(即某些指令的副作用)。
0x080484ab 1 + 0计算值:推%EBP
0x080484ac 1 + 1&GT ;: MOV%ESP,EBP%
0x080484ae 1 + 3计算值:子$量0x118,%尤
0x080484b4 1 + 9计算值:MOV位于0x8(%EBP),%eax中
0x080484b7 1 + 12计算值:加$为0x4,%eax中
0x080484ba 1 + 15计算值:MOV(%EAX),EAX%
0x080484bc 1 + 17计算值:LEA -0x108(%EBP),%EDX
0x080484c2 1 + 23计算值:MOV%EDX,为0x4(%尤)
0x080484c6 1 + 27计算值:MOV EAX%(%ESP)
0x080484c9 1 + 30计算值:调用0x804848c< BAR>
0x080484ce 1 + 35计算值:离开
0x080484cf 1 + 36计算值:保留
巴西莱Starynkevitch得到了提对齐奖
。
原来, GCC 4.7.2
默认帧边界对齐到4字的边界。在32位的仿真硬件,即16字节。由于保存的帧指针和保存的指令指针一起只占用8个字节,编译器放在另外8个字节 BUF
结束后对准栈帧的顶部一个16字节边界。
使用下列额外的编译标志,8个字节消失,由于8个字节是足以对准的2字边界
-m preferred堆栈边界= 2
I am doing a stack-smashing exercise for coursework, and I have already completed the assignment, but there is one aspect that I do not understand.
Here is the target program:
#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;
}
Here are the commands used to compile it, on an x86
virtual machine running Ubuntu 12.04
, with ASLR
disabled.
gcc -ggdb -m32 -g -std=c99 -D_GNU_SOURCE -fno-stack-protector -m32 target1.c -o target1
execstack -s target1
When I look at the memory of this program on the stack, I see that buf
has the address 0xbffffc40
. Moreover, the saved frame pointer is stored at 0xbffffd48
, and the return address is stored at 0xbffffd4c
.
These specific addresses are not relevant, but I observe that even though buf
only has length 256
, the distance 0xbffffd48 - 0xbffffc40 = 264
. Symbolically, this computation is $fp - buf
.
Why are there 8
extra bytes between the end of buf
and the stored frame pointer on the stack?
Here is some disassembly of the function foo
. I have already examined it, but I did not see any obvious usage of that memory region, unless it was implicit (ie a side effect of some instruction).
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
Basile Starynkevitch gets the prize for mentioning alignment
.
It turns out that gcc 4.7.2
defaults to aligning the frame boundary to a 4-word boundary. On 32-bit emulated hardware, that is 16 bytes. Since the saved frame pointer and the saved instruction pointer together only take up 8 bytes, the compiler put in another 8 bytes after the end of buf
to align the top of the stack frame to a 16 byte boundary.
Using the following additional compiler flag, the 8 bytes disappears, because the 8 bytes is enough to align to a 2-word boundary.
-mpreferred-stack-boundary=2
这篇关于为什么有一个缓冲的结束和保存的帧指针之间的8个字节?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!