??????? 這節我們討論linux是如何利用x86結構中的段機制的,更確切的說是如何繞過linux的段機制的。
??????? 我們決定從linux的可移植性開始討論。我們說linux是一個廣泛移植的操作移動,它支持x86,Alpha,arm等多種體系結構。但是很多的結構其實都是不支持段機制的,比如arm,Alpha等,但是他們都支持分頁機制。linux為了能移植到x86上,做了不少工作。
??????? 首先我們說,x86是肯定有段機制的,那么我們要在x86上運行程序,那不可避免要用到段機制。于是我們想到我們先前所想到的段描述符中有一個表示以字節為單位還是以頁為單位表示一個段長度的屬性位。我們當時說,當G=1時表示以頁(4KB)為單位,那么一個段最大長度能到4GB。根據這一點,我們把一個段的段基址固定設置為0,然后讓G=1,于是我們一個段的最大長度就是4GB了,吶,這個很顯然就能和我們4GB的線性地址空間一一映射了。通過這樣的處理,我們說現在x86的段機制已經形同虛設了,邏輯地址和線性地址可以混為一談了。
??????? 但是x86還規定說,必須為代碼段和數據段創建不同的段,所以linux為代碼段和數據段分別創建了一個基地址為0,段長度為4GB的段描述符。不僅如此,由于linux內核運行在特權級0,用戶程序運行在特權級3,x86規定說特權級為3的用戶程序是不能訪問特權級為0的內核代碼的,所以linux又分別為內核和用戶程序分別創建代碼段和數據段。
??????? 于是在arch/x86/include/asm/segment.h中這樣定義四個段(即在機器啟動過程中段寄存器中放的值):
#define __KERNEL_CS (GDT_ENTRY_KERNEL_CS*8) #define __KERNEL_DS (GDT_ENTRY_KERNEL_DS*8) #define __USER_DS (GDT_ENTRY_DEFAULT_USER_DS*8+3) #define __USER_CS (GDT_ENTRY_DEFAULT_USER_CS*8+3)
??????? 其中:
#define GDT_ENTRY_DEFAULT_USER_CS 14 #define GDT_ENTRY_DEFAULT_USER_DS 15 #define GDT_ENTRY_KERNEL_BASE (12) #define GDT_ENTRY_KERNEL_CS (GDT_ENTRY_KERNEL_BASE+0) #define GDT_ENTRY_KERNEL_DS (GDT_ENTRY_KERNEL_BASE+1)
?
??????? 于是上邊的定義的結果是下邊這樣:
#define __KERNEL_CS 0x00C0 /*內核代碼段,index=12,TI=0,RPL=0*/ #define __KERNEL_DS 0x00D0 /*內核代碼段,index=13,TI=0,RPL=0*/ #define __USER_DS 0x00E3 /*用戶代碼段,index=14,TI=0,RPL=3*/ #define __USER_CS 0x00F3 /*用戶代碼段,index=15,TI=0,RPL=3*/
?
??????? 于是我們可以用12,13,14,15四個索引來找到我們四個段所對應的段描述符,并且我們把內核代碼段的特權聲明為0,用戶代碼段的特權為3,TI為0表示我們總是訪問全局描述符表。
??????? 在我們對應的段描述符中我們把G設置為1,段上限規定為0xfffff,就巧妙的繞過了x86的段機制。
??????? 但在這里我不能忽略的一個問題就是,我們把四個段的上限全部設置為4G,那就完全破壞了段的保護,就是說,我們有可能隨隨便便就修改了我們的其他段的數據。所幸,我們現在還是個線性地址,所幸此時我們還沒把數據裝載進內存,因此,我們就有處理這個問題的辦法,這就是下面要講的分頁機制了。
?
???????
?
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
