Windows X86虛擬內存尋址原理探究

Windows X86虛擬內存尋址原理探究

我們知道,在X86機器下面每個進程都有自己的4GB內核空間,當然普通情況下只有2GB地址可用,但是如果每個進分配2GB物理內存的話,針對系統幾十上百的進程,那麼需要的物理內存也太大了,而且X86的CPU是32位的尋址,最多也只能尋址4GB的物理內存,那麼具體是怎麼來實現每個進程2GB私有地址的呢?針對每個地址的物理內存操作又是怎麼實現的呢?本來來探討一下實現原理。

1. 地址轉換

其實我們每個程序使用的地址都是虛擬地址,什麼是虛擬地址呢?也就是說這個東西是虛擬的,爲了存放真實的東西,每個虛擬地址都必須轉換成爲物理地址才能使用。例如:

mov eax, dwrod prt[0x12345678]

那麼針對程序來說0x12345678這個地址就是一個虛擬地址,CPU 存取數據的時候將這個地址轉換成爲物理地址(例如0x23232323`地址)來存放。

那麼這個轉換過程是怎麼進行的呢?Windows爲每個進程保存一個這樣的表,提供虛擬地址到物理地址的映射。針對不同進程的地址0x12345678查找到不同物理地址,使得使用的時候不必衝突。

因爲不是每個進程都將虛擬內存全部用滿,所以爲了節省映射表的大小,Windows使用了二級映射(稀疏存儲)來節省內存,整個過程是:

  1. 將虛擬地址拆分成爲三個部分,第一部分爲10位,第二部分爲10,第三部分爲12位。
  2. 第一部分的10位當做第一級表的偏移。
  3. 根據第一級表的地址找到第二級表的入口。
  4. 第二部分的10當做第二級表的偏移。
  5. 根據第二級表的地址找到物理內存的入口。
  6. 第三部分爲12位爲物理內存的偏移,找到真實的物理內存。

其中:

  1. 第一級表叫做頁目錄表(PDE表)。
  2. 第二級表叫做頁表(PTE表)。
  3. 第一級表的地址存放到CR3中。

我們的頁表存放在CR3寄存器中,在所有的寄存器中,只有Cr3存儲的是物理地址,其它寄存器存的都是線性地址Cr3所存儲的物理地址,指向了一個頁目錄表(PDT),在Windows中,一個頁的大小通常爲4KB,即一個頁可以存儲1024個頁目錄表項(PDE)。

頁目錄表(PDT)的每一項元素稱爲頁目錄表項(PDE), 每個頁目錄表項指向一個頁表(PTT),每個頁表的大小爲4KB,即一個頁表可以存儲1024個頁表項(PTE)。

頁表(PTT)的每一個元素稱爲頁表項(PTE),頁表項(PTE)所指向的纔是真正的物理頁。

其中PTE有如下特徵:

  1. PTE可以指向一個物理頁,也可以不指向物理頁
  2. 多個PTE可以指向同一個物理頁
  3. 一個PTE只能指向一個物理頁

所以,對於一個虛擬地址的查找過程如下:

在這裏插入圖片描述

上圖中PDE和PTE的結構如下:

在這裏插入圖片描述在這裏插入圖片描述

對於這些標記爲的作用如下:

  1. P位:是否有效位; 注意:當PDE或PTE中有一個的屬性P=0時,物理頁就是無效的
  2. R/W位:讀寫位
    • R/W=0:只讀
    • R/W=1:可讀可寫
  3. U/S位:權限位
    • U/S=0:特權用戶
    • U/S=1:普通用戶
  4. PS位:PDE特有
    • PS == PageSize
    • PS=1:PDE直接指向物理頁,低22位=頁內偏移,偏移最大值爲4MB,俗稱"大頁"
    • PS=0:PDE指向PTE
  5. A位:訪問位
    • A=1:該PDE/PTE被訪問過
    • A=0:該PDE/PTE未被訪問過
  6. D位:髒位
    • D=1:該PDE/PTE被寫過
    • D=0:該PDE/PTE未被寫過

2. 總結

利用虛擬地址的映射的特性,Windows可以做很多的事情:

第一個就是共享內存,如下

其實就是兩個虛擬地址尋址得到的物理內存頁是同一個。

還有就是內存保護,我們知道如果我們去寫NULL地址的內存的話程序就會拋出異常,主要原因是對應的物理內存不能訪問,例如我們針對0處內存的物理地址查找過程如下:

kd> !dd 3fdd24c0
#3fdd24c0 3b119801 00000000 3ad9a801 00000000
#3fdd24d0 3aa5b801 00000000 3ab5c801 00000000
#3fdd24e0 39152801 00000000 397d3801 00000000
#3fdd24f0 38414801 00000000 38f95801 00000000
#3fdd2500 8db26620 00000000 29a16801 00000000
#3fdd2510 34a17801 00000000 34b98801 00000000
#3fdd2520 37543801 00000000 37a04801 00000000
#3fdd2530 38445801 00000000 37906801 00000000
kd> !dd 3b119000
#3b119000 3a8a5867 00000000 3b527867 00000000
#3b119010 3b10e867 00000000 3b4b5867 00000000
#3b119020 3ac58867 00000000 00000000 00000000
#3b119030 00000000 00000000 00000000 00000000
#3b119040 00000000 00000000 00000000 00000000
#3b119050 0d929867 00000000 3501a867 00000000
#3b119060 28f5a867 00000000 3b3ee867 00000000
#3b119070 3b130867 00000000 3b66f867 00000000
kd> !dd 3a8a5000
#3a8a5000 00000000 00000000 00000000 00000000
#3a8a5010 00000000 00000000 00000000 00000000
#3a8a5020 00000000 00000000 00000000 00000000
#3a8a5030 00000000 00000000 00000000 00000000
#3a8a5040 00000000 00000000 00000000 00000000
#3a8a5050 00000000 00000000 00000000 00000000
#3a8a5060 00000000 00000000 00000000 00000000
#3a8a5070 00000000 00000000 00000000 00000000

由於這個特性,如果我們改寫這個地方的內存屬性的話,那麼NULL地址就可以正常訪問了。

3. PAE

默認情況下,CPU只有32位地址線,也只能使用4GB的物理內存,然後隨着內存技術的發展,內存越來越大,4GB物理內存已經不能滿足目前的硬件要求了,因此CPU提供了PAE技術,這個技術尋址方式如下:
在這裏插入圖片描述

PAE模式下的頁表結構,把一個32位的虛擬地址分成4個部分:

  1. 0-11:頁內偏移
  2. 12-20:頁表(Page Table)
  3. 21-29:頁表目錄表(Page Table Directory)
  4. 30-31:頁目錄指針表(Page Directory Pointer Table)

可以看到,這裏PAE的分頁把頁表項做成了8個字節(即64Bit),除去低12位做標誌,還有52位可以用作尋址物理頁框,這正是PAE模式的核心。

其實在APE的環境下面,對於應用程序來說,還是隻能使用4GB的私有地址,但是物理地址尋址空間增大,PAE主要是增加物理內存的利用率。

在PAE模式下,CR3存儲的是頁目錄指針表的地址,頁目錄指針表是32字節對齊的,其大小爲32字節,所以此模式下的CR3結構如下
在這裏插入圖片描述
其中每個表項是8個字節,共有四個表項,每個表項對應1GB的內存空間。對應於這四個表項,處理器爲每個表項維護一個寄存器稱爲PDPTE0,PDPTE1,PDPTE2,PDPTE3。

在尋址的時候使用CR3就可以直接尋址到頁目錄了,在尋址的時候可以直接利用PDPTE寄存器來定位具體的頁目錄了。PDPTE結構如下:
在這裏插入圖片描述

最下面的的M表示的是是實際的物理地址位寬,假如說是64GB即36位,那麼M=36。通過12~(M-1)可以定位一個具體的物理頁框。

在頁目錄裏中,指向的頁表項的結構如下

在這裏插入圖片描述

對於目前來說,M的值一般爲36,因此整個PAE的尋址空間爲64GB。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章