Unix Linux程序在記憶體中的布局

2021-08-08 15:08:35 字數 1473 閱讀 7349

對於linux作業系統之上的程式而言,其執行的程序所使用的記憶體位址都是虛擬位址,是mmu經過對映後的位址,我們這裡所談及的記憶體也是虛擬記憶體,而不是物理記憶體。

我們將編寫好的程式經過gcc編譯得到乙個可執行的檔案,然後將其執行起來,通過檢視程序的命令得到程序id:

ps -aux

在得到程序id之後,我們通過pmap命令來檢視程序在記憶體中的布局:

pmap -d 程序號

下圖是筆者的乙個程式程式通過pmap得到的程序記憶體布局:

以so結尾的是庫檔案,a.out的有兩個,乙個具可讀可執行許可權,也就是**段,另乙個具有可讀可寫的許可權,也就是資料段,接下來的幾段我們可能看不明白,但沒關係,stack我們知道是棧。到此我們對程序在記憶體中的布局的分析還未成型,我們需要借助另外乙個工具:readelf,一款檢視elf檔案資訊的工具。

命令列下,執行readelf:

readelf -s a.out

得到下面一幅圖:

這一次的資訊量比上一次的大多了。看到了我們熟悉的.text,rodata,.data,.bss。下面是筆者抽象出來的程序在記憶體中的布局示意圖,其中忽略了一些資訊。

高位址在上,低位址在下。如果讀者分析過足夠多的程式,你會發現,linux使用者程序的開始位址是0x08048000。下面我們對其中的一些段作簡單的解釋。

棧,也叫堆疊(這個叫法說實話真不像乙個程式設計師叫出來的),向下生長。資料結構中,我們學習過棧,這裡的棧就是資料結構中學習的那種結構,lifo(後進先出)。c語言要想順利的執行必須要有棧,棧是存放臨時變數、函式呼叫現場等的記憶體空間。c語言中定義的普通區域性變數就在棧中分配記憶體。

堆是程式執行時能夠自由分配的一段記憶體空間,向上生長。正由於其非常自由,所以很多的程式安全問題發生於此。例如臭名昭著的「記憶體洩漏」,就會發生在這裡。當你不斷地向獲取記憶體,而不釋放,那麼堆就會越來越小,最後無法完成分配的工作時,程式也將發生異常。c語言中,我們使用malloc,calloc,realloc函式來申請對記憶體,請記住,有借一定要有還(free)。

資料段分為.bss段和.data段。未初始化的全域性變數和靜態區域性變數存放於bss段。bss段會被初始化為0,這也正是全域性變數和靜態區域性變數不初始化也會是0的原因。已經初始化的全域性變數和靜態區域性變數存放於data段,這個初始值從程式檔案中複製而來。

**段分為.rodata,.text和.init。const修飾的全域性變數和一些字面值常量存放於rodata段,這段記憶體是唯讀的。text段存放的是程式指令。init段則用來給使用者程式新增一些「初始化」的**,包括環境變數的準備,命令列引數的組織和傳遞等,並將這部分資料之餘棧底。

檢視Unix Linux程序記憶體分布

摘自 sudo gdb p 1 gdb info process 1 start addr end addr size offset objfile 0x400000 0x401000 0x1000 0x0 usr bin runit 0x401000 0x480000 0x7f000 0x1000...

linux 程序在記憶體中的布局

先從 linux平台下 虛擬記憶體管理說起,寫c程式時,我們經常會列印乙個指標位址,說這個指標指向某某記憶體位址.可這些位址是真實物理記憶體位址嗎?不是 這些只是虛擬記憶體位址.當乙個c程式調入記憶體開始執行後,在記憶體中就會產生乙個程序.而在多工作業系統中每個程序都擁有一片屬於自己的記憶體空間 記...

程序在記憶體中的執行情況

一,程序在記憶體中的總結 上圖並不代表記憶體分布位址次序 1,區,存放程式的二進位制 2,常量區,他的生命週期和會從初始化開始到程式結束。例如,char str hello world 字串就存放在常量區。如下程式可以正常輸出 char fun char p hello word return p ...