转自 https://segmentfault.com/a/1190000002630697
运行环境:ubuntu 14.04(32bit)
编译环境:gcc
Source Code:
{stack_test.c}
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buffer_one[8], buffer_two[8];
int value = 5;
strcpy(buffer_one, "one");
strcpy(buffer_two, "two");
printf("[BEFORE] buffer_two is at %p and contains \'%s\'\n", buffer_two, buffer_two);
printf("[BEFORE] buffer_one is at %p and contains \'%s\'\n", buffer_one, buffer_one);
printf("[BEFORE] value is at %p and is %d (0x%08x)\n\n", &value, value, value);
return 0;
}
- 第一组对比:在栈溢出保护机制下的编译和没有溢出保护机制下的编译的入栈顺序的对比:
局部变量在源代码中是:
char buffer_one[8], buffer_two[8];
int value = 5;
栈溢出保护机制下的编译:
$ gcc -g -o so stack_test.c
$ ./so
[BEFORE] buffer_two is at 0xbfa12fb4 and contains 'two'
[BEFORE] buffer_one is at 0xbfa12fac and contains 'one'
[BEFORE] value is at 0xbfa12fa8 and is 5 (0x00000005)
可以看出来为变量创建创建的栈顺序依次是:buffer_two,buffer_one,value;
没有溢出保护机制下的编译:
$ gcc -fno-stack-protector -g -o so stack_test.c
$ ./so
[BEFORE] buffer_two is at 0xbf9a1530 and contains 'two'
[BEFORE] buffer_one is at 0xbf9a1538 and contains 'one'
[BEFORE] value is at 0xbf9a152c and is 5 (0x00000005)
可以看出来为变量创建创建的栈顺序依次是:buffer_one,buffer_two,value;
- 第二组对比:调整局部变量的顺序,再次在栈溢出保护机制下的编译和没有溢出保护机制下的编译的入栈顺序的对比:
即源码中局部变量声明改为:
int value = 5;
char buffer_one[8], buffer_two[8];
栈溢出保护机制下的编译:
$ gcc -g -o so stack_test.c
$ ./so
[BEFORE] buffer_two is at 0xbfe0ac54 and contains 'two'
[BEFORE] buffer_one is at 0xbfe0ac4c and contains 'one'
[BEFORE] value is at 0xbfe0ac48 and is 5 (0x00000005)
可以看出来为变量创建创建的栈顺序依次是:buffer_two,buffer_one,value;
没有溢出保护机制下的编译:
$ gcc -fno-stack-protector -g -o so stack_test.c
$ ./so
[BEFORE] buffer_two is at 0xbf9998bc and contains 'two'
[BEFORE] buffer_one is at 0xbf9998c4 and contains 'one'
[BEFORE] value is at 0xbf9998cc and is 5 (0x00000005)
可以看出来为变量创建创建的栈顺序依次是:value,buffer_one,buffer_two;
- 第三组对比:调整局部变量中buffer_one,buffer_two的顺序,再次在栈溢出保护机制下的编译和没有溢出保护机制下的编译的入栈顺序的对比:
即源码中局部变量声明改为:
int value = 5;
char buffer_two[8], buffer_one[8];
栈溢出保护机制下的编译:
$ gcc -g -o so stack_test.c
$ ./so
[BEFORE] buffer_two is at 0xbff96dfc and contains 'two'
[BEFORE] buffer_one is at 0xbff96e04 and contains 'one'
[BEFORE] value is at 0xbff96df8 and is 5 (0x00000005)
可以看出来为变量创建创建的栈顺序依次是:buffer_one,buffer_two,value;
没有溢出保护机制下的编译:
$ gcc -fno-stack-protector -g -o so stack_test.c
$ ./so
[BEFORE] buffer_two is at 0xbfa55234 and contains 'two'
[BEFORE] buffer_one is at 0xbfa5522c and contains 'one'
[BEFORE] value is at 0xbfa5523c and is 5 (0x00000005)
可以看出来为变量创建创建的栈顺序依次是:value,buffer_two,buffer_one;
得出的结论:
在没有溢出保护机制下的编译时,我们可以发现,所有的局部变量入栈的顺序(准确来说是系统为局部变量申请内存中栈空间的顺序)是正向的,即哪个变量先申明哪个变量就先得到空间,
也就是说,编译器给变量空间的申请是直接按照变量申请顺序执行的。在有溢出保护机制下的编译时,情况有了顺序上的变化,对于每一种类型的变量来说,栈空间申请的顺序都与源代码中相反,即哪个变量在源代码中先出现则后申请空间;而对不同的变量来说,申请的顺序也不同,有例子可以看出,int型总是在char的buf型之后申请,不管源代码中的顺序如何(这应该来源于编译器在进行溢出保护时设下的规定)。