共用方式為


x86 架構

Intel x86 處理器使用複雜的指令集電腦 (CISC) 架構,這表示有少量的特殊用途緩存器,而不是大量的一般用途緩存器。 這也表示複雜的特殊用途指示將佔主導地位。

x86 處理器會追蹤其遺產,至少可以追溯到 8 位 Intel 8080 處理器。 x86 指令集中的許多特點是由於與該處理器的回溯相容性(以及其 Zilog Z-80 變體)。

Microsoft Win32 使用 32 位平面模式中的 x86 處理器。 本檔僅著重於一般模式。

寄存 器

x86 架構包含下列不具特殊許可權的整數緩存器。

eax

累計

ebx

基底快取器

ecx

計數器快取器

edx

數據快取器 - 可用於 I/O 連接埠存取和算術函式

esi

源索引緩存器

edi

目的地索引緩存器

ebp

基底指標緩存器

esp

堆疊指標

所有整數緩存器都是32位。 不過,其中許多都有16位或8位子登錄。

斧頭

低 16 位 eax

bx

低16位 ebx

cx

低16位 的ecx

dx

低16位 edx

低16位 esi

低 16 位 edi

bp

低16位 ebp

sp

低16位 esp

低8位 的eax

高8位的斧頭

bl

低8位 ebx

bh

高8位 bx

cl

低8位 ecx

ch

高8位 cx

dl

低 8 位 edx

dh

高8位 dx

在子登錄上操作只會影響子登錄,而且子登錄外部的所有元件都不會受到影響。 例如,儲存至 ax 快取器會讓 eax 快取器的高 16 位保持不變。

使用 時?(評估表達式) 命令,快取器應前面加上 「at」 符號 ( @ 。 例如,您應該使用 ? @ax 而不是 ? ax。 這可確保調試程式會將 ax 辨識為緩存器,而不是符號。

不過,r (Registers) 命令中 不需要 (@) 。 例如, r ax=5 一律會正確解譯。

另外兩個緩存器對於處理器的目前狀態很重要。

eip

指令指標

flags

flags

指令指標是所執行指令的位址。

旗標快取器是單一位旗標的集合。 許多指示會改變旗標來描述指示的結果。 然後,這些旗標可以透過條件式跳躍指示進行測試。 如需詳細資訊,請參閱 x86 旗標

呼叫慣例

x86 架構有數個不同的呼叫慣例。 幸運的是,它們都遵循相同的緩存器保留和函式傳回規則:

  • 函式必須保留所有緩存器,但eaxecx和edx除外,這些緩存器可以跨函數調用進行變更,而 esp 必須根據呼叫慣例進行更新。

  • 如果結果為 32 位或更小,則 eax 快取器會收到函式傳回值。 如果結果為 64 位,則結果會儲存在 edx:eax 配對中

以下是 x86 架構上所使用的呼叫慣例清單:

  • Win32 (__stdcall

    函式參數會在堆疊上傳遞、由右至左推入,而被呼叫者會清除堆疊。

  • 原生C++方法呼叫 (也稱為 thiscall)

    函式參數會在堆疊上傳遞,由右至左推入,“this” 指標會傳入 ecx 緩存器中,而被呼叫者會清除堆棧。

  • COM (__stdcall 用於C++方法呼叫)

    函式參數會在堆疊上傳遞,由右至左推入,然後在堆棧上推送“this” 指標,然後呼叫 函式。 被呼叫端會清除堆疊。

  • __fastcall

    前兩個 DWORD 或較小的自變數會在 ecx 和 edx 快取器中傳遞。 其餘參數會在堆疊上傳遞,由右至左推送。 被呼叫端會清除堆疊。

  • __cdecl

    函式參數會在堆疊上傳遞、由右至左推送,而呼叫端會清除堆疊。 __cdecl呼叫慣例會用於具有可變長度參數的所有函式。

調試程序顯示緩存器和旗標

以下是除錯程式快取器顯示範例:

eax=00000000 ebx=008b6f00 ecx=01010101 edx=ffffffff esi=00000000 edi=00465000
eip=77f9d022 esp=05cffc48 ebp=05cffc54 iopl=0         nv up ei ng nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000286

在使用者模式偵錯中,您可以忽略 iopl 和調試程序顯示的完整最後一行。

x86 旗標

在上述範例中,第二行結尾的兩個字母代碼是 旗標。 這些是單一位緩存器,而且有多種用途。

下表列出 x86 旗標:

標幟程序代碼 旗標名稱 旗標狀態 描述
溢位旗標 0 1 nvov 無溢位 - 溢位
df 方向旗標 0 1 updn 向上方向 - 向下方向
if 中斷旗標 0 1 diei 中斷已停用 - 已啟用插斷
sf 簽署旗標 0 1 plng 正數 (或零) - 負數
zf 零旗標 0 1 nzzr 非零 - 零
af 輔助攜帶旗標 0 1 naac 無輔助攜帶 - 輔助攜帶
pf 同位旗標 0 1 pepo 同位奇數 - 同位偶數
cf 攜帶旗標 0 1 nccy 無攜帶 - 攜帶
tf 陷阱旗標 如果 tf 等於 1,處理器會在執行一個指令之後引發STATUS_SINGLE_STEP例外狀況。 調試程式會使用此旗標來實作單一步驟追蹤。 它不應該由其他應用程式使用。
iopl I/O 許可權等級 I/O 許可權等級 這是兩位整數,其值介於零和 3 之間。 操作系統會使用它來控制硬體的存取。 應用程式不應該使用它。

當緩存器顯示為 [調試程式命令] 視窗中某些命令的結果時,它是 顯示的旗標狀態 。 不過,如果您想要使用 r (Registers) 命令變更旗標,您應該透過旗標程式代碼來參考它。

在 WinDbg 的 [快取器] 視窗中,旗標程式代碼是用來檢視或改變旗標。 不支援旗標狀態。

以下是範例。 在上述緩存器顯示中,旗標狀態 ng 隨即出現。 這表示正負號旗標目前設定為 1。 若要變更此動作,請使用下列命令:

r sf=0

這會將符號旗標設定為零。 如果您執行另一個緩存器顯示, ng 狀態代碼將不會顯示。 相反地 ,將會顯示 pl 狀態代碼。

[標誌旗標]、[零旗標] 和 [攜帶旗標] 是最常用的旗標。

條件

條件描述一或多個旗標的狀態。 x86 上的所有條件式作業都會以條件表示。

組合器會使用一或兩個字母縮寫來表示條件。 條件可以透過多個縮寫來表示。 例如,AE (“above 或 equal”) 與 NB 相同(“不低於”)。 下表列出一些常見條件及其意義。

條件名稱 旗標 意義

Z

ZF=1

最後一個作業的結果為零。

紐西蘭

ZF=0

上次作業的結果不是零。

C

CF=1

上次作業需要攜帶或借用。 (對於不帶正負號的整數,這表示溢位。

NC

CF=0

上次作業不需要攜帶或借用。 (對於不帶正負號的整數,這表示溢位。

S

SF=1

最後一個作業的結果已設定高位。

NS

SF=0

最後一個作業的結果具有較高的位清除。

O

OF=1

當被視為帶正負號的整數作業時,最後一個作業會造成溢位或下溢。

OF=0

當被視為帶正負號的整數作業時,最後一個作業不會造成溢位或下溢。

條件也可以用來比較兩個值。 cmp 指令會比較其兩個操作數,然後設定旗標,就像從另一個操作數減去一個操作數一樣。 下列條件可用來檢查 cmp value1value2 的結果

條件名稱 旗標 CMP 作業之後的意義。

E

ZF=1

value1 == value2

NE

ZF=0

value1 != value2

GE NL

SF=OF

value1>= value2。 值會被視為帶正負號的整數。

LE NG

ZF=1 或 SF!=OF

value1<= value2。 值會被視為帶正負號的整數。

G NLE

ZF=0 和 SF=OF

value1>value2。 值會被視為帶正負號的整數。

L NGE

SF!=OF

value1<value2。 值會被視為帶正負號的整數。

AE NB

CF=0

value1>= value2。 值會被視為不帶正負號的整數。

BE NA

CF=1 或 ZF=1

value1<= value2。 值會被視為不帶正負號的整數。

A NBE

CF=0 和 ZF=0

value1>value2。 值會被視為不帶正負號的整數。

B NAE

CF=1

value1<value2。 值會被視為不帶正負號的整數。

條件通常用於處理 cmp測試指令的結果。 例如,

cmp eax, 5
jz equal

藉由計算表達式 (eax - 5) 和根據結果設定旗標,來比較 eax 快取器與數位 5。 如果減法的結果為零,則會 設定 zr 旗標,而 jz 條件會是 true,因此會採用跳躍。

數據類型

  • 位元組:8 位

  • word:16 位

  • dword:32 位

  • qword:64 位(包括浮點雙精度浮點數)

  • tword:80 位(包括浮點擴充雙精度浮點數)

  • oword:128 位

表示法

下表指出用來描述彙編語言指示的表示法。

標記法 意義

rr1r2...

暫存器

m

記憶體位址 (如需詳細資訊,請參閱後續尋址模式一節。

#n

即時常數

r/m

註冊或記憶體

r/#n

緩存器或立即常數

r/m/#n

緩存器、記憶體或即時常數

cc

上述 [條件] 區段中所列的條件代碼。

T

“B”、“W” 或 “D” (位元組、單字或 dword)

accT

大小 T 累積器: 如果 T = “B”, ax if T = “W”,或 eax if T = “D”

尋址模式

有數種不同的尋址模式,但它們都採用 T ptr [expr] 格式,其中 T 是一些數據類型(請參閱先前的數據類型一節),expr 是涉及常數和緩存器的一些表達式。

大部分模式的表示法可以推斷,而不需要太多困難。 例如,BYTE PTR [esi+edx*8+3] 表示「取得 esi 快存器的值,將其新增至 edx 快取器的值八倍,再新增三個,然後在產生的位址存取位元節」。

流水線

Pentium 是雙重問題,這表示它可以在一個時鐘刻度中執行最多兩個動作。 然而,當它能夠同時執行兩個動作(稱為 配對)的規則是非常複雜的。

因為 x86 是 CISC 處理器,因此您不必擔心跳躍延遲插槽。

同步處理記憶體存取

載入、修改和儲存指示可以接收 鎖定 前置詞,其會修改指示,如下所示:

  1. 發出指令之前,CPU 會排清所有擱置中的記憶體作業,以確保一致性。 系統會放棄所有數據預先擷取。

  2. 發出指示時,CPU 將具有總線的獨佔存取權。 這可確保載入/修改/存放區作業的不可部分完成性。

每當 xchg 指令以記憶體交換值時,就會自動遵守先前的規則。

所有其他指示預設為非鎖定。

跳躍預測

預計會採用無條件跳躍。

條件式跳躍會根據其上次執行時間而定,預測會採用或未採用。 錄製跳躍歷程記錄的快取大小有限。

如果 CPU 沒有記錄條件式跳躍是在上次執行時是否採用條件式跳躍,它會預測採用的回溯條件式跳躍,而前向條件式跳躍則不採用。

對準

x86 處理器會在效能降低時自動更正未對齊的記憶體存取。 不會引發例外狀況。

如果位址是物件大小的整數倍數,則會將記憶體取視為對齊。 例如,所有 BYTE 存取都會對齊(所有專案都是 1 的整數倍數)、連位址的 WORD 存取都對齊,而 DWORD 位址必須是 4 的倍數才能對齊。

鎖定前置詞不應該用於未對齊的記憶體存取。