X86架構

**x86** 泛指一系列基於 Intel 8086 且向下相容的中央處理器指令集架構。最早的 8086 處理器於 1978 年由 Intel 推出，為 16 位元微處理器。

該系列較早期的處理器名稱是以數字來表示 **80x86**。由於以「86」作為結尾，包括 Intel 8086、80186、80286、80386 以及 80486，因此其架構被稱為「x86」。由於數字並不能作為註冊商標，因此 Intel 及其競爭者均在新一代處理器使用可註冊的名稱，如 Pentium，來描述 x86 架構下的處理器產品。現時英特爾將其稱為 IA-32，全名為「**I**ntel **A**rchitecture, **32**-bit」，一般情形下指代 32 位元的架構。

## 歷史

x86 架構於 1978 年推出的 Intel 8086 中央處理器中首度出現，它是從 Intel 8008 處理器中發展而來的，而 8008 則是發展自 Intel 4004 的。8086 在三年後為 IBM PC 所選用，之後 x86 便成為了個人電腦的標準平台，成為了歷來最成功的 CPU 架構。

其他公司也有製造 x86 架構的處理器，計有 Cyrix（現為威盛電子所收購）、NEC 集團、IBM、IDT 以及 Transmeta。Intel 以外最成功的製造商為 AMD，其早先產品 Athlon 系列處理器的市場份額僅次於 Intel Pentium。

8086 是 16 位元處理器；直到 1985 年 32 位元的 80386 的開發，這個架構都維持是 16 位元。接著一系列的處理器表示了 32 位元架構的細微改進，推出了數種的擴充，直到 2003 年 AMD 對於這個架構發展了 64 位元的擴充，並命名為 AMD64。後來英特爾也推出了與之相容的處理器，並命名為 Intel 64。兩者一般被統稱為 **x86-64** 或 **x64**，開創了 x86 的 64 位元時代。

值得注意的是英特爾早在 1990 年代就與惠普合作提出了一種用在安騰系列處理器中的獨立的 64 位元架構，這種架構被稱為 IA-64。IA-64 是一種嶄新的系統，和 x86 架構完全沒有相似性；不應該把它與 **x86-64** 或 **x64** 弄混。

## 設計

x86 架構是重要地可變指令長度的 CISC（複雜指令集電腦，**C**omplex **I**nstruction **S**et **C**omputer）。字組（word, 4 位元組）長度的記憶體存取允許不對齊記憶體位址，字組是以低位位元組在前的順序儲存在記憶體中。向後相容性及 Intel 量產製程經常領先業界一直都是在 x86 架構的發展背後一股驅動力量（設計的需要決定了這項因素而常常導致批評，尤其是來自對手處理器的擁護者和理論界，他們對於一個被廣泛認為是落後設計的架構的持續成功感到不解）。但在較新的微架構中，x86 處理器會將常用的 x86 指令盡全力以硬體線路執行，不常用者則轉換為更像 RISC 的微指令再予執行，從而獲得可與 RISC 比擬的超純量效能，而仍然保持向下相容。x86 架構的處理器一共有四種執行模式，分別是真實模式，保護模式，系統管理模式以及虛擬 V86 模式。

在這篇簡短的文章中出現的指令和暫存器助憶符號的名稱，都在 Intel 檔案中有所指定以及使用在 Intel 組譯器（Assembler）中（和相容的，比如微軟的 MASM、Borland 的 TASM、CAD-UL 的 as386 等等）。一個以 Intel 語法指定的指令 "mov al, 30h" 與 AT&T 語法的 "movb $0x30, % al" 相當，都是會被轉譯為兩個位元組的機器碼 "B0 30"（十六進制）。你可以發現在這段程式中的 "mov" 或 "al"，都是原來的 Intel 助憶符號。如果我們想要的話，我們可以寫一個組譯器由程式碼 move immediate byte hexadecimally encoded 30 into low half of the first register（移動立即值位元十六進制編碼 30 到第一個暫存器的低半部位），來產生相同的機器碼。然而，傳統上組譯器（Assembler）一直使用 Intel 的助憶符號。

x86 組合語言會在 x86 組合語言文章中有更詳細的討論。

### 運作模式

#### 真實模式

在真實模式下，記憶體的存取是被區段開來。為了得到最後 20 位元的記憶體位址，要將區段的位址往左移動 4 位元，並且加上偏移的位址。因此，真實模式下總共可以定址的空間是 220 位元組，或者是 1MB，於 1979 年是相當讓人印象深刻的象徵。在真實模式下有兩種定址模式：near 和 far。在 far 模式，區段跟偏移都需要被指定；在 near 模式，只需要偏移模式被指定，而記憶體區段是由適當的區段暫存器獲得。以資料而言是使用 DS 暫存器，程式碼是 CS 暫存器，堆疊是 SS 暫存器。舉個例子，如果 DS 是 A000h 且 SI 是 5677h，DS:SI 會指向記憶體的絕對位址 DS × 16 + SI = A5677h

在這種架構下，兩對不同的區段／偏移可以指向一個相同的絕對位址。因此如果 DS 是 A111h 且 SI 是 4567h，DS:SI 會指向跟上一段相同的 A5677h。除了異值同址重複性之外，這種架構無法同時一次擁有 4 個以上的區段。此外，CS、DS 和 SS 是為了程式正確功能而必須的，因此僅僅只有 ES 可以被用來指向其他的地方。這種模式原本是為了與 Intel 8085 相容，導致程式設計師永無止盡的痛苦。

除了以上所說的，8086 也擁有 16-bit 的 32K（其變種 Intel 8088 是 8-bit 的 64K）輸入輸出空間，以及一個由硬體支援的 64K（一個區段）記憶體堆疊。只有 words（2 位元組）可以被推入到堆疊中。堆疊是由記憶體的上端往下成長，他的底端是由 SS:SP 指向。有 256 個中斷，可以由硬體或是軟體同時組成。中斷是可以串連在一起，使用堆疊來儲存返回被中斷的程式位址。

#### 16 位元保護模式

Intel 80286 可以在不改變任何東西下，支援 8086 的真實模式 16 位元軟體，然而它也支援額外的工作模式稱為保護模式，可以將可定址的實體記憶體擴充到 16MB，可定址的虛擬記憶體最大到 1GB。這是使用節區暫存器來儲存在節區表格中的索引值。處理器中有兩個這樣的表格，分別為 GDT 和 LDT，每一個可以儲存最多 8192 個節區的描述子，每一個節區可以給予最大到 64KB 的記憶體存取。節區表格提供一個 24 位元的基底位址（base address），可以用此基底位址增加想要的偏移量來創造出一個絕對位址。此外，每一個節區可以被賦予四種權限等級中的一種（稱為 "rings"）。

儘管這個推出的功能是一項進步，但是他們並沒有被廣泛地使用，因為保護模式的作業系統無法執行當時的真實模式軟體。這樣的能力只有在隨後 80386 處理器的虛擬 86 模式中出現。

在同時，作業系統比如 OS/2 嘗試使用類似桌球的方法，讓處理器在保護和真實模式間切換。這樣都會讓電腦變慢且不安全，像是在真實模式下的程式可以輕易地使電腦當機。OS/2 也定義了限制性的程式設計規則允許 "Family API" 或 "bound" 程式可以在真實模式或保護模式下執行。然而這是給原本為保護模式下設計的程式有關，反之則不然。保護模式程式並不支援節區選擇子和實體記憶體之間的關係。有時候會錯誤地相信在 16 位元保護模式下執行真實模式的程式，導致 IBM 必須選擇使用 Intel 保留給 BIOS 的中斷呼叫。事實上這類的程式使用任意的選擇子數值和使用在上面提到的「節區運算」的方式有關。

這個問題也在 Windows 3.x 上出現。這個推出版本想要在 16 位元保護模式下執行程式，而先前的版本只能在真實模式下執行。理論上，如果 Windows 1.x 或 2.x 程式是寫得「適當」且避免使用節區運算的方式，它就有可能在真實和保護模式兩者下執行。Windows 程式一般來說都會避免節區運算，這是因為 Windows 實作出軟體的虛擬記憶體方式，及當程式不執行時候，搬移記憶體中的程式碼和資料，所以操作絕對位址的方式是很危險的；當程式不執行時，被認為要保持記憶體區塊的「handles」，這樣的 handles 已經非常相當於保護模式的選擇子。在保護模式下的 Windows 3.0 執行一個舊的程式，會觸發一個警告對話盒，建議在真實模式下執行 Windows（推測還是仍然可以使用擴充記憶體，可能是在 80386 機器用 EMM386 類比，因此它並不被局限於 640KB）或是從廠商那更新到新的版本。好的行為之程式可能可以使用特別的工具來避免這樣的對話盒。不可能有些 GUI 程式在 16 位元保護模式下執行，且其它 GUI 程式在真實模式執行，可能是因為這會需要兩個分開的環境且會依於前面所提到的處理器在兩個模式間的桌球效應。從 Windows 3.1 版開始，真實模式就消失了。

#### 32 位元保護模式

Intel 80386 推出後，也許是到目前為止 x86 架構的最大躍進。除了需要值得注意的 Intel 80386SX 是 32 位元架構但僅只有 24 位元定址（和 16 位元資料匯流排）。除此之外其他架構都是 32 位元 - 所有的暫存器、指令集、輸出輸入空間和記憶體定址。為了能夠在後者所說的功能工作，要使用 32 位元擴充的保護模式。然而不像 286，386 所有的區段可以使用 32 位元的偏移量，即使記憶體空間有使用區段，但也允許應用程式存取超過 4GB 空間而不需要區段的分隔。此外，32 位元保護模式提供分頁的支援，是一種讓虛擬記憶體得以實現的機制。

沒有新的通用暫存器被加入。所有 16 位元的暫存器除了區段暫存器外都擴充為 32 位元。Intel 在暫存器的助記符號上加入「E」來表示（因此擴充的 AX 變成 EAX，SI 變成 ESI，依此類推）。因為有更多的暫存器數量、指令、和運算單元，因此機器碼的格式也被擴充。為了提供與先前的架構相容，包含執行碼的區段可以被標示為 16 或是 32 位元的指令集。此外，特殊的前置符號也可以用來在 16 位元的區段包含 32 位元的指令碼，反之亦然。

分頁跟區段的記憶體存取是為了支援現在多工作業系統所必須要的。Linux、386BSD、Windows NT 和 Windows 95 都是一開始為 386 所發展，因為它是第一顆提供可靠地程式分離記憶體空間的支援（每個程式擁有自己的定址空間）以及可以在必要的情況下打斷他們程式的執行（使用 ring，一種 x86 保護模式下權力分級的名稱）。這種 386 的基本架構變成未來所有 x86 系列發展的基礎。

Intel 80386 數學輔助運算處理器也在整合到這個 CPU 之後的 x86 系列中，也就是 Intel 80486。新的 FPU 可以幫助浮點數運算，對於科學計算和圖形設計是非常重要。

#### 系統管理模式

Intel 首次在 80386SL 將系統管理模式引入 x86 體系結構。

#### 虛擬 86 模式

### 功能擴充

#### MMX

1996 年 Intel 的 MMX（AMD 認為這是矩陣數學擴充 Matrix Math Extensions 的縮寫，但大多數時候都被當成 Multi-Media Extension，而 Intel 從來沒有官方宣布過詞源）技術出現。儘管這項新的科技得到廣泛宣傳，但它的精髓是非常簡單的：MMX 定義了八個 64 位元 SIMD 暫存器，與 Intel Pentium 處理器的 FPU 堆疊有相重疊。不幸的是，這些指令無法非常簡單地對應到由原來 C 編譯器所產生的指令碼中。MMX 也只局限於整數的運算。這項技術的缺點導致 MMX 在它早期的存在有輕微的影響。現今，MMX 通常是用在某些 2D 影片應用程式中。

#### 3DNow!

1997 年 AMD 推出 3DNow!，是對於 MMX 的 SIMD 的浮點指令增強（針對相同的 MMX 暫存器）。儘管這些也沒有解決編譯器的難題，但這項技術的推出符合了 PC 上的 3D 休閒娛樂應用程式之崛起。3D 遊戲開發者和 3D 繪圖硬體製造商在 AMD 的 AMD K6 和 Athlon 系列處理器上，使用 3DNow! 來幫助增加他們的效能。微軟後來也在其開發的 Direct X7.0 中加入針對 3DNow! 的最佳化，使當時的 Athlon 處理器在 3D 遊戲效能上首次全面超過對手英特爾的 Pentium 3 處理器。

#### SSE

在 1999 年 Intel 推出 SSE 指令集，增加了八個新的 128-bit 暫存器（不跟其他的暫存器重疊使用）。這些指令類似於 AMD 的 3DNow!，主要是增加浮點數運算的 SIMD 指令。

#### SSE2

2001 年英特爾推出 SSE2 指令集，增加了：

* 完整地補充了整數指令（與 MMX 相似）到原來的 SSE 暫存器。
* 64 位元的 SIMD 浮點運算指令到原來的 SSE 暫存器。

第一個的增加導致 MMX 幾乎是過時可以捨棄的，第二個則允許這些指令可以讓傳統的編譯器現實地產生。

#### SSE3

於 2004 年隨著 Pentium 4 處理器的改版 **Prescott** 核心推出。SSE3 增加特定的記憶體和 thread-handling 指令來提升 Intel 超執行緒的效能，在科學計算方面也有增強。

#### SSE4

2007 年 1 月，Intel 公開發表使用其 45 奈米製程 "Penryn"晶片家族的 PC 和伺服器。"Penryn" 是這一系列依據英代爾 Core 微架構之筆記型電腦、桌上型電腦和伺服器晶片家族的代號，首次正式發布時共有 16 款處理器，除了一款 Intel Core 2 Extreme QX9650 是針對普通桌上型電腦市場外，其餘的雙核 Xeon 5200 系列和四核 5400 系列都是伺服器處理器。基本上 Penryn 是繼 Merom 之後的縮小版 Core 2 Duo，再加上 47 條新的 SSE4 指令集等額外配備。SSE4 指令集之首次發表時間為 2006 年 9 月的英特爾開發者論壇（IDF，Intel Developer Forum）。

另外，x86 處理器製造廠商 AMD 也在該公司 K10 架構的 Phenom 處理器中，加入 4 條新的 SSE4A 指令集。注意，SSE4 與 SSE4A 無法彼此相容。

#### AVX

#### FMA

#### AES

#### SHA

### 定址模式

定址模式在 16-bit 的 x86 處理器：

　
: ${\begin{Bmatrix}CS:\\DS:\\SS:\\ES:\end{Bmatrix}}{\begin{bmatrix}{\begin{Bmatrix}BX\\BP\end{Bmatrix}}\end{bmatrix}}+{\begin{bmatrix}{\begin{Bmatrix}SI\\DI\end{Bmatrix}}\end{bmatrix}}+{\rm {[displacement]}}$

32-bit 定址模式在 32-bit 或 64-bit 的 x86 處理器：

　
: ${\begin{Bmatrix}CS:\\DS:\\SS:\\ES:\\FS:\\GS:\end{Bmatrix}}{\begin{bmatrix}{\begin{Bmatrix}EAX\\EBX\\ECX\\EDX\\ESP\\EBP\\ESI\\EDI\end{Bmatrix}}\end{bmatrix}}+{\begin{bmatrix}{\begin{Bmatrix}EAX\\EBX\\ECX\\EDX\\EBP\\ESI\\EDI\end{Bmatrix}}*{\begin{Bmatrix}1\\2\\4\\8\end{Bmatrix}}\end{bmatrix}}+{\rm {[displacement]}}$

64-bit 定址模式在 64-bit 的 x86 處理器：

　
: ${\begin{Bmatrix}{\begin{Bmatrix}FS:\\GS:\end{Bmatrix}}{\begin{bmatrix}{\rm {general\;register}}\end{bmatrix}}+{\begin{bmatrix}{\rm {general\;register}}*{\begin{Bmatrix}1\\2\\4\\8\end{Bmatrix}}\end{bmatrix}}\\\\RIP\end{Bmatrix}}+{\rm {[displacement]}}$

x86 組譯指令 lea，是 Load Effective Address 的縮寫，其優勢是：

* LEA 指令具有單時鐘周期，執行效率很高。
* 是 CPU 位址生成單元參與運算的，而不是 ALU 參與運算的，所以在管線上不會與上下文的算術邏輯指令產生流水相關
* INTEL 指令集中不存在很多 RISC 機器所具有的三運算元算術運算指令，比如像 ARM 的 "add r0,r1,r2"，而 LEA 指令恰好提供了同樣的功能，以類比「三元算術邏輯指令」。例如：lea ebx ,[eax+edx]
* 在組合語言程式設計中，在需要取得一個變數位址時，使用 lea 是很方便的。而 mov 指令則常常出錯，因為在微軟 MASM 組譯語法中，label 和 variable 是不同的：addr 不可前向參照，offset 則能；addr 可以處理局部變數而 offset 則不能。

### x86 暫存器

#### 16 位元

自 Intel 8086 和 8088 起，有 14 個 16 位元暫存器。其中四個（AX, BX, CX, DX）是通用目的（儘管每個暫存器都有附加目的；舉個例子：只有 CX 可以被用來當作 _loop_（迴圈）指令的計數器。）每個暫存器可以被當成兩個分開的位元組存取（因此 BX 的高位元可以被當成 BH，低位元則可以當成 BL）。除了這些暫存器，還有四個區段暫存器（CS、DS、SS、ES）。他們用來產生記憶體的絕對位址。還有兩個指標暫存器（SP 是指向堆疊的底部，BP 可以用來指向堆疊或記憶體的其它地方）。兩個指標暫存器（SI 和 DI）可以用來指向陣列的內部。最後，有旗標暫存器（包含狀態旗標比如進位、溢位、結果為零，等等）。以及 IP 是用來指向目前執行指令的位址。

#### 32 位元

自 Intel 80386 起，四個通用暫存器（EAX, EBX, ECX, EDX），它們較低的 16 位元分別與原本 16 位元的通用暫存器（AX, BX, CX, DX）重疊共享。指標暫存器（EIP, EBP, ESP, ESI, EDI）。區段暫存器除了原本的（CS、DS、SS、ES），另外新增（FS、GS），但是區段暫存器在 32 位元模式下改做為記憶體區塊的選擇子暫存器。旗標暫存器被擴展為 32 位元，較低的 16 位元與原本在 16 位元下的旗標暫存器重疊共享。

#### 64 位元

MMX 暫存器（MM0～MM7），它們分別與浮點運算器〈FP0～FP7〉相重疊，所以 MMX 與浮點運算不可同時使用，必須透過切換選擇要使用哪一種。

##### AMD64

英特爾原本已經決定在 64 位元的世代推出新的架構 IA-64 技術的 Itanium 處理器產品線來接替取代 x86，但它與 x86 的軟體天生不相容，因此藉以各種形式來執行 x86 的軟體，不過，效率十分低下，加之處理器本身和軟體移植的成本難以控制，因此這個計畫最終告吹。

AMD 自行把 32 位元 x86（或稱為 IA-32）拓展為 64 位元，並命名為 x86-64 或 Hammer 架構，而後更名為 AMD64 架構，並曾禁止使用之前的名字來稱呼這一架構。以這個技術為基礎的第一個產品是單核心的 Opteron 和 Athlon 64 處理器家族。由於 AMD 的 64 位元處理器產品線首先進入市場，且微軟也不願意為英代爾代號為 Yamhill 的 64 位元版 x86 處理器開發第三個不同的 64 位元作業系統，英代爾被迫採納 AMD64 架構且增加某些新的擴充到他們自己的產品，命名為 EM64T 架構（顯然他們不想承認這些指令集是來自它的主要對手），EM64T 後來被英代爾正式更名為 Intel 64。

這個架構也被稱為 64 位元拓展架構，即 x64，譬如四個通用暫存器（RAX, RBX, RCX, RDX）是由 32 位元的（EAX, EBX, ECX, EDX）64 位元擴展而來，相應的還有 指標暫存器（RIP, RBP, RSP, RSI, RDI），以及增加八個通用暫存器（R8～R15）等等。 這些資源只可在 x64 處理器的 64 位元模式下使用，在用來支援 x86 軟體的遺留模式和相容模式中是不可見的。

#### 128 位元

自 SSE 起，SIMD 的暫存器 XMM0 - XMM15.

#### 256 位元

SIMD registers YMM0 - YMM15.

#### 512 位元

SIMD registers ZMM0 - ZMM31.

#### 暫存器結構

Note: The ?PL registers are only available in 64-bit mode.

Note: The ?IL registers are only available in 64-bit mode.

 

### 虛擬化

Intel CPU 的 x86 虛擬化技術有 VT-x、VT-d 等。AMD CPU 的 x86 虛擬化技術有 AMD-V 等。

## x86 指令格式

x86 與 x86-64 指令集的指令的格式為：

### 指令字首

分為 4 組，每組用 1 個位元組編碼。每組在指令中至多指定 1 個字首值。4 組的順序可以任意。

* 第 1 組鎖與重複（Lock and repeat）
  * 鎖（LOCK）編碼為：F0H。用於互斥存取共享記憶體的操作。
  * 非零時重複（REPNE/REPNZ）編碼為：F2H。用於字串操作指令。
  * 為零時重複（REP/REPE/REPZ）編碼為：F3H。用於字串操作指令。
* 第 2 組
  * 段覆蓋（Segment override）：CS、SS、DS、ES、FS、GS 的段覆蓋字首的編碼分別是 2EH、36H、3EH、26H、64H、65H.
  * 分支提示（Branch hints），用於條件分支指令 J_cc_。提示分支不發生編碼為 2EH；提示分支發生編碼為 3EH。
* 第 3 組運算元長度覆蓋（Operand-size override）編碼為 66H。用於在 16 位元與 32 位元運算元切換。
* 第 4 組位址長度覆蓋（Address-size override）編碼為 67H. 用於在 16 位元與 32 位元位址切換。

### 指令碼

長度為 1、2 或 3 位元組，此外 ModR/M 中還可能有 3 位。對於雙位元組指令碼或三位元組指令碼，其中的第 1 個位元組為 0FH，用於與指令字首區分。

### ModR/M 與 SIB

許多指令的記憶體運算元需要使用 ModR/M 位元組作為定址模式說明符。其中的 mod 與 r/m 組合，共有 32 個值，表示 8 個暫存器與 24 種定址模式。reg/opcode 表示暫存器號或者額外的 3 位指令碼，其具體含義依賴基本指令碼。Mod 與 R/M 的 5 位表示的**第一運算元**（源與目的運算元中定址方式更複雜的那個運算元，指令碼中的「方向位」direction bit (d) 給出源或目的運算元哪個是第一運算元）的定址方式如下：

某些 ModR/M 位元組表示的尋找模式，需要 SIB 位元組來補充定址方式。scale 表示比例係數；index 表示變址暫存器號；base 表示基址暫存器號。使用 scale 與 index 的 5 位定義比例變址暫存器如下：

3 位 base 表示的基址暫存器號，定義如下：

在組譯程式設計中，一般把第 1 運算元的定址方式總結為如下 8 種：

綜合指令格式中的 ModR/M 與 SIB 兩個位元組的語意規定，指令的第 1 運算元的定址方式可總結為 4 種物理實現：

* 立即數：表示在指令的「立即數」部分。包括了直接定址，即立即數作為記憶體的位址。
* 暫存器運算元：Mod 為 11B，根據 R/B 部分的值、指令碼、運算元長度屬性，確定具體的暫存器號。
* 基址相對定址：即 [Reg+disp8 或 disp32]。包括了暫存器間接定址。這種情況計算第 1 運算元位址時使用了 1 個暫存器。
* 基址加比例變址的相對定址：即 [BaseReg+IndexReg\*scale+disp8 或 disp32]。這種情況計算第 1 運算元位址時使用了 2 個暫存器。

### 位移與立即數

某些定址方式需要給出位移值。有些指令需要給出立即數作為運算元。

## 生產商

目前仍在設計、生產並販賣 x86 處理器的公司包括：

* 英特爾（Intel）
* 超微（AMD）
* 瞻營全電子（DMP Electronics INC.）
* 威盛電子（VIA）
* 兆芯

曾經設計、生產並販賣 x86 處理器，但現已退出 x86 處理器市場的公司包括：

* Chips and Technologies
* Cyrix（被威盛電子收購）
* IBM
* IDT
* 國家半導體（NS，National Semiconductor）
* 日本電氣（NEC）
* NexGen（被超微收購）
* Rise Technology（被矽統科技收購）
* 意法半導體
* 矽統科技（SiS）
* 德州儀器（Texas Instruments）
* 全美達（Transmeta）
* 聯華電子（UMC）
* Montalvo

## 參考文獻

## 參見