區域性變數申請棧空間時的入棧順序

JinhaoPlus發表於2015-03-29

執行環境: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型之後申請,不管原始碼中的順序如何(這應該來源於編譯器在進行溢位保護時設下的規定)。

相關文章