linux內核學習-內存-分析程序的內存地址分配

前言

學習過linux後,知道linux程序內存結構可以分成五個區塊。分別是“代碼段”,“數據段“,”BSS段”,堆(head)和棧(stack)。他們分別的功能是
代碼段: 存放程序編譯後的機器代碼,它是一塊只讀區。

數據段: 數據段用來存放可執行文件中已初始化全局變量,換句話說就是存放程序靜態分配[1]的變量和全局變量。

BSS段[2]: BSS段包含了程序中未初始化的全局變量,在內存中 bss段全部置零。

堆(heap): 堆是用於存放進程運行中被動態分配的內存段,它的大小並不固定,可動態擴張或縮減。當進程調用malloc等函數分配內存時,新分配的內存就被動態添加到堆上(堆被擴張);當利用free等函數釋放內存時,被釋放的內存從堆中被剔除(堆被縮減)

棧: 棧是用戶存放程序臨時創建的局部變量,也就是說我們函數括弧“{}”中定義的變量(但不包括static聲明的變量,static意味着在數據段中存放變量)。除此以外,在函數被調用時,其參數也會被壓入發起調用的進程棧中,並且待到調用結束後,函數的返回值也會被存放回棧中。由於棧的先進先出特點,所以棧特別方便用來保存/恢復調用現場。從這個意義上講,我們可以把堆棧看成一個寄存、交換臨時數據的內存區。
在這裏插入圖片描述
如下我們將使用程序的方法,更加感性的認識這些區塊。

程序代碼

代碼大體思路如下,注意,以下打印的地址,不一定就是這個區塊的首地址。
1.代碼段:就是main函數的內存地址
2.數據段:打印某個有初始化全局變量的地址
3.BSS段:打印某個未初始化的全局變量地址
4.堆:打印某個動態創建的變量的地址
5.棧:打印某局部變量的變量地址。

程序代碼如下:

#include<stdio.h>
#include<malloc.h>
#include<unistd.h>

int bss_var;
int data_var0=1;

int main(int argc,char **argv)
{
	printf("below are addresses of types of process's mem\n");
	printf("Text location:\n");
	printf("\tAddress of main(Code Segment):%p\n",main);
	printf("____________________________\n");

	printf("Data Location:\n");
	printf("\tAddress of data_var(Data Segment):%p\n",&data_var0);
	static int data_var1=4;
	printf("\tNew end of data_var(Data Segment):%p\n",&data_var1);
	printf("____________________________\n");
	
	printf("BSS Location:\n");
	printf("\tAddress of bss_var:%p\n",&bss_var);
	printf("____________________________\n");

	int stack_var0=2;
	printf("Stack Location:\n");
	printf("\tInitial end of stack:%p\n",&stack_var0);
	int stack_var1=3;
	printf("\tnew end of stack:%p\n",&stack_var1);
	printf("____________________________\n");

	char *b = sbrk((ptrdiff_t)0);
	printf("Heap Location:\n");
	printf("\tInitial end of heap:%p\n",b);
	brk(b+4);
	b=sbrk((ptrdiff_t)0);
	printf("\tNew end of heap:%p\n",b);

	return 0;
}

程序輸出結果如下
在這裏插入圖片描述
多次運行程序,我們發現代碼段,數據段,BSS段都的地址都是固定好的,但是堆和棧的地址是動態變化的。該怎麼解釋呢?
在這裏插入圖片描述

在linux中,用戶程序使用的是虛擬地址。也就是說,也就是說程序的運行之前,很多地址已經是確定好的。按照道理堆棧段都是固定的,但是因爲系統開啓了安全機制,程序在運行的時候,把堆棧的起始地址隨機分配了,這樣可以增加緩衝區溢出攻擊的難度。

原理
操作系統分配進程棧的起始地址:操作系統給進程棧分配的起始地址爲STACK_TOP,這個值一般也爲TASK_SIZE,即爲用戶空間的最大地址(在32位系統中,該值爲3G),但是如果系統設置PF_RANDOMIZE標誌,則操作系統會在進程啓動後,隨機設置棧的起始位置,即爲:STACK_TOP - randomized_variable,所以每次看到main函數局部變量地址是不一樣的

STACK_TOP的代碼如下

代碼:在內核2.6.32中,對應的方法:
static unsignedlong randomize_stack_top(unsigned long stack_top)
{
  unsignedint random_variable = 0;
  
  if((current->flags & PF_RANDOMIZE) &&
    !(current->personality & ADDR_NO_RANDOMIZE)) {
    random_variable = get_random_int() & STACK_RND_MASK;
    random_variable <<= PAGE_SHIFT;
  }
#ifdef CONFIG_STACK_GROWSUP
  returnPAGE_ALIGN(stack_top) + random_variable;
#else
  returnPAGE_ALIGN(stack_top) - random_variable;
#endif
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章