歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C++程序的內存布局

對任何一個普通C++程序來講,它都會涉及到5種不同的數據段。常用的幾個數據段種包含有“程序代碼段”、“程序數據段”、“程序堆棧段”等。不錯,這幾種數據段都在其中,但除了以上幾種數據段之外,進程還另外包含兩種數據段。下面我們來簡單歸納一下進程對應的內存空間中所包含的5種不同的數據區。

代碼段:代碼段是用來存放可執行文件的操作指令,也就是說是它是可執行程序在內存種的鏡像。代碼段需要防止在運行時被非法修改,所以只准許讀取操作,而不允許寫入(修改)操作——它是不可寫的。

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

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

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

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

我們要知道,棧中存放的是一個個被調函數所對應的堆棧幀,當函數fun1被調用,則fun1的堆棧幀入棧,fun1返回時,fun1的堆棧幀出棧。什麼是堆棧幀呢,堆棧幀其實就是保存被調函數返回時下一條執行指令的指針、主調函數的堆棧幀的指針、主調函數傳遞給被調函數的實參(如果有的話)、被調函數的局部變量等信息的一個結構。

首先,我們要說明的是如何區分每個堆棧幀,或者說,如何知道我現在在使用哪個堆棧幀。和棧密切相關的有2個寄存器,一個是ebp,一個是esp,前者可以叫作棧基址指針,後者可以叫棧頂指針。對於一個堆棧幀來說,ebp也叫堆棧幀指針,它永遠指向這個堆棧幀的某個固定位置(見上圖),所以可以根據ebp來表示一個堆棧幀,可以通過對ebp的偏移加減,來在堆棧幀中來來回回的訪問。esp則是隨著push和pop而不斷移動。因此根據esp來對堆棧幀進行操作。

再來講一下上圖,一個堆棧幀的最頂部,是實參,然後是return address,這個值是由主調函數中的call命令在call調用時自動壓入的,不需要我們關心,previousframe pointer,就是主調函數的堆棧幀指針,也就是主調函數的ebp值。ebp偏移為正的都是被調函數的局部變量。

Copyright © Linux教程網 All Rights Reserved