天天看點

IA32(x86) 記憶體管理:分段機制

IA32(x86) CPU 架構在 8086 到 80386 的發展中,為了相容舊程式,又提供新特性,引入了實模式和保護模式的概念。CPU 首先從實模式啟動,這可以認為是 8086 的運作模式,并由軟體控制切換到保護模式,獲得新特性。

與 IA32 有關的硬體程式設計,需要參考 IA32 架構軟體開發人員手冊。

分段是一種隔離不同的代碼、資料、棧子產品的機制,能夠保證不同程序或任務不會互相幹擾。我們可以為一個程序配置設定屬于它的段集合,CPU 的硬體機制會保證其代碼不會越權通路段,也不會通路到段外的位址。

保護模式下的尋址不再由段寄存器和偏移量寄存器的值計算得到,必須借助于段。分段機制是保護模式下必須開啟的,沒有标志位可用于關閉分段機制。

X86 CPU 的可尋址空間(即線性位址空間)為

0 - 0xFFFFFFFFH

。我們将線性位址空間分為較小的、受保護的位址空間,并命名為段。

邏輯位址由段選擇子和偏移量組成。 段選擇子是一個段的唯一辨別,能夠找到對應的段描述符。 段描述符描述了段的大小、通路權限、優先級、類型及段基址。 線性位址由段基址和偏移量組成。 通過向 CPU 傳入邏輯位址,CPU 能夠找到對應的段,将邏輯位址映射到線性位址。如果沒有開啟分頁機制,則線性位址即為實體位址。

段選擇子 Selector

段選擇子 16 位。它不直接指向段或段描述符,而是借助于 GDT/LDT。

IA32(x86) 記憶體管理:分段機制
  • RPL

    請求特權級。指明以哪一特權級通路段。
  • TI

    表訓示标記。指明使用 0(GDT) 還是 1(LDT) 查找段描述符。
  • INDEX

    索引。13 位(8192)。目标描述符在 GDT/LDT 中的 INDEX * 8(段描述符長度) 處。

通過段選擇子,能夠唯一确定一個段。

段描述符 Descriptor

段描述符 64 位。它是包含段的元資訊的資料結構。

IA32(x86) 記憶體管理:分段機制

一般地,段描述符由編譯器、連接配接器、裝載器或作業系統設立。

  • 段基址、段界限均是兩段比特位拼接而成。
  • S

    系統描述符标志位。指明是系統描述符(1)或普通代碼段或資料段描述符(0)。
  • TYPE

    類型域。和

    S

    一起指明段的類型,并确定段的通路權限和增長方向。
  • DPL

    描述符特權級。指明段的特權級。
  • P

    段存在标志位。指明段目前是(1)否(0)在記憶體中。
  • AVL

    由使用者(作業系統)使用。
  • D/B

    預設操作數大小标志位。指明是 32 位的段(1)還是 16 位(0)。
  • G

    粒度标志位。指明段界限的機關是 1B(0)還是 4KB(1)。段基址的粒度永遠是 1 位元組。

段描述符類型

S

== 0 時

S

== 0 時,

TYPE

含義如下表所示。

IA32(x86) 記憶體管理:分段機制

最高位決定是資料段(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

== 1 時,

TYPE

含義如下表所示。

IA32(x86) 記憶體管理:分段機制

這裡不較長的描述系統描述符。

段描述符表

段描述符表是一個以段描述符為元素的數組。段描述符表的長度是可變的,最多可以有 $2^13 = 8192$ 個段描述符,每個段描述符 8 位元組(64 位),即 64KB。

有兩種描述符表:全局描述符表(GDT)和局部描述符表(LDT)。

在進入保護模式前,必須定義一個 GDT,以供所有程序或任務使用。 GDT 的線性基址和界限需裝入 GDTR 寄存器。

IA32(x86) 記憶體管理:分段機制

基址以 8 位元組方式對齊可獲得最好的處理器性能。 界限以位元組計。因為段描述符總是 8 位元組長,是以段描述符表的界限應該總是

8N-1

LDT 位于類型為 LDT 的系統段内。GDT 必須包含至少一個指向 LDT 段的段描述符。 LDT 的段選擇子需裝入 LDTR 寄存器。

IA32(x86) 記憶體管理:分段機制

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