1. 程式人生 > 其它 >虛幻與真實:程式中的地址如何轉換?

虛幻與真實:程式中的地址如何轉換?

1)讀取指令、讀寫資料的時候需要和記憶體進行怎樣的互動?

  • 告訴記憶體晶片:hi,記憶體老哥請你把 0x10000 地址處的資料交給我……hi,記憶體老哥,我已經計算完成,請讓我把結果寫回 0x200000 地址的空間。這些地址存在於程式碼指令欄位後的常數,或者存在於某個暫存器中。

設想一下,如果一臺計算機的記憶體中只執行一個程式 A,這種方式正好用前面 CPU 的真實模式來執行,因為程式 A 的地址在連結時就可以確定,例如從記憶體地址 0x8000 開始,每次執行程式 A 都裝入記憶體 0x8000 地址處開始執行,沒有其它程式干擾。現在改變一下,記憶體中又放一道程式 B,程式 A 和程式 B 各自執行一秒鐘,如此迴圈,直到其中之一結束。這個新場景下就會產生一些問題,當然這裡我們只關心記憶體相關的這幾個核心問題。

2) 誰來保證程式 A 跟程式 B 沒有記憶體地址的衝突?

  • 換句話說,就是程式 A、B 各自放在什麼記憶體地址,這個問題是由 A、B 程式協商,還是由作業系統決定?

3)如何解決記憶體容量問題?

  • 程式 A 和程式 B,在不斷開發迭代中程式程式碼佔用的空間會越來越大,導致記憶體裝不下?

4)如果還要拓展其他程式又該怎麼辦?

  • 如果不只程式 A、B,還可能有程式 C、D、E、F、G……它們分別由不同的公司開發,而每臺計算機的記憶體容量不同。這時候,又對我們的記憶體方案有怎樣的影響呢?

5)怎樣完美的解決以上最核心的 4 個問題?

  • 所有的程式都各自享有一個從 0 開始到最大地址的空間,這個地址空間是獨立的,是該程式私有的,其它程式既看不到,也不能訪問該地址空間,這個地址空間和其它程式無關,和具體的計算機也無關。---虛擬地址

6)什麼是虛擬地址?

  • 不存在的地址,邏輯上的,和具體的環境無關。這個環境包括軟體環境和硬體環境。

7)我們用 objdump 工具反彙編一下 Hello World 二進位制檔案看看長什麼樣?

 
 00000000000004e8 <_init>:
  4e8: 48 83 ec 08           sub   $0x8,%rsp
  4ec: 48 8b 05 f5 0a 20 00   mov   0x200af5(%rip),%rax       # 200fe8 <__gmon_start__>
  4f3: 48 85 c0               test   %rax,%rax
  4f6: 74 02                 je     4fa <_init+0x12>
  4f8: ff d0                 callq *%rax
  4fa: 48 83 c4 08           add   $0x8,%rsp
  4fe: c3                     retq
  • 左邊第一列資料就是虛擬地址,第三列中是程式指令,如:“mov 0x200af5(%rip),%rax,je 4fa,callq *%rax”指令中的資料都是虛擬地址。

8)為什麼所有的應用程式開始的部分都是這樣的?

  • 因為每個應用程式的虛擬地址空間都是相同且獨立的。

9)那麼這個地址是由誰產生的呢?

  • 連結器

10)什麼是實體地址呢?

  • 一個會被地址譯碼器等電子部件變成電子訊號的資料,這個電子訊號放到地址總線上去,多個訊號組合起來呢就可以表示為我們記憶體的一個儲存單元了。

11)地址總線上的訊號(即實體地址)除了可以選擇記憶體之外,還可以選擇那些地方?

  • 顯示卡中的視訊記憶體、I/O 裝置中的暫存器、網絡卡上的網路幀快取器。

12)虛擬地址到實體地址如何轉換?

  • 轉換機構:相當於一個函式:p=f(v),輸入虛擬地址 v,輸出實體地址 p。

13)那麼要怎麼實現這個函式呢?

  • 軟體方式實現太低效,用硬體實現沒有靈活性。

  • 最終就用了軟硬體結合的方式實現,它就是 MMU(記憶體管理單元)。

14)MMU 工作原理框架圖是怎樣的?

 

 

  • 注意地址關係轉換表本身則是放實體記憶體中的。

15)地址關係轉換表中邏輯地址和實體地址的對應關係是怎樣的?

  • 把虛擬地址空間和實體地址空間都分成同等大小的塊,也稱為頁,按照虛擬頁和物理頁進行轉換。根據軟體配置不同,這個頁的大小可以設定為 4KB、2MB、4MB、1GB,這樣就進入了現代記憶體管理模式——分頁模型。

16)分頁模型框架是怎樣的?

 

 

  • 一個虛擬頁可以對應到一個物理頁,頁大小固定。所以在地址關係轉換表中,只要存放虛擬頁地址對應的物理頁地址就行了。

17)MMU是做什麼工作的?

  • 接受虛擬地址和地址關係轉換表,以及輸出實體地址。

18)MMU的工作需要什麼前提條件?

  • 必須先開啟保護模式或者長模式,真實模式下是不能開啟 MMU 的。

19)保護模式的記憶體模型是分段模型,而MMU是分頁模型的,那怎麼說保護模式下可以工作?

  • 別忘了我們的保護模式下還有個平坦模式,繞過我們的分段模型。

20)地址產生的過程是怎樣的?

 

 

21)地址關係轉換表更專業的名字是什麼?

  • 頁表

22)為了提高查詢效率,頁表是分級的,那麼頁表分級的結構是怎樣的?

  • 一個頂級頁目錄,多箇中級頁目錄,最後才是頁表。

 

 

23)開啟 MMU,步驟是怎樣的?

  • 使 CPU 進入保護模式或者長模式。

  • 準備好頁表資料,這包含頂級頁目錄,中間層頁目錄,頁表,假定我們已經編寫了程式碼,在實體記憶體中生成了這些資料。

  • 把頂級頁目錄的實體記憶體地址賦值給 CR3 暫存器。

     
     mov eax, PAGE_TLB_BADR ;頁表實體地址
     mov cr3, eax
  • 設定 CPU 的 CR0 的 PE 位為 1,這樣就開啟了 MMU。

     
     ;開啟 保護模式和分頁模式
     mov eax, cr0
     bts eax, 0   ;CR0.PE =1
     bts eax, 31   ;CR0.P = 1
     mov cr0, eax

     

24)MMU 的主要功能是根據頁表資料把虛擬地址轉換成實體地址,但有沒有可能轉換失敗?

  • 絕對有可能,例如,頁表項中的資料為空,使用者程式訪問了超級管理者的頁面,向只讀頁面中寫入資料。這些都會導致 MMU 地址轉換失敗。

25)MMU 地址轉換失敗了怎麼辦呢?

  • MMU 停止轉換地址。

  • MMU 把轉換失敗的虛擬地址寫入 CPU 的 CR2 暫存器。

  • MMU 觸發 CPU 的 14 號中斷,使 CPU 停止執行當前指令。

  • CPU 開始執行 14 號中斷的處理程式碼,程式碼會檢查原因,處理好頁表資料返回。

  • CPU 中斷返回繼續執行 MMU 地址轉換失敗時的指令。

26)在分頁模式下,作業系統是如何對應用程式的地址空間進行隔離的?

  • 對於每個程序而言,它會誤認為(被作業系統欺騙)自己獨有所有地址空間,因此它訪問地址是不會考慮任何問題的,可是這個地址是虛擬地址,待被MMU翻譯後會得到對應的頁表,而這個頁表由作業系統管理,不同的程序擁有不同的頁表,也因此產生了程序地址空間隔離,但是多個程序也是可以共享某個頁表,這也是程序通訊(IPC)的根本手段。