section和segment
最近遇到一個問題,我想構建一個很大的kernelImage.elf文件來進行測試。我在測試代碼中加入了全局變量aaa[10000],并且也賦了初值,然而現實卻是,elf文件大小并沒有增加,該全局變量仍然在.bss段中。則可咋整呢?詢問燕姐,得知解決方法是把小節.bss放到大節的.text中去。我想燕姐說的小節即節信息section,大節即段信息segment,嘗試后,果然elf變大了十幾兆。這也讓我產生了思考,節信息section和段信息segment,到底應當如何定義和區分呢?
首先匯編器根據語法規則,會將匯編源碼中表示“節”的語法關鍵字section 或segment 在目標文件中編譯成“節”,此“節”便是我們要討論的section。經過匯編生成目標文件之后,由這些section 或segment 修飾的程序區域便成為了“節” section )。
但操作系統加載程序時并不關心節的數量和大小,操作系統只關心節的屬性,因為程序必然是要加載到內存中才能運行的,而內存的訪問會涉及到全局描述符表中段描述符的訪問權限等屬性,保護模式下對任何內存的訪問都要經過段描述符才行。比如程序代碼所在的段描述符權限屬性必須是只讀,數據所在的段描述符的權限屬性必然是可讀寫,程序中那些只讀的節(比如代碼區域)必然不能指向可讀寫的段描述符,同樣,程序中的數據也不能用只讀權限的段描述符去訪問。
操作系統在加載程序時,不需要對逐個節進行加載,只要給出相同權限的節的集合就行了,例如把所有只讀可執行的節(如代碼節.text 和初始化代碼節.init )歸并到一塊,所有可讀寫的節(如數據節.data 和未初始化節.bss )歸并到一塊,這樣操作系統就能為它們分配不同的段選擇子,從而指向不同段描述符,實現不同的訪問權限了。
為了程序能在操作系統上運行,操作系統和編譯器需要相互配合,此時匯編器只生成了目標文件,尚未鏈接,因此這個將“節”合井的工作是由鏈接器來完成的,鏈接器將目標文件中屬性相同的節合并成一個大的section 集合,此集合便稱為segment,也就是段,此段便是我們平時所說的可執行程序內存空間中的代碼段和數據段。
編譯器提供的關鍵字Section 只是為了讓程序員在邏輯上將程序劃分成幾個部分,因為它是偽指令,CPU 都不知道有這個東西,更不知道咱們交給它執行的代碼經過了這很多的“風風雨雨”。甚至,我懷疑as 即使提供了這個section ,它也不知道這個section 中的內容是什么,是代碼?數據? as不關心,也沒必要關心,因為這是它給程序員的福利,程序員自己知道在哪個section 中是什么就行啦。
一般section的應用場所是根據不同的屬性人為地將程序劃分幾部分,如數據放在一個section 中,指令放在另一個section 中,這樣程序員便將指令和數據分開了,使代碼結構清晰明了,更易于維護。程序如何劃分,這個沒有規定,完全是看程序員自己的風格喜好,甚至可以利用section 把程序切得零碎不堪,所以你懂了,as 根本沒必要知道你的section 中到底是啥。
關鍵字section 并沒有對程序中的地址產生任何影響,即在默認情況下,有沒有section 都一個樣, section 中數據的地址依然是相對于整個文件的順延,僅僅是在邏輯上讓開發人員梳理程序之用。
自定義的section 名,會在elf 的section header 中顯示出來。下面是幾個標準的section (節)名,不是segment (段〉名, segment 沒有名稱。
節名 說明
.data 用于存入數據,可讀可寫
.text 用于存入代碼,只讀可執行
.bss 全局未初始化區域
在匯編代碼中,若以標準節名定義section,如我們定義的.bss 便是標準節名。編譯器會按照以上說明中的要求使用section 內的數據。
不管定義了多少節名,最終要把屬性相同的section,或者編譯認為可以放到一塊的,合并到一個大的segment 中,也就是elf 中說的program header 中的項。
由此可見,某個節( section )屬于某個段( segment),段是由節組成的。另外多說一句,最終給加載器用的也是program header 中顯示的段,這才是進程的資源。
總結一下:
section 稱為節,是指在匯編源碼中經由關鍵字section 或segment 修飾、邏輯劃分的指令或數據區域,匯編器會將這兩個關鍵字修飾的區域在目標文件中編譯成節,也就是說“節”最初誕生于目標文件中。
segment 稱為段,是鏈接器根據目標文件中屬性相同的多個section 合并后的section 集合,這個集合稱為segment,也就是段,鏈接器把目標文件鏈接成可執行文件,因此段最終誕生于可執行文件中。我們平時所說的可執行程序內存空間中的代碼段和數據段就是指的segment 。