1. IA-32架構的基本執行環境
1.1 寄存器的擴充
為了在彙編語言程式中使用經過擴充(Extend) 的寄存器:

在32位模式下,為了生成32位實體位址,處理器需要使用32位的指令指針寄存器。标志寄存器也擴充到32位,第16位和原先保持一緻。
32位處理器依然需要以段位機關通路記憶體,即,隻分一個段,段地基位址是0x00000000,段地長度(大小)是4GB。在這種情況下,可以視為不分段,即平坦模式(Flat Mode)。
在32位模式下傳統的段寄存器,儲存的不再是16位段位址,而是段選擇器,而且增加了兩個額外的段寄存器FS和GS,每個段寄存器還包括一個不可見部分,稱為描述符高速緩存器。
1.2 線性位址
段的管理是由處理器的段部件負責進行的,段部件将段位址和偏移位址相加,得到通路記憶體的位址。一般來說,段部件産生的位址就是實體位址。
分頁功能将實體記憶體空間劃分成邏輯上的頁。頁的大小是固定的,一般為4KB,通過使用頁,可以簡化記憶體管理,将小塊記憶體空間,配置設定給某個任務。
當頁功能開啟時,段部件産生的位址就不再是實體位址了,而是線性位址(Linear Address),線性位址還要經頁部件轉換後,才是實體位址。
線性位址的概念用來描述任務的位址空間。IA-32 處理器上的每個任務都擁有4GB 的虛拟記憶體空間,這是一段長 4GB 的平坦空間,就像一段平直的線段,是以叫線性位址空間。相應地,由段部件産生的位址,就對應着線性位址空間上的每一個點,這就是線性位址。
2. 現代處理器的結構和特點
2.1 流水線
為了提高處理器的執行效率和速度,可以把一條指令的執行過程分解成若幹個細小的步驟,并配置設定給相應的單元來完成。各個單元的執行是獨立的,并行的。如此一來,各個步驟的執行在時間上就會重疊起來,這種執行指令的方法就是 流水線(Pipe-Line) 技術。
2.2 高速緩存
寄存器的速度最快,因為使用了觸發器,這是一種回報原理制作的存儲電路,工作速度是 納秒(ns) 級别的。記憶體(DRAM 動态存儲器) 晶片的材料一般是電容和單個的半導體,由于電容需要定時重新整理,使得他的通路速度變得很慢,通常是幾十個納秒。最後是硬碟,由機電裝置,通常在毫秒級(ms)。
這種情況下,為了解決需要等待記憶體和硬碟這樣的低速裝置,一個在處理器和 記憶體(DRAM) 之間速度可以比對的靜态存儲器 高速緩存(Cache) 應運而生。
利用程式運作時的局部性原理,可以把處理器正在通路和即将通路的指令和資料塊從記憶體調入高速緩存中。于是,每當處理器要通路記憶體時,首先檢索高速緩存。如果要通路的内容已經在高速緩存中,那麼,可以用極快的速度直接從高速緩存中取得,這稱為命中(Hit);否則,稱為不中(Miss)。在不中的情況下,處理器在取得需要的内容之前必須重新裝載高速緩存,而不隻是直接到記憶體中去取那個内容。高速緩存的裝載是以塊為機關的,包括那個所需資料的鄰近内容。為此,需要額外的時間來等待塊從記憶體載入高速緩存,在該過程中所損失的時間稱為不中懲罰(MissPenalty)。
2.3 亂序執行
為了實作流水線技術,需要将指令拆分成更小的可獨立執行部分,即拆分成微操作(Micro-Operations),簡寫為μ ops。
有些簡單指令隻用一個微操作:
add eax,ebx
有些指令可以拆分成兩個微操作,一個從記憶體中讀取資料并儲存到臨時寄存器,另一個用于将EAX寄存器和臨時寄存器的數值相加。
add eax,[mem]
這個可以拆分成三個微操作一個從記憶體中讀資料,一個執行相加的動作,第三個用于将相加的結果寫回到記憶體中。一旦将指令拆分成為操作,處理器就可以在必要的時候 亂序執行(Out-Of-Order Execution) 程式:
mov eax,[mem1]
shl eax,5
add eax,[mem2]
mov [mem3],eax
這裡,指令mov [mem2],eax可以拆分成兩個微操作,如此,在執行邏輯左移指令的同時,處理器可以提前從記憶體中讀取mem2的内容,典型的,如果資料不在高速緩存中,那麼處理器在擷取mem1的内容之後,會立即開始擷取mem2的内容,于是同時,shl指令已經開始執行了。同理,亂序執行可以大大加快如push,call等指令的執行速度。
2.4 寄存器重命名
mov eax,[mem1]
shl eax,3
mov [mem2],eax
mov eax,[mem3]
add eax,2
mov [mem4],eax
代碼上做了兩件事情,一個是将mem1的内容進行左移3個機關,另一個是将mem3的内容+2,如果将後面三個操作所用的寄存器名名稱不同的名字,那麼這個操作也不會被影響,是以處理器為最後三條指令使用了另一個不同的臨時寄存器,是以左移和加法可以并行地進行。
mov eax,[mem1]
mov ebx,[mem2]
add ebx,eax
shl eax,3
mov [mem3],eax
mov [mem4],ebx
假定現在mem1的内容在高速緩存中,可以立即取得,但mem2的内容不在高速緩存中,也就是說,算術左移可以在add之前就進行了,是以我們為左移設定一個新的臨時寄存器,那麼這樣eax的内容認識以前的,他将一直儲存着這個值,直到ebx的内容就緒,然後和它一同做加法運算。如果沒有寄存器重命名機制,左移操作将不得不等待從内從中讀取mem2的内容到EBX寄存器中以及加法操作。
在所有操作都完成後,那個代表EAX寄存器的最終結果的臨時寄存器的内容被寫入真實的EAX寄存中,該處理過程被稱為引退(Retirement)。所有通用寄存器,棧指針,标志,浮點寄存器,甚至段寄存器都有可能被重命名。
2.5 分支目标預測
流水線并不是百分百完美解決方案。如果遇到轉移指令,則後面已經進入流水線的指令就無效了。是以引入了分支預測技術(Branch Prediction)。它會預測預測會不會發生轉移,當處理器執行了一條分支語句後,它會在處理器内部一個小容量的高速緩存器,叫 分支目标緩存器(Branch Target Buffer,BTB) 中記錄目前指令的位址,分支目标的位址,以及本次分支預測的結構。下一次,在那條轉移指令實際執行前,處理器會查找 BTB,看有沒有最近的轉移記錄。如果能找到對應的條目,則推測執行和上一次相同的分支,把該分支的指令送入流水線。
當該指令實際執行時,如果預測是失敗的,那麼,清空流水線,同時重新整理 BTB 中的記錄。這個代價較大。
3. 32位模式的指令系統
3.1 32位處理器的尋址方式
如果處理器在16位模式下,沒有指令字首0x66,則認為指令是傳統的16位尋址方式,如果有指令字首0x66,則是32位尋址方式,在32位模式下,沒有指令字首0x66,則認為指令是傳統的32位尋址方式,如果有指令字首0x66,則是16位尋址方式。指令預設使用32位寬度的寄存器和32位的立即數,如果存在記憶體尋址,則偏移量也是32位的。
32位模式下,記憶體尋址可以使用全部的32位通用寄存器作為基址寄存器,還可以加上一個除了ESP的32位通用寄存器作為變址寄存器,變址寄存器還可以允許乘以1,2,4和8作為比例因子。最後還可以在加上一個8位或者32位的偏移量。
3.2 操作數大小的指令字首
每一條處理器指令都可以擁有字首,比如重複字首(REP/REPE/ REPNE)、段超越字首(如 ES:)、總線封鎖字首(LOCK)等。字首是可選的,每個字首的長度是 1 位元組,每條指令可以有 1~4 個字首,或者不使用字首。
為了指明程式的預設運作環境,編譯器提供了僞指令 bits,用于指明其後的指令應該被編譯成 16 位的,還是 32 位的。
3.3 一般指令的擴充
由于 32 位的處理器都擁有 32 位的寄存器和算術邏輯部件,而且同記憶體晶片之間的資料通路至少是 32 位的,是以,所有以寄存器或者記憶體單元為操作數的指令都被擴充,以适應 32 位的算術邏輯操作。而且,這些擴充的操作即使是在 16 位模式下(實模式和 16 位保護模式)也是可用的。
32位處理器的棧允許壓入雙子操作數。特别是,它現在支援立即數壓棧操作。通用寄存器可以不用關鍵字byte,word,dword修飾,記憶體單元一定要關鍵字byte,word,dword修飾,處理器壓入記憶體操作行為和壓入立即數的行為是一樣的。
- 如果壓入一個位元組,必須使用byte來修飾,但是,他執行是,無論在什麼時候,處理器都不會真的壓入一個位元組,會将該位元組操作符号位擴充到高24位,壓棧時使用ESP寄存器,且先将ESP的内容減去4。
- 如果壓入一個字,必須使用word來修飾,壓入的擴充到高16位,且先将ESP的内容減去4。
- 如果要壓入一個雙字立即數,則無論是在16位模式下或者是32位模式下,一定要使用dword,而且棧指針寄存器(SP或者ESP)都要減去4。
- 壓入段寄存器操作比較特殊,在 16 位模式下,先将 SP 的内容減去 2,然後直接壓入段寄存器的内容;在 32 位模式下,要先将段寄存器的内容用零擴充到 32 位,即高 16 位為全零。然後,将 ESP 的内容減去 4,再壓入擴充後的 32 位值。