IA32(x86) CPU 架構在 8086 到 80386 的發展中,為了相容舊程式,又提供新特性,引入了實模式和保護模式的概念。CPU 首先從實模式啟動,這可以認為是 8086 的運作模式,并由軟體控制切換到保護模式,獲得新特性。
與 IA32 有關的硬體程式設計,需要參考 IA32 架構軟體開發人員手冊。
分段是一種隔離不同的代碼、資料、棧子產品的機制,能夠保證不同程序或任務不會互相幹擾。我們可以為一個程序配置設定屬于它的段集合,CPU 的硬體機制會保證其代碼不會越權通路段,也不會通路到段外的位址。
保護模式下的尋址不再由段寄存器和偏移量寄存器的值計算得到,必須借助于段。分段機制是保護模式下必須開啟的,沒有标志位可用于關閉分段機制。
X86 CPU 的可尋址空間(即線性位址空間)為
0 - 0xFFFFFFFFH
。我們将線性位址空間分為較小的、受保護的位址空間,并命名為段。
邏輯位址由段選擇子和偏移量組成。 段選擇子是一個段的唯一辨別,能夠找到對應的段描述符。 段描述符描述了段的大小、通路權限、優先級、類型及段基址。 線性位址由段基址和偏移量組成。 通過向 CPU 傳入邏輯位址,CPU 能夠找到對應的段,将邏輯位址映射到線性位址。如果沒有開啟分頁機制,則線性位址即為實體位址。
段選擇子 Selector
段選擇子 16 位。它不直接指向段或段描述符,而是借助于 GDT/LDT。

-
請求特權級。指明以哪一特權級通路段。RPL
-
表訓示标記。指明使用 0(GDT) 還是 1(LDT) 查找段描述符。TI
-
索引。13 位(8192)。目标描述符在 GDT/LDT 中的 INDEX * 8(段描述符長度) 處。INDEX
通過段選擇子,能夠唯一确定一個段。
段描述符 Descriptor
段描述符 64 位。它是包含段的元資訊的資料結構。
一般地,段描述符由編譯器、連接配接器、裝載器或作業系統設立。
- 段基址、段界限均是兩段比特位拼接而成。
-
系統描述符标志位。指明是系統描述符(1)或普通代碼段或資料段描述符(0)。S
-
類型域。和TYPE
一起指明段的類型,并确定段的通路權限和增長方向。S
-
描述符特權級。指明段的特權級。DPL
-
段存在标志位。指明段目前是(1)否(0)在記憶體中。P
-
由使用者(作業系統)使用。AVL
-
預設操作數大小标志位。指明是 32 位的段(1)還是 16 位(0)。D/B
-
粒度标志位。指明段界限的機關是 1B(0)還是 4KB(1)。段基址的粒度永遠是 1 位元組。G
段描述符類型
S
== 0 時
S
S
== 0 時,
TYPE
含義如下表所示。
最高位決定是資料段(0)還是代碼段(1)。
A
通路位。表示最後一次清零後,段是否被通路過。CPU 會在把段選擇子裝入段寄存器後,将段的通路位置 1,并保持到作業系統進行顯式清零為止。通路位一般用于虛拟記憶體管理和調試。
對于資料段:
W
是否可寫。
E
擴充方向。
E
== 0 時
[BASE, BASE + limit]
這段空間是可通路的,其它空間不可通路,稱為向上擴充;
E
== 1 時
(BASE + limit, MAX]
不可通路,其它空間可通路,稱為向下擴充。
D/B
稱為
B
标志位。同時指明上述的
MAX
是 4GB(1) 還是 64KB(0)。
堆棧段必須是可讀寫的資料段。為 SS 裝載一個不可寫的資料段選擇子會導緻“一般保護異常”。
對于代碼段:
R
是否可讀。表示是否可以從代碼段裡讀取資料。
C
是否有一緻性。
程序轉入有更高特權級的有一緻性的代碼段可以繼續運作。一般地,不能被更低特權級的程序通路的代碼應該被載入非一緻性代碼段。
所有的資料段都是非一緻性的,但無需使用特别的通路門,即可被更高特權級的程序通路。
保護模式中,代碼段是不可寫的。
S
== 1
S
S
== 1 時,
TYPE
含義如下表所示。
這裡不較長的描述系統描述符。
段描述符表
段描述符表是一個以段描述符為元素的數組。段描述符表的長度是可變的,最多可以有 $2^13 = 8192$ 個段描述符,每個段描述符 8 位元組(64 位),即 64KB。
有兩種描述符表:全局描述符表(GDT)和局部描述符表(LDT)。
在進入保護模式前,必須定義一個 GDT,以供所有程序或任務使用。 GDT 的線性基址和界限需裝入 GDTR 寄存器。
基址以 8 位元組方式對齊可獲得最好的處理器性能。 界限以位元組計。因為段描述符總是 8 位元組長,是以段描述符表的界限應該總是
8N-1
。
LDT 位于類型為 LDT 的系統段内。GDT 必須包含至少一個指向 LDT 段的段描述符。 LDT 的段選擇子需裝入 LDTR 寄存器。
GDT 的第 0 項是不用的,稱為空段選擇子。空選擇子一般用于初始化未使用的段寄存器。 CS 或 SS 裝載空選擇子會産生“一般保護異常”;其他段寄存器指向空選擇子時不會産生異常,但使用空選擇子通路記憶體會産生異常。
内部尋址過程
提供邏輯位址,得知段選擇子,假設是 GDT 段,通過 GDTR 找到 GDT,通過段選擇子和 GDT 找到段描述符,通過段描述符得知段基址,即可将邏輯位址轉換為線性位址。
分段記憶體模型
用不同的方法使用分段機制,能夠建立不同的分段記憶體模型。
平坦(flat)模型中,程式通路一個連續的、沒有分段的位址空間。
基本平坦模型可以通過建立 2 個段描述符,分别指向代碼段和資料段來實作。這兩個段被映射到整個線性位址空間——這句話的意思是,兩個段的基址為 0,界限為 4GB。 這樣,即使通路的位址超過了實體記憶體,CPU 也不會抛出“超出記憶體範圍”的異常。
保護平坦模型的段界限設為在實際的實體記憶體範圍内,如果超出則産生“一般保護異常(#GP)”。該模型最小程度地利用了硬體的保護機制來防止程式錯誤。
更複雜地,定義 4 個段描述符,分别指向特權級 0 和 3 的代碼段和資料段。一般地,這些段互相重疊,都從位址 0 開始。這種平坦分段模型,再加上簡單的分頁結構,已經能夠保護作業系統免受應用程式幹擾。如果再為每個程序配置設定一個分頁結構,也能夠保護應用程式。
多段模型充分利用分段機制,在各種場景中使用硬體強制保護機制。通路記憶體時,通過每一個段寄存器得到所使用的段描述符,提供相應權限,進行位址轉換。
版權聲明:本文為CSDN部落客「weixin_33816300」的原創文章,遵循CC 4.0 BY-SA版權協定,轉載請附上原文出處連結及本聲明。
原文連結:https://blog.csdn.net/weixin_33816300/article/details/91918825