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