32位的虛擬地址翻釋成32位的物理地址
自 386開始,IA-32處理器開始支持分頁機制。分頁機制的主要目的是高效地利用內存,按頁來組織和管理內存空間,把暫時不用的數據放到外部存儲器(通常 是硬盤)上。在啓用分頁機制後,操作系統將將線性地址空間劃分爲固定大小的頁面(4kb、2MB、4MB)。每個頁面可以被映射到物理內存或外部存儲器上 的虛擬內存文件中。 下面就介紹一下WINDOWS是如何把32位的虛擬地址翻釋成32位的物理地址的。
我們先看下面的一張圖:
我們可以用通常書本中的目錄來理解。請看十圖:
一、在進入主題之前,我們來理解三個概念:CR3寄存器、頁目錄、頁表。
1、CR3寄存器。
CR3寄存器又稱爲頁目錄基址寄存器。
2、頁目錄。
頁目錄是存放頁目錄表項(Page-Directory Entry,
簡稱PDE)線性表。每個頁目錄佔一個4KB的內存頁,每個PDE的長度爲32個比特位(4字節),因此每個頁目錄中最多包含1024個PDE。下圖畫出
了指向4KB頁表的PDE的大概的格式,圖中高20位代表該PDE所指向頁表起始物理地址的高20位,該起始物理地址的低12位固定爲零,所以頁表一定是
按照4KB對齊的。
指向頁表的頁目錄表項(PDE)的格式
3、頁表。
頁表是用來存放頁表表項(Page-Table Entry,
簡稱PTE)的線性表。每個表佔一個4KB的內存頁,每個PTE的長度爲32比特位,因此每個頁表中最多包含1024個PTE。下圖畫出了PTE的大概的
格式,其中高20位代表的是4KB內存頁的起始物理地址的的高20位,該起始物理地址的低20位假定爲零,所以4KB內存頁都是按4KB進行對齊的。
頁表表頁(PTE)的格式
二、地址翻譯。
有了上面的基礎後,下面就來看一下CPU是如何利用頁目錄和頁表等數據結構將一個32位的虛擬地址翻譯爲32位的物理地址的。其過程可以概括如下:
1、通過CR3寄存器定位到頁目錄的起始地址,正因爲如此,CR3寄存器又被稱爲頁目錄基地址寄存器。
2、取線性地址的高10位作爲索引選取頁目錄的一個表項,也就是PDE。
3、根據PDE中的頁表基地址(取PDE的高20位,低12位設爲零)定位到頁表。
4、取線性地址的12位到21位(共10位)作爲索引選取頁表的一個表頁,也就是PTE。
5、取出PTE中的內存基地址(取PTE的高20位,低12位設爲零)。
6、取線性地址的低12位作爲頁中的偏移與上一步的內存頁基地址相加便得到物理地址。
這整個過程就是本頁的第一個圖所描繪的。
三、下面通過實例來說明。
這個實驗要求在安裝好了WinDBG工具Windows XP SP1的進行。
1、運行計算器程序(calc.exe),鍵入一串數字(如123456789)以便後面的觀察。
2、啓動WinDBG,並附加到計算器程序上開始調試(File|Attach to process...)。
3、在WinDBG的命令區中輸入x calc!g*命令列出所有以g開頭的符號。注意其中包含的gpszNum行。
01014db0 calc!gqszNum = <no type information>
3、在WinDBG命令區輸入dd calc! gpszNum 11命令,查看該符號地址的內容.
01014db0 000a6c88
5、繼續查看地址000a6c88(應該換作你試驗時看到的值)處的內容:dd 000a6c88
0:002>dd 000a6c88
000a6c88 00320031 00340033 00360035 00380037
000a6c98 00000039 00000000 00040004 000c0100
...
6.看來000a6c88指向的很像我們前面輸入的數字。使用顯示字符串命令進一步驗證:
0:002> du 000a6c88
000a6c88 “123456789”
看來真是如此,嘗試鍵入其他的數字,再重複第4到第6步,可以進一步驗證。主意gpszNum11的值是會變化的,也就是它是指向一個動態分配的緩衝 區,該緩衝區包含了用戶輸入的字符串。下面我們來看一下如何把這個字符串地址(000a6c88)翻譯爲物理地址。
7.先將這個虛擬地址轉換爲二進制格式,以便了解它的各個位域的值。這可以使用.formats命令。
0:002> .formats 000a6c88
Evaluate expression:
Hex: 000a6c88
Decimal:683144
Octal: 00002466210
Binary: 00000000 00001010 01101100 10001000
根據上面的數據,虛擬地址000a6c88的頁目錄索引爲0,頁表索引爲001010110b,即0xA6,頁內偏移爲110010001000b,即0xc88。
8.再啓動一個WinDBG實例,並開始本地內核調試以便觀察計算器進程的頁目錄基地址。以下所有操作都是在這個WinDBG中進行的。
9.先通過!process 0 0命令列出所有進程,並在其中找到關於calc.exe的內容。
lkd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
...
PROCESS 86474030 SessionId: 0 Cid: 0bf8 Peb: 7ffdf000 ParentCid: 0d98
DirBase: 3a744000 ObjectTable: e25acb08 HandleCount: 39.
Image: calc.exe
...
10.上面的DirBase項描述的就是calc進程的頁目錄基地址的物理地址(CR3寄存器的內容)。也就是說,該進程的內存頁目錄表的基地址是0x3a744000。
11.使用!dd命令顯示目錄表的內容。
lk> !dd 3a744000
#3a744000 15f93067 1b4c8067 0c8ec067 1b1e7067
#3a744010 2c792067 00000000 00000000 00000000
#3a744020 00000000 00000000 00000000 00000000
...