本頁使用了標題或全文手工轉換

x86記憶體區段

維基百科,自由的百科全書
跳至導覽 跳至搜尋

x86架構中,記憶體區段英語:Memory Segmentation)是在不改變16位元段選擇子時,使用單個索引暫存器(儲存了段內地址偏移值)所能夠定址的的記憶體範圍部份。也指在英特爾x86指令集體系結構下記憶體區段的實現方式。

8086開始到隨後的各款x86架構CPU,無論是真實模式還是保護模式,記憶體定址時都使用16位元段暫存器(segment register)。段暫存器預設使用情況為:

  • 代碼段暫存器CS與暫存器IP相配合獲得當前線程代碼執行到的記憶體位置;
  • 數據段暫存器DS與各通用暫存器配合存取記憶體中的數據;
  • 棧段暫存器SS與暫存器(E)SP、(E)BP配合存取線程的呼叫棧(call stack);
  • 擴充功能段暫存器ES用於特定字串指令(如MOVS或CMPS)。
  • 80386引入了2個額外的段暫存器FS與GS,並無特定的硬件用途。

這些段暫存器除了有16位元的可見部分,還有不可見的隱藏部分,稱為描述符緩衝記憶體「descriptor cache」或隱藏暫存器「shadow register」[1]。當一個段選擇子(segment selector)裝入段暫存器的可見部分,處理器同時也把該段描述符的其它數據裝入到段暫存器的隱藏部分,這包括段開始的基地址、段長度、存取控制資訊等。這些資訊緩衝記憶體到段暫存器中,避免了處理器在轉址(translate address)時花費額外的總線周期從段選擇子表中讀入數據。處理器指令中可以明示使用哪些段暫存器,這將替換掉預設使用的段暫存器。[2]

歷史[編輯]

1978年的Intel 8086開始引入了記憶體區段。這使得16位元CPU可以存取超過64 KB (65,536位元組)的記憶體,實際上8086 CPU到記憶體的地址總線是20位,即可存取220=1MB記憶體。在16位元模式,要讓應用程式使用多個記憶體區段(為了存取比任一64K區段還要大的記憶體)是相當複雜。這個問題的根源在於沒有適當的適合做整個記憶體範圍的平面定址的地址算術指令。平面定址方式也可以乘法指令來完成,但這會導致較慢的程式執行速度。

1982年面世的80286處理器的真實模式保護模式,以及80386及其後的處理器的虛擬86模式,一個區段的大小是64 KiB(使用16位元索引暫存器)。在Intelx86真實模式下的區段架構的記憶體空間會有所重疊,這是一種不好的設計。 80286的保護模式下,16位元的段暫存器中的13位(稱作段選擇子segment selector)是描述符表的條目(descriptor table entry)的索引;該條目包含了24位元的段開始地址以及16位元的段長度;段開始地址與段內偏移地址相加即為記憶體實體位址。16位元段暫存器中的剩餘3位分別是全局/局部描述符表指示位、請求特權級(request privilege level)。

1985年面世的80386及其後續處理器的32位元保護模式下,一個區段長度上限是220個粒度單位,粒度可以是1位元組或4K位元組,因此區段長度上限可以是4 GB,這與索引暫存器是32位元相配合。

隨着32位元作業系統的推出,以及更舒適的32位元平面記憶體模式,到1990年末期幾乎淘汰了使用區段定址。然而,使用32位元平面記憶體模式產生的最多只能存取4 GB地址空間的限制並沒有遠離日常的使用。區段允許作業系統對每個行程虛擬定址空間的限制,最大可利用64 GB的系統記憶體,但這種最終回歸到區段的尷尬,經常被引述為朝着64位元處理器發展的動機。

2003年問世的x86-64架構下,強制實現了平面記憶體模型,但保留了使用段暫存器FS或GS的64位元下的區段定址。

真實模式[編輯]

真實模式虛擬86模式下,一個段總是長64,536位元組(16位元段內偏移地址)。在段暫存器內的16位元段選擇子(segment selector)被解釋為20位線性地址空間的高16位元,稱為段地址;其餘的低4位元全為0。段地址與16位元段內偏移地址相加產生線性地址,同時也是這種記憶體模式下的實體位址。 任何程式都可以存取全部記憶體空間。沒有對記憶體的存取權限保護。

80286保護模式[編輯]

Intel 80286處理器仍然使用16位元段暫存器與16位元的段內偏移地址,但保護模式下支援存取224(16M)位元組的記憶體。16位元段暫存器內不再是段地址,16位元段暫存器的高13位被稱作段選擇子(segment selector),其值是到段描述符英語segment descriptors表的索引值。段描述符中包含了24位元的段開始的基地址,20位的段長度。段開始地址與段內偏移地址相加即為記憶體實體位址。段的長度上限為220=1M位元組。

80386保護模式[編輯]

Intel 80286處理器繼續使用286的區段保護模式,但段描述符中包含了32位元的段開始的基地址。段內偏移地址也是32位元。在區段轉址與實體位址之間又增加了一層分頁(paging)轉址。區段定址是不能關閉的。分頁可以使能或關閉(enabled or disabled),如果關閉就與286保護模式一樣。如果使用分頁機制,則由段開始的基地址與段內偏移地址相加得到的是線性地址(虛地址),線性地址還需要分頁轉址才得到記憶體實體位址。

386的段描述符中的段長度為20位,段長度的粒度可設為1位元組或212位元組。因此段長度可以為1位元組-1M位元組,或者為1×4K位元組-1M×4K位元組。段描述符的數據結構為;

B[a] Bits[b] 80286 80386 B[a]
0 00..07, 0..7 limit bits 0..15 of limit 0
1 08..15, 0..7 1
2 16..23, 0..7 base address bits 0..23 of base address 2
3 24..31, 0..7 3
4 32..39, 0..7 4
5 40..47, 0..7 attribute flags #1 5
6 48..51, 0..3 unused bits 16..19 of limit 6
52..55, 4..7 attribute flags #2
7 56..63, 0..7 bits 24..31 of base address 7

Attribute flags #2
52 4 unused, available for operating system
53 5 reserved, should be zero
54 6 default flag / D-bit
55 7 granularity flag / G-bit

  1. Byte offset inside entry.
  2. First range is the bit offset inside entry; second range is the bit offset inside byte.


386處理器增加了兩個段暫存器FS、GS,這兩個暫存器並無硬件繫結的用途。Windows作業系統在地址FS:0中儲存了當前線程資訊塊。Linux中GS指向了線程局部儲存

通過清除控制暫存器CR0中的最低位,可由386保護模式轉為真實模式。

Linux作業系統在386保護模式下把段基址設為0,段長度設為4GiB,從而模擬了平面記憶體模型。

段暫存器名字 描述 基地址 段長度 段描述符特權級
__KERNEL_CS 內核代碼段 0 4 GiB 0
__KERNEL_DS 內核數據段 0 4 GiB 0
__USER_CS 用戶代碼段 0 4 GiB 3
__USER_DS 用戶數據段 0 4 GiB 3

x86-64的64位元模式[編輯]

在x86-64體系結構64位元的long mode,段暫存器CS, SS, DS, ES強制為0。段長度強制為264。形式上還有記憶體區段,但實際上所有記憶體都在唯一的一個區段中。段暫存器FS、GS可以有非0值,被作業系統用於其它用途。即硬件支援如「FS:[RAX]」這樣的暫存器間接定址。

參考文獻[編輯]

  1. ^ "Intel 64 and IA-32 Architectures Software Developer's Manual", Volume 3, "System Programming Guide", published in 2011, Page "Vol. 3A 3-11".
  2. ^ Intel Corporation (2004). IA-32 Intel Architecture Software Developer's Manual Volume 1: Basic Architecture