x86中記憶體段和段描述符

2021-04-30 11:28:09 字數 3976 閱讀 1523

一、段

保護模式中80x86 提供了4gb的實體地址空間。這是處理器在其位址匯流排上可以定址的位址空間。這個位址空間是平坦的,位址範圍從0到0xffffffff。這個實體地址空間可以對映到讀寫記憶體、唯讀記憶體以及記憶體對映i/o中。分段機制就是把虛擬位址空間中的虛擬記憶體組織成一些長度可變的稱為段的記憶體塊單元。80386虛擬位址空間中的虛擬位址(邏輯位址)由乙個段部分和乙個偏移部分構成。段是虛擬位址到線性位址轉換機制的基礎。每個段由以下幾個引數定義:

(3)段屬性(attributes):指定段的特性。例如該段是否可讀、可寫或可作為乙個程式執行;段的特權級等。

段限長定義了在虛擬位址空間中段的大小。段基址和段限長定義了段所對映的線性位址範圍或區域。段內0到limit的位址範圍對應線性位址中範圍base到base+limit。偏移量大於段限長的虛擬位址是無意義的,如果使用則會導致異常。另外,若訪問乙個段並沒有得到段屬性許可則也會導致異常。例如,如果你試圖寫乙個唯讀的段,那麼80386就會產生乙個異常。另外,多個段對映到線性位址中的範圍可以部分重疊或覆蓋,甚至完全重疊,如圖4-6所示。在本書介紹的linux 0.1x系統中,乙個任務的**段和資料段的段限長相同,並被對映到線性位址完全相同而重疊的區域上。

圖4-6  虛擬(邏輯)位址空間中的段對映到線性位址空間

段的基位址、段限長以及段的保護屬性儲存在乙個稱為段描述符(segment descriptor)的結構項中。在邏輯位址到線性位址的轉換對映過程中會使用這個段描述符。段描述符儲存在記憶體中的段描述符表(descriptor table)中。段描述符表是包含段描述符項的乙個簡單陣列。前面介紹的段選擇符即用於通過指定表中乙個段描述符的位置來指定相應的段。

即使利用段的最小功能,使用邏輯位址也能訪問處理器位址空間中的每個位元組。邏輯位址由16位的段選擇符和32位的偏移量組成,如圖4-7所示。段選擇符指定位元組所在的段,而偏移量指定該位元組在段中相對於段基位址的位置。處理器會把每個邏輯位址轉換成線性位址。線性位址是處理器線性位址空間中的32位位址。與實體地址空間類似,線性位址空間也是平坦的4gb位址空間,位址範圍從0到0xffffffff。線性位址空間中含有為系統定義的所有段和系統表。

圖4-7  邏輯位址到線性位址的變換過程

(1)使用段選擇符中的偏移值(段索引)在gdt或ldt表中定位相應的段描述符(僅當乙個新的段選擇符載入到段暫存器中時才需要這一步)。

(2)利用段描述符檢驗段的訪問許可權和範圍,以確保該段是可訪問的並且偏移量位於段界限內。

(3)把段描述符中取得的段基位址加到偏移量上,最後形成乙個線性位址。

如果沒有開啟分頁,那麼處理器直接把線性位址對映到實體地址,即線性位址被送到處理器位址匯流排上。如果對線性位址空間進行了分頁處理,那麼就會使用二級位址轉換把線性位址轉換成實體地址。頁轉換將在稍後進行說明。

二、段描述符

段描述符表是段描述符的乙個陣列,如圖4-8所示。描述符表的長度可變,最多可以包含8192個8位元組描述符。有兩種描述符表:全域性描述符表gdt(global descriptor table)和區域性描述符表ldt(local descriptor table)。

圖4-8  段描述符表結構

描述符表儲存在由作業系統維護著的特殊資料結構中,並且由處理器的記憶體管理硬體來引用。這些特殊結構應該儲存在僅由作業系統軟體訪問的受保護的記憶體區域中,以防止應用程式修改其中的位址轉換資訊。虛擬位址空間被分割成大小相等的兩半。一半由gdt來對映變換到線性位址,另一半則由ldt來對映。整個虛擬位址空間共含有214個段:一半空間(即213個段)是由gdt對映的全域性虛擬位址空間,另一半是由ldt對映的區域性虛擬位址空間。通過指定乙個描述符表(gdt或ldt)以及表中描述符號,我們就可以定位乙個描述符。

當發生任務切換時,ldt會更換成新任務的ldt,但是gdt並不會改變。因此,gdt所對映的一半虛擬位址空間是系統中所有任務共有的,但是ldt所對映的另一半則在任務切換時被改變。系統中所有任務共享的段由gdt來對映。這樣的段通常包括含有作業系統的段以及所有任務各自的包含ldt的特殊段。ldt段可以想象成屬於作業系統的資料。

圖4-9表明乙個任務中的段如何能在gdt和ldt之間分開。圖中共有6個段,分別用於兩個應用程式(a和b)以及作業系統。系統中每個應用程式對應乙個任務,並且每個任務有自己的ldt。應用程式a在任務a中執行,擁有ldta,用來對映段codea和dataa。類似地,應用程式b在任務b中執行,使用ldtb來對映codeb和datab段。包含作業系統核心的兩個段codeos和dataos使用gdt來對映,這樣它們可以被兩個任務所共享。兩個ldt段:ldta和ldtb也使用gdt來對映。

圖4-9  任務所用的段型別

當任務a在執行時,可訪問的段包括ldta對映的codea和dataa段,加上gdt對映的作業系統的段codeos和dataos。當任務b在執行時,可訪問的段包括ldtb對映的codeb和datab段,加上gdt對映的段。

這個例子通過讓每個任務使用不同的ldt,演示了虛擬位址空間如何能夠被組織成隔離每個任務。當任務a在執行時,任務b的段不是虛擬位址空間的部分,因此任務a沒有辦法訪問任務b的記憶體。同樣地,當任務b執行時,任務a的段也不能被定址。這種使用ldt來隔離每個應用程式任務的方法,正是關鍵保護需求之一。

每個系統必須定義乙個gdt,並可用於系統中所有程式或任務。另外,可選定義乙個或多個ldt。例如,可以為每個執行任務定義乙個ldt,或者某些或所有任務共享乙個ldt。

gdt本身並不是乙個段,而是線性位址空間中的乙個資料結構。gdt的基線性位址和長度值必須載入進gdtr暫存器中。gdt的基位址應該進行記憶體8位元組對齊,以得到最佳處理器效能。gdt的限長以位元組為單位。與段類似,限長值加上基位址可得到最後表中最後1位元組的有效位址。限長為0表示有1個有效位元組。因為段描述符總是8位元組長,因此gdt的限長值應該設定成總是8的倍數減1(即8n-1)。

處理器並不使用gdt中的第1個描述符。把這個"空描述符"的段選擇符載入進乙個資料段暫存器(ds、es、fs或gs)並不會產生乙個異常,但是若使用這些載入了空描述符的段選擇符訪問記憶體時就肯定會產生一般保護性異常。通過使用這個段選擇符初始化段暫存器,那麼意外引用未使用的段暫存器肯定會產生乙個異常。

ldt表存放在ldt型別的系統段中。此時gdt必須含有ldt的段描述符。如果系統支援多ldt的話,那麼每個ldt都必須在gdt中有乙個段描述符和段選擇符。乙個ldt的段描述符可以存放在gdt表的任何地方。

訪問ldt需使用其段選擇符。為了在訪問ldt時減少位址轉換次數,ldt的段選擇符、基位址、段限長以及訪問許可權需要存放在ldtr暫存器中。

當儲存gdtr暫存器內容時(使用sgdt指令),乙個48位的"偽描述符"被儲存在記憶體中。為了在使用者模式(特權級3)避免對齊檢查出錯,偽描述符應該存放在乙個奇字位址處(即 位址 mod 4 = 2)。這會讓處理器先存放乙個對齊的字,隨後是乙個對齊的雙字(4位元組對齊處)。使用者模式程式通常不會儲存偽描述符,但是可以通過使用這種對齊方式來避免產生乙個對齊檢查出錯的可能性。當使用sidt指令儲存idtr暫存器內容時也需要使用同樣的對齊方式。然而,當儲存ldtr或任務暫存器(分別使用sltr或str指令)時,偽描述符應該存放在雙字對齊的位址處(即 位址 mod 4 = 0)。

段描述符與段選擇子

存放的是gdt 全域性描述符表 表的位置和大小,大小為48位 在windeg中 r gdtr 檢視gdt表的位置 r gdtl 檢視表的大小 gdt表裡面存放的元素稱為段描述符 大小為8位元組 dd 位址 檢視位址裡面的內容 檢視4位元組 dq 位址 檢視8位元組 eq 位址 8位元組資料 往指定位...

段選擇器 段描述符 段描述符表 線性位址形成

買了本羅老師的琢石成器,才看前3章就感覺暈暈忽忽,總體覺得要看懂這本書前提是必須會dos彙編,了解32位彙編基礎.dos彙編本人只看了王爽老師的組合語言前11章,中斷這塊還沒有看,看來不看還是不行的。轉回來說,羅老師這本書前3章寫的很亂,尤其是描述符這塊,看了似懂非懂,通而不透。只能自己抽絲剝繭,捋...

段選擇器 段描述符 段描述符表 線性位址形成

段選擇器 32位彙編中16位段暫存器 cs ds es ss fs gs 中不再存放段基址,而是段描述符在段描述符表中的索引值,d3 d15位是索引值,d0 d1位是優先順序 rpl 用於特權檢查,d2位是描述符表引用指示位ti,ti 0指示從全域性描述表gdt中讀取描述符,ti 1指示從區域性描述...