「學習筆記」對實模式/保護模式的三種訪問內存機制的理解


  假設x86處理器執行以下的指令

1 mov ds, cx    ;其中假設 (cx) = 0x0010

  主要討論實模式和保護模式:這包括16位模式即實模式,32位模式即保護模式,以及32位模式下的16位兼容模式(首先需要明確的是保護模式有着不同的內存訪問機制,簡單地說就是傳統的涉及段的幾個寄存器如CS,DS,ES,SS等被解釋為不同的內容——實模式解釋為段寄存器,保護模式解釋為段選擇子,可以先理解為換一種叫法,但要注意它們保存的內容也會有着不同的處理方式)

 

 

  (在討論之前我想先說說下面我用紅字標出來的內容是相對於其他模式尋址機制不同的地方,其次我會用 “斜體的引用” 注解新引入的概念)

  1、16位模式/實模式:

    執行 mov ds, cx 時,DS解釋為段寄存器,0x0010作為段基址

    先直接將0x0010賦給DS

    然后當訪問涉及內存的指令如 mov [0x00], al 時,處理器自動完成段基址0x0010左移4位再加上偏移地址(這個例子是0x00)

    最后訪問該過程得到的20位物理地址(這個例子是0x00100)便是該模式訪問內存的過程

  2、32位下的(兼容)實模式——比如保護模式下運行8086程序,或者說32位模式下運行16位程序

    執行 mov ds, cx 時,DS仍然解釋為段寄存器,0x0010也仍然作為段基址

    先直接將0x0010賦給DS

    然后當訪問涉及內存的指令如 mov [0x00], al 時,處理器也是自動完成段基址0x0010左移4位,不過之后處理器會把左移4位后產生的地址傳送到描述符高速緩存器(此時描述符高速緩存器的內容是0x100),再加上偏移地址(該例子中是0x00)

    最后訪問該過程得到的20位物理地址(這個例子是0x00100)便是該模式訪問內存的過程

這里簡單解釋一下“描述符高速緩存器”:

  32位模式下尋址空間必然會增大,這就使得原來實模式(16位)尋址機制需要擴展,相應地段寄存器也需要擴展。簡單地說就是在32位模式下,段寄存器除了包括原來的CS,DS這一類傳統的段相關的寄存器,還包括一個對程序員來說不可見的部分——這個不可見部分就是描述符高速緩存器,它的作用就是緩存段基址(你可以能會疑惑為什么保護模式比實模式要多一步緩存,這個緩存的意義是什么?別急,在說完下面保護模式的尋址之后,我會在本博文最后附上我的理解)。

  3、32位模式/保護模式:

    執行 mov ds, cx 時,DS此時解釋為段選擇器,0x0010此時作為段選擇子

這里也簡單解釋一下“段選擇子”:

  段選擇子:段描述符段描述符表中的索引號(可以先認為表項在表中的項號,但是實質上段選擇子除了索引號還有其他組成部分)

 

那段描述符和段描述符表又是什么呢?

  這得先從保護模式是什么講起。一個程序在實模式下設置的數據段是任意的,也就是說可以設置在1MB范圍內的隨意一個區域——這就使得程序可以在即使不屬於它自己的內存單元的訪問也沒有一點障礙,這是非常不安全也是不合理的。

  而保護模式對實模式一個很重要的改進就是,保護模式讓每個程序都先定義它自己能夠訪問的內存區域,這樣每當一個程序想要非法地訪問不屬於它自己的區域時能有依據地被制止。而每個程序能夠訪問的內存區域實質上是其定義的數據段、代碼段、棧段等,這些段的定義信息就被保存於內存的某個區域內

  這個區域是一堆這樣的“段定義信息”,這個區域便是段描述符表(Global Descriptor Table, GDT),而這一個個組成整個表的表項就是段描述符(Segment Descriptor)

    此時處理器會先將段選擇子(段選擇子可以指示索引號)乘以8作為偏移地址,再同GDTR(Global Descriptor Table Register,段描述符表寄存器)中提供的GDT表的基地址相加,求得結果指向GDT表中某個表項(即某個段描述符),並加載表項中的該段的基地址到描述符高速緩存器

這里也簡單解釋一下為什么要“段選擇子乘以8”,以及“GDTR”是什么

  段選擇子乘以8:在段描述符表中,每個表項長8字節,每個表項從0開始編排索引號。所以當我們訪問GDT的時候,先讀取GDT表頭地址(也就是索引號#0的地址),這樣每個表項的地址便可用相對GDT表頭地址來表示——比如我們讀取到GDT表頭地址為0xXXXX_XXX0,則索引號#0地址為0xXXXX_XXX0,索引號#1地址為0xXXXX_XXX8(前面是索引號#0,長8字節)...——這樣便可以用段選擇子(段選擇子可以指示索引號)乘以8來找出段描述符的地址,這個地址便是段描述符相對於GDT表頭的地址

  GDTR(Global Descriptor Table Register,段描述符表寄存器):主要作用是用來找到GDT,該寄存器保存有GDT在內存中的起始地址

    然后當訪問涉及內存的指令如 mov [0x00], al (32位模式也可用8位操作數)時,處理器將描述符高速緩存器中的段基地址加上該指令中給出的偏移地址

    最后訪問該過程得到的32位物理地址(這個例子是0x00000100)便是該模式訪問內存的過程

 

 

 

  最后我想注解一下第一個引用結尾提出來的問題:為什么保護模式比實模式要多一步緩存,這個緩存的意義是什么?

  經過保護模式尋址的討論,我們可以知道保護模式的尋址最簡單地可以理解為多增加了一步——查表,為什么需要查表?因為實模式無限制的尋址並不安全,所以保護模式需要先在表中定義每個段所能訪問的地址空間(這是最簡單的理解)。而查表會帶來開銷,對於指令給出一個偏移地址。思考實模式的尋址機制,實模式是每給一個偏移地址就進行左移4位再相加的動作;而到了保護模式,如果也像實模式這樣每給出一個偏移地址就查表相加,這一步是存在開銷的,所以此時引入的緩存機制,可以避免每次訪問內存的操作時都進行一次查表操作。這便是我的粗略理解。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM