跳轉到內容

MS-DOS 7 下的系統程式設計入門 / 偵錯程式的組合語言命令

50% developed
來自華夏公益教科書,開放的書籍,開放的世界


Clipboard

待辦事項


第 7 章 偵錯程式的組合語言命令

過時的 DEBUG.EXE 的命令值得花時間去熟悉嗎?這個問題讓人回憶起過去。半個多世紀以前,計算機實現了對多個終端的時間共享。每個終端用來啟動一個獨立的程式,計算機的記憶體必須在這些程式之間分配。為了宣告記憶體需求,引入了程式的檔案頭。從那時起,那些不能自動編譯檔案頭的彙編器就被認為是過時的。正是這種態度被 DEBUG.EXE 所繼承。

更復雜的彙編器會自動編譯檔案頭和跳轉目標地址。然而,這種極大的便利也有其負面影響:對地址空間和段暫存器的操作自由度會丟失。應用程式不會因此而受到影響,但對於研究和系統任務來說,這可能是一個相當大的障礙。正是因為這個原因,MASM 彙編器無法編譯本書第 9.06、9.08、9.10 部分中展示的程式示例。類似的不可接受的程式碼片段在 BIOS 程式碼中甚至在 Windows XP 作業系統的載入模組中都有發現。無法透過 MASM 的程式碼可以用 DEBUG.EXE 編譯。

為了直接瞭解程式設計,應該首選最簡單的彙編工具。除了簡單之外,DEBUG.EXE 還擁有一些優點,使其成為本書最合適的工具

  • 首先,它最清楚地展示了機器程式碼的使用;
  • 其次,它結合了彙編和除錯功能;
  • 第三,它提供對硬體和作業系統結構的訪問;
  • 第四,它能夠與使用者互動。

雖然 DEBUG.EXE 可以將任何機器程式碼傳送到 CPU 執行,但所有 x86 機器指令的種類非常多,可能會讓新手感到困惑。因此,第 7 章介紹了一個易於理解的選擇:DEBUG.EXE 版本的命令集,該版本隨 Windows 95/98 釋出。這些命令構成所有現代 CPU 命令的一個子集,但這個子集扮演著非常重要的角色。它包含了使用最廣泛的命令。目前大約 96% 的活躍計算機都“理解”這些命令。大多數現代計算機的機器程式碼相容性就是基於這裡介紹的子集。

現代 CPU 中更新的命令可能有所不同。然而,一些這樣的命令得到了廣泛認可,並且對於最佳化現代計算機是必要的。作為例外,第 7 章包括對幾個 DEBUG.EXE “不認識”的命令的描述。描述闡明瞭以機器程式碼形式使用這些命令的方法。在任何情況下,這都不會成為用這些程式碼除錯程式的障礙。

DEBUG.EXE 接受組合語言命令,當它切換到將組合語言翻譯成可執行機器程式碼時(6.05-02)。雖然每種組合語言方言都有其特點,但組合語言命令的總體組成是通用的。一行以命令名稱開頭,後面跟著運算元。某些命令中的運算元必須以運算元型別的標記開頭。如果一個組合語言命令包含多個運算元,則這些運算元之間用逗號隔開。生成任何數字結果的命令會將其第一個(最左邊的)運算元覆蓋為該結果。該暫存器(或記憶體單元)的先前內容將丟失。在文章 9.05、9.06、9.08、9.10 中展示了包含將 DEBUG.EXE 切換到組合語言翻譯以及大量組合語言命令的命令檔案示例。

由於備選命令規範太多,第 7 章中的一些變數和運算元被賦予易於識別的固定小寫字母識別符號,在所有示例中都相同。下表顯示並解釋了這些識別符號的允許替換以及 DEBUG 組合語言方言中使用的其他一些術語。

表 7.00
識別符號 解釋和允許的替代項
bl 任何 8 位暫存器:AL、CL、DL、BL、AH、CH、DH、BH。
bx 任何 16 位暫存器:AX、CX、DX、BX、SP、BP、SI、DI。
ss 任何段暫存器:CS、DS、ES、SS。
ST 協處理器的堆疊頂暫存器 ST(0) [注 1]
ST(0-7) 任何協處理器的堆疊暫存器,從 ST(0) 到 ST(7)
far 4 位元組地址(段 + 偏移量)的標記。
byte 一個位元組運算元的 ptr 標記(ptr = “指標”)
word 2 位元組運算元(一個字)的 ptr 標記
dword 4 位元組運算元(一個雙字)的 ptr 標記
qword 8 位元組運算元(一個四字)的 ptr 標記
tbyte 10 位元組運算元的 ptr 標記
f 任何從 “0” 到 “F” 的十六進位制數字
±7f 任何從 –7Fh 到 +7Fh 的帶符號十六進位制數
ff 任何從 00h 到 FFh 的十六進位制數
ffff 任何從 0000h 到 FFFFh 的十六進位制數
aaaa 用於 “短” 跳轉的地址 [注 2]
[bp+si+ffff] 方括號中的表示式表示對記憶體中的運算元定址。相應記憶體單元的偏移量需要透過計算給定的表示式來找到。允許兩種表示式的形式。 [注 3][注 4]
註釋
  1. ^ 協處理器的堆疊頂暫存器通常稱為 ST(0),但在一些位置,如果不能定址其他暫存器,則 DEBUG.EXE 接受簡寫名稱 ST。
  2. ^ 對於具有一個地址位元組的控制轉移命令,偏移量指定為 “aaaa”。該偏移量必須在下一個機器命令的 ±7Fh 範圍內。如果範圍條件不滿足,DEBUG.EXE 將給出錯誤訊息。
  3. ^ a b c 第一種表示式的形式生成偏移量,預設情況下是指向 DS 中的段地址。這些表示式可以是
    僅僅是偏移量規範 [ffff],或者
    單個暫存器引用 [BX][DI][SI],或者
    2 個暫存器的和 [BX+DI][BX+SI],或者
    帶有位移量的和 [BX±7f], [BX+ffff], [BX+DI±7f], [BX+DI+ffff], [BX+SI±7f], [BX+SI+ffff], [DI±7f], [DI+ffff], [SI±7f], [SI+ffff].
  4. ^ a b c 第二組表示式包括對 BP 暫存器的引用,並生成偏移量,預設情況下是指向 SS 中的段地址:[BP+DI], [BP+SI], [BP±7f], [BP+ffff], [BP+DI±7f], [BP+DI+ffff], [BP+SI±7f], [BP+SI+ffff].
  5. 表示式中的暫存器名稱可以用減號隔開,但這不會影響結果:無論如何都會計算總和。
  6. 預設段暫存器可以透過顯式指定字首位元組(7.02-01)來更改。
  7. 當運算元的型別標記(“byte ptr”、“word ptr”...)不在彙編命令中時,DEBUG.EXE 會根據包含另一個運算元的暫存器來確定運算元的型別:16 位暫存器(AX、BX...)設定字型別,8 位暫存器(AL、AH、BL...)設定位元組型別。如果命令不指向暫存器,則運算元的型別標記成為必填項。在任何情況下,這些標記都可以截斷為 2 個字元:“by”、“wo”等。

7.01 控制指令

[編輯 | 編輯原始碼]

切換到彙編命令的翻譯後,DEBUG.EXE 會接受命令和控制指令。後者不會被翻譯成機器程式碼,而是會影響翻譯過程,並且可能在翻譯過程中發揮非常重要的作用。

7.01-01 DB – 資料位元組插入指令

[編輯 | 編輯原始碼]

DB(= Data Byte)指令通知 DEBUG.EXE 以下的位元組字串不能被視為彙編命令,而應該被視為單獨的資料位元組,應該“原樣”寫入到彙編程式碼中。每個位元組由兩個十六進位制數字表示,沒有尾部的“h”。位元組字串可以包括用單引號或雙引號括起來的 ASCII 字元組。ASCII 字元(除包圍的引號外)被逐位元組翻譯成十六進位制程式碼。DB 指令後的註釋不允許。這是一個 DB 指令用法示例 

DB 71 6C 65 'data array'
註釋
  1. 在反彙編機器程式碼時,可能會遇到一些位元組,它們不能被識別為 DEBUG.EXE 已知的機器命令。然後,將顯示“DB”作為每個此類位元組的字首。

7.01-02 DW – 資料字插入指令

[編輯 | 編輯原始碼]

DW(= Data Word)指令通知 DEBUG.EXE 以下的字串不能被視為彙編命令,而應該被視為單獨的資料字,應該“原樣”寫入到彙編程式碼中。每個字最多包含 4 個十六進位制數字。如果一個字中少於 4 個數字,它將自動用高位零補充到 4 個數字。在彙編的機器程式碼中,每個字的最低有效 2 位構成第一個位元組,最高有效 2 位構成後面的位元組。DW 指令後的字字串可以包括用單引號或雙引號括起來的 ASCII 字元組。這些字元(除包圍的引號外)被翻譯成十六進位制表示形式,每個字元一個位元組,就像在 DB 指令(7.01-01)之後一樣。DW 指令後的註釋不允許。這是一個 DW 指令用法示例 

DW 71A0 F01 06D5 "other key" 0FFF

7.01-03 ORG – 目標地址更改指令

[編輯 | 編輯原始碼]

ORG 指令通知 DEBUG.EXE 從下一個命令開始,彙編命令的機器程式碼必須寫入到另一個位置,從 ORG 指令後指定的地址開始。處理器的暫存器不受 ORG 指令的影響。在互動式偵錯程式會話過程中,ORG 指令允許您沿著彙編程式碼導航,以便更正錯誤以及那些無法預先指定的向前引用。

在偵錯程式的示例命令檔案中,ORG 指令用於固定重新啟動點和跳轉目標點的位置(9.02-02 中的示例)。在固定點之前預留的空閒空間有助於避免繁瑣的地址重新計算,否則每次在命令檔案的任何先前部分新增或刪除程式碼位元組時都需要進行此重新計算。ORG 指令後的註釋允許。以下表格顯示了使用示例 

示例 執行的操作
ORG ffff:ffff 顯式設定段地址和偏移量
ORG fff 保持段地址不變,設定偏移量 0fffh
ORG ss:ffff 引用段暫存器“ss:”,設定偏移量 ffffh
ORG ss 引用段暫存器“ss:”,隱式偏移量為 0000h

7.01-04 指令“空行”

[編輯 | 編輯原始碼]

不包含任何命令、指令、資料和註釋的空行本身被 DEBUG.EXE 視為指令,強制從第 7 章中描述的彙編命令翻譯返回到正常控制,並使用第 6.05-02 到 6.05-23 文章中描述的這些命令。為了從鍵盤輸入此指令,您必須將最後一行留空,然後按 ENTER 鍵。當彙編命令透過輸入重定向從命令檔案接收時,透過此命令檔案中遇到的第一個空行來誘發返回正常控制。因此,應注意命令檔案中任何彙編命令塊中沒有空行,以及注意標記每個彙編命令塊末尾的空行的存在。

7.01-05 分號 – 註釋插入指令

[編輯 | 編輯原始碼]

在包含彙編命令的任何行中遇到分號( ; )時,DEBUG.EXE 會將其解釋為立即轉到下一行彙編命令的指令,跳過分號本身以及當前命令列其餘部分中所有後續字元的機器程式碼翻譯。分號的這種作用用於將註釋附加到彙編命令。

註釋
  1. 以分號開頭的行不被視為空行(7.01-04),並且不會強制 DEBUG.EXE 停止將彙編命令翻譯成機器程式碼。這提供了一個機會來插入標題和多行註釋。
  2. DEBUG 的訊息“ ^ Error” 向上指向上一行中的分號意味著前一行中存在錯誤。最有可能的情況是,由於缺少某些必需的引數,命令列被視為不完整。
  3. 分號不能用於將註釋附加到那些以控制指令 DB 或 DW 開頭的彙編命令列,以及當 DEBUG.EXE 未切換到彙編命令翻譯時。

7.02 字首

[編輯 | 編輯原始碼]

在 x86 平臺 CPU 的機器程式碼中,幾個特定的位元組被賦予了特殊的字首狀態。每個此類位元組都不是單獨的機器命令。但是,字首位元組在遇到機器命令之前,會強制 CPU 更改其解釋或執行方式。字首位元組的影響不會擴充套件到下一個命令之外。

DEBUG.EXE 允許在受字首影響的彙編命令之前的一行中指定字首位元組,例如 

CS:
ADD byte ptr [BX],0F

在同一行中受影響命令之前的指定字首位元組也是允許的 

CS: ADD byte ptr [BX],0F

機器命令的程式碼前面可以最多有四個字首,如果它們的效果彼此不矛盾。一個命令中的所有字首必須不同,不允許重複字首。

7.02-01 段覆蓋字首

[編輯 | 編輯原始碼]

大多數彙編命令不包含顯式段地址規範。對於此類命令,CPU 根據預設段暫存器分配(請參閱表格 7.00 的註釋 [3][4])來計算絕對記憶體地址(請參閱 6.05-01 的註釋 2)。段覆蓋字首強制 CPU 從另一個段暫存器讀取段地址,而不是從最接近的下一條命令的預設段暫存器讀取。當然,段覆蓋字首只能應用於那些訪問記憶體並因此隱含絕對地址計算的命令。

DEBUG.EXE “知道” 四個段覆蓋字首,繼承了相應段暫存器的名稱(見下表第二列)。CS: 字首使用的例子已經在文章 7.02 中展示。其他類似字首使用的例子可以在彙編器文字中找到,這些文字在文章 9.06 和 9.08 中給出。

現代 CPU 並非只有四個段暫存器,而是有六個。輔助段暫存器 FS 和 GS 的段覆蓋字首不被 DEBUG.EXE “知道”,但它允許透過 DB 指令(7.01-01)將這些字首作為資料指定,並且不會妨礙 CPU 正確解釋這些字首。當然,為了正確解釋這些字首,需要 80386 或更新的 CPU。

程式碼 示例 註釋
2E CS
3E DS
26 ES
36 SS
64 DB 64 相對於 FS: 段暫存器
65 DB 65 相對於 GS: 段暫存器
註釋
  1. 段覆蓋字首不能影響 ES: 暫存器的預設分配,特別是對於字串命令 CMPSB、CMPSW、INSB、INSW、MOVSB、MOVSB、SCASB、SCASW、STOSB、STOSW。

7.02-02 LOCK – 系統匯流排鎖定字首

[edit | edit source]

LOCK 字首對應於前綴位元組 F0h,它會使 CPU 傳送“匯流排忙”訊號並保持其活動狀態,直到執行以下命令終止。這在具有多個處理器的計算機中是必要的,以防止對共享記憶體資源的非協調訪問。對於具有單個處理器的普通計算機,LOCK 字首是不需要的。

LOCK 字首可以用於使用 ADC、ADD、AND、DEC、INC、NEG、NOT、OR、SBB、SUB、XCHG、XOR 命令寫入記憶體。但是,當相同的命令只執行讀取操作或與暫存器操作時,則不應指定 LOCK 字首。在這種情況下,CPU 會對位元組 F0h 響應異常 06h,導致呼叫中斷 INT 06 處理程式(8.01-07)。

程式碼 示例
F0 LOCK
註釋
  1. 英特爾的 CPU 不允許在單個命令中將 LOCK 字首與任何重複字首(7.02-03、7.02-04)組合使用。
  2. 現代處理器擁有超過 8 個控制暫存器,允許使用字首位元組 F0h 透過 MOV 命令訪問控制暫存器。[Note 1 to 7.03-58] 在這種情況下,F0h 位元組被解釋為不是 LOCK 字首,而是訪問暫存器 CR8–CR15 的字首。

7.02-03 重複字首 REPNZ

[edit | edit source]

REPNZ 代表“REPeat while Not Zero”。REPNZ 字首會迴圈執行緊隨其後的命令。重複迴圈會在至少滿足以下兩個條件之一時終止

  • 執行的命令發現運算元相等,因此將零標誌 (ZF) 設定為 ZR 狀態(6.05-15)。
  • CX 暫存器中的數字變為零,因為 CX 暫存器中規定的重複次數已用盡。

REPNE 字首,代表“REPeat while Not Equal”,被 DEBUG.EXE 接受為等效於 REPNZ,因為它們都對應於相同的字首位元組 F2h,這迫使 CPU 迴圈執行以下操作

  1. 檢查 CX==0 條件。如果滿足,則終止迴圈。如果沒有,則將 CX 暫存器中的數字減 1。
  2. 將零標誌重置為 NZ 狀態。
  3. 執行該命令,該命令由重複字首先行。
  4. 檢查零標誌是否設定為 ZR 狀態。如果是,則終止迴圈;如果不是,則從 CX==0 檢查開始重複。

只要這兩個條件都沒有滿足,CPU 就繼續迴圈。一旦至少滿足一個條件,CPU 就會退出迴圈並繼續執行下一個命令,該命令緊隨在迴圈中執行的命令之後。

重複字首與字串命令一起使用,這些命令在每次迭代時會自動增加或減少索引暫存器(SI、DI 或兩者)的內容。因此,它們的運算元的實際地址在每次迭代中都會發生變化。字串命令 CMPSB、CMPSW、SCASB、SCASW 不僅影響索引,還影響 ZF 標誌的狀態。因此,將重複字首與這些命令一起使用可以分析位元組或字的字串。當將重複字首與不影響 ZF 標誌的命令(INSB、INSW、MOVSB、MOVSW、OUTSB、OUTSW、STOSB、STOSW)一起使用時,這些命令將只是重複 CX 暫存器中預設的次數。

程式碼 示例
F2 REPNE
F2 REPNZ
註釋
  1. 當一個命令前面有幾個字首,包括一個重複字首時,舊式處理器(比 80386 更舊)有時無法在中斷後恢復執行重複迴圈。如果不能避免這種字首組合,則必須顯式重新檢查迴圈終止條件,或者在迴圈執行期間使用 CLI 命令(7.03-12)禁止中斷。
  2. 重複字首不應用於非字串命令,因為這會導致那些位元組組合,這些位元組組合可能被現代處理器解釋為操作碼擴充套件(7.02-08),特別是表示 SSE 命令。
  3. 當重複字首與運算元大小覆蓋字首(7.02-06)一起使用時,規定的重複次數不是從 16 位 CX 暫存器讀取的,而是從 32 位 ECX 暫存器讀取的。對於這種情況,重要的是要提醒在 ECX 暫存器的高位部分(位 31–16)準備一個適當的值。

7.02-04 重複字首 REPZ

[edit | edit source]

REPZ 代表“REPeat while Zero”。REPZ 字首會導致對其先行命令的迭代執行。重複迴圈會在至少滿足以下兩個條件之一時終止

  • 執行的命令發現運算元不同,因此將零標誌 (ZF) 重置為 NZ 狀態(6.05-15)。
  • CX 暫存器中的數字變為零,因為 CX 暫存器中規定的重複次數已用盡。

字首名稱 REP(=REPeat)、REPE(= REPeat while Equal)和 REPZ 被 DEBUG.EXE 視為等效:它們中的任何一個都對應於相同的字首位元組 F3h。遇到位元組 F3h 後,處理器會執行與 REPNZ 字首(7.02-03)相同的操作序列,只是 ZF 標誌的初始狀態反轉為 ZR,ZF 標誌的目標狀態相反(NZ)。所有其他與 REPNZ 字首一起執行命令的特殊性(在文章 7.02-03 和以下注釋中描述)同樣也存在於使用 REPZ 字首執行命令中。

程式碼 示例
F3 REP
F3 REPE
F3 REPZ
註釋
  1. REPZ 字首通常與 CMPSB 和 CMPSW 命令一起使用,用於比較兩個字元字串 - 名稱、路徑、簽名。當比較迴圈終止時,結果由 ZR 標誌的狀態表示:設定狀態 (ZR) 證明了同一性,重置狀態 (NZ) 證明了差異。

7.02-05 同步字首 WAIT 和 FWAIT

[edit | edit source]

字首名稱 WAIT 和 FWAIT 對應於相同的字首位元組 9Bh。它與暗示 CPU 和非同步協處理器之間程式碼傳輸的命令一起使用。位元組 9Bh 強制 CPU 等待協處理器向 CPU 的“BUSY”引腳傳送就緒確認訊號。特別是,如果機器程式碼要由沒有內部算術協處理器的 CPU 執行,則字首位元組 9Bh 應該先行於 ESC 命令(7.03-22)和協處理器的命令(7.04)。

對於現代 CPU,它們包含一個整合的算術協處理器,具有硬體同步機制,因此字首位元組 9Bh 的以前任務不再需要。如果控制暫存器 CR0(A.11-4)中的“協處理器同步”位 01h 被重置為零,則忽略位元組 9Bh。預設情況下,位 01h 被設定,然後位元組 9Bh 可能會導致呼叫 INT 07 處理程式,如果同時任務切換標誌(CR0 中的位 03h)也被設定。任務切換與處理協處理器註冊的異常的必要性相結合。INT 07 處理程式可以負責此任務,然後透過 WAIT 字首的適當使用可以確保其完成。

程式碼 示例
9B FWAIT
9B WAIT

7.02-06 運算元大小覆蓋字首

[edit | edit source]

在真實模式下,現代 CPU 預設情況下會模擬過時處理器 8086 的 16 位操作。但實際上,現代 CPU 具有 32 位通用暫存器。有時希望訪問整個 32 位暫存器,而 CPU 仍保持在真實模式下。這可以透過運算元大小覆蓋字首位元組 66h 來實現,所有屬於 x86 平臺的 32 位 CPU 都能正確“理解”它。

由於 DEBUG.EXE 不“知道”運算元大小覆蓋字首,因此應透過 DB 指令(7.01-01)引入它,例如

DB 66
SHR AX,CL

在所示的示例中,字首位元組 66h 的存在會修改 SHR 命令(7.03-83)的動作,使其影響整個 32 位暫存器 EAX。特別是,如果 CL 暫存器中預設的移位次數為 10h(= 十進位制 16),則 EAX 中的位 31–16 的內容將被移入位 15–0,並將作為普通 16 位運算元在 AX 中變得可訪問。

在由字首位元組 66h 領先的情況下,堆疊命令 PUSH、PUSHF、POP、POPF 會一次操作四個位元組。位元組按降序重要性被推入堆疊:從最高有效位到最低有效位。EAX 暫存器中位 31–16 的內容可以透過以下方式從堆疊中讀取

DB 66
PUSH AX
POP BX
POP BX

在這個例子中,字首位元組 66h 強制將 32 位暫存器 EAX 的全部內容壓入堆疊。然後第一個 POP 命令將 EAX 的兩個最低有效位元組移入 BX 暫存器,但這些位元組僅來自 AX,因此不需要。下一個 POP 命令使用 EAX 內容的所需最高有效位元組覆蓋 BX 暫存器中的先前資料。

CMP 命令(7.03-14)帶運算元大小覆蓋字首比較四個位元組的運算元,包括儲存在 32 位暫存器中的運算元。對於帶有運算元大小覆蓋字首的命令,儲存在記憶體中的運算元以及直接在可執行程式碼中指定的運算元也必須是 DWORD 型別,即 4 個位元組長。不幸的是,DEBUG.EXE 無法為帶有 DWORD 型別附加運算元的 CPU 組裝機器命令。如有必要,可以透過 DB 指令(7.01-01)附加額外的位元組。

註釋
  1. 使用運算元大小覆蓋字首的程式無法由 16 位 CPU 執行。
  2. 運算元大小覆蓋字首不能在帶有單個位元組運算元的命令之前指定,包括那些在單個位元組暫存器(AH、AL、BH 等)中的運算元,也不能在單個位元組字串命令(CMPSB、INSB、LODSB、MOVSB、OUTSB、SCASB、STOSB)之前指定。這些程式碼組合可能被現代處理器解釋為 SSE 命令。
  3. 運算元大小覆蓋字首不能在帶有段暫存器中運算元的命令之前指定,因為這些暫存器在 16 位和 32 位處理器中都是 16 位暫存器。但是,此限制不適用於讀取段地址以訪問特定記憶體單元的命令。
  4. 當使用“繼續”(6.05-14)或“跟蹤”(6.05-17)命令測試程式時,DEBUG.EXE 不會將字首位元組 66h 後的那個作為下一個機器命令顯示。儘管如此,32 位 CPU 始終接受字首位元組 66h 與後面的機器命令一起,並在一步執行這兩個命令。
  5. 運算元大小覆蓋字首始終強制使用非預設運算元大小。當代碼段描述符[註釋 5 到 A.12-2] 位元組 06h 中的第 6 位指定預設 32 位運算元大小時,字首位元組 66h 強制使用 16 位運算元大小。此處以及本書的後續部分均隱含使用預設的 16 位運算元大小,就像 CPU 在開機後進入真實模式時,CPU 的“影子”暫存器自動設定的那樣。

7.02-07 地址大小覆蓋字首

[編輯 | 編輯原始碼]

為了測試記憶體和其他一些任務,需要在沒有受保護模式下 32 位定址固有限制的情況下訪問整個地址空間。在真實模式中,可以訪問整個地址空間,但這需要設定最大 4 GB 段大小(參見文章 9.10-01),此外還需要允許非預設的 32 位定址。地址大小覆蓋字首位元組 67h 允許對緊跟其後的單個命令使用非預設的 32 位定址。

字首位元組 67h 不為 DEBUG.EXE “所知”。因此,它必須透過 DB 指令(7.01-01)作為資料引入。當一個命令之前有幾個字首時,字首位元組 67h 在運算元大小覆蓋字首(7.02-06)之前指定,但在段覆蓋字首(7.02-01)之後。當然,將字首位元組 67h 與那些不涉及記憶體單元的命令組合在一起毫無意義。

字首位元組 67h 會影響許多機器命令的程式碼長度,並更改表 7.00 註釋[3][4] 中列出的所有間接表示式解釋。只有帶有隱式間接定址的命令保持不變:CMPSB、CMPSW、LODSB、LODSW、MOVSB、MOVSW、SCASB、SCASW、STOSB、STOSW。對於使用字首位元組 67h 組裝所有其他命令,DEBUG.EXE 的功能不足。

下表顯示了間接表示式的原始解釋(在左列)與受地址大小覆蓋字首位元組 67h 影響的解釋(在右列)之間的比較。該表僅列出那些與執行相同操作的相同長度的機器命令相對應的解釋。因此,所示的解釋可以交換,從而可以“欺騙”DEBUG.EXE。您可以自由地指定 DEBUG.EXE 左列的間接表示式,該表示式對應於您在右列選擇的所需的 CPU 解釋。

原始形式 受字首 67h 影響
[BP+DI] [EBX]
[BX] [EDI]
[BP+DI±7f] [EBX±7f]
[BX±7f] [EDI±7f]
[BP±7f] [ESI±7f]
[DI±7f] [EBP±7f]
註釋
  1. 使用地址大小覆蓋字首的程式無法由 16 位 CPU 執行。
  2. 當使用“繼續”(6.05-14)或“跟蹤”(6.05-17)命令測試程式時,DEBUG.EXE 不會將字首位元組 67h 後的那個作為下一個機器命令顯示。儘管如此,32 位處理器始終接受字首位元組 67h 與後面的機器命令一起,並在一步執行這兩個命令。
  3. 地址大小覆蓋字首始終強制使用非預設地址大小。當代碼段描述符[註釋 5 到 A.12-2] 位元組 06h 中的第 6 位指定預設 32 位地址大小時,字首位元組 67h 會強制對緊跟其後的命令使用 16 位地址大小。此處以及本書的後續部分均隱含使用預設的 16 位地址大小,就像 CPU 在開機後進入真實模式時,CPU 的“影子”暫存器自動設定的那樣。

7.02-08 操作碼擴充套件字首

[編輯 | 編輯原始碼]

x86 平臺 CPU 的操作碼是在長期演變過程中形成的。在演變的每個階段,一組機器命令都用新命令進行補充。因此,一些位元組被用作操作碼擴充套件字首,影響了 CPU 指令解碼器中操作碼的解釋。這些字首沒有共同的特定功能,除了每個這樣的字首都能引入一組不同的機器命令。

過去,主要是在大型機上,位元組 FFh 被賦予了操作碼擴充套件字首的功能。現在,它被視為第 7.03 部分中描述的許多不同機器命令操作碼中的第一個位元組。後來的位元組 D8h–DFh 專用於引入第 7.04 部分中描述的算術協處理器命令。在 1990 年代,字首位元組 0Fh 引入了用於奔騰處理器的全新命令;表 6.05-18 中提到了其中的一些命令。

如今,不再有可以充當字首的空閒位元組。對於現代處理器,SSE 組的新命令是透過操作碼與字首 66h(7.02-06)、F2h(7.02-03)、F3h(7.02-04)的組合引入的,這些組合之前被認為是無效的。新的 64 位處理器將位元組 40h–4Fh 轉移到字首類別,而所有其他 x86 平臺處理器將這些位元組解釋為命令 DEC(7.03-20)和 INC(7.03-27)。即使本書的目標僅限於瞭解 DOS 下的 16 位程式設計,也無法忽略這些變化。關於確保 16 位程式碼與現代處理器相容的建議,請參見受影響機器命令描述中的註釋。

7.03 CPU 命令

[編輯 | 編輯原始碼]

7.03-01 AAA – 未打包和的十進位制校正

[編輯 | 編輯原始碼]

AAA 代表 Adjust After Addition(加法後調整)。AAA 命令將 AX 暫存器中未打包十進位制數字相加後獲得的二進位制和轉換為適當的未打包十進位制字,每個位元組包含一位十進位制數字(有關打包十進位制格式的和的校正,請參見 7.03-18)。AAA 命令檢查 AX 中的二進位制和是否違反十進位制溢位條件。違反表現為要麼 AF 標誌設定為 AC 狀態,要麼 AL(低位位元組)的最低 4 位上的數字超過 9。如果未發生十進位制溢位,則 AAA 命令不執行任何操作,但會清除 CF 標誌(將其重置為 NC 狀態)。否則,AAA 命令執行 AL =(AL + 6)、AH =(AH + 1),並將 AF 和 CF 標誌分別設定為 AC 和 CY 狀態。在任何情況下,AL(高位位元組)中的最高 4 位都將被清除為零。OF、SF、ZF 和 PF 標誌獲得不確定的狀態。

程式碼 示例
37 AAA

7.03-02 AAD – 十進位制除法準備

[編輯 | 編輯原始碼]

AAD 指令(AAD = Adjust AX for Division)表示 AX 暫存器包含一個非壓縮十進位制字,即每個位元組代表一個十進位制數字。AAD 指令將此十進位制字轉換為二進位制形式,以便可以進行二進位制除法(7.03-21)。AAD 指令計算 AL = AL + (10 • AH),然後將 AH 清零。根據結果設定標誌 SF、ZF、PF。標誌 OF、AF、CF 處於不確定的狀態。

程式碼 示例
D5 0A AAD
註釋
  1. 機器程式碼 "D5 (1-F)(0-9,B-F)" 被 DEBUG.EXE 錯誤地反彙編為 "AAD ff" 指令。
  2. 壓縮十進位制格式的數字不能由 AAD 指令處理,必須先解壓縮。

7.03-03 AAM – 十進位制乘積校正

[編輯 | 編輯原始碼]

AAM 代表 Adjust After Multiplication。假設 AX 暫存器包含兩個位元組的二進位制乘積,每個位元組代表一個非壓縮十進位制數字,並且最高四位(高級別)為零。AAM 指令將 AX 中的乘積除以 10,將商寫入 AH,將餘數寫入 AL,結果是一個適當的非壓縮十進位制字,每個位元組包含一個十進位制數字。根據結果設定標誌 SF、ZF、PF。標誌 OF、AF、CF 處於不確定的狀態。以類似的方式,AAM 指令能夠將任何二進位制數(最多 63h)轉換為非壓縮十進位制字。

程式碼 示例
D4 0A AAM
註釋
  1. 機器程式碼 "D4 (1-F)(0-9,B-F)" 被 DEBUG.EXE 錯誤地反彙編為 "AAM ff" 指令。
  2. 壓縮十進位制位元組的乘積不能由 AAM 指令校正。壓縮十進位制數必須在乘法之前解壓縮。

7.03-04 AAS – 非壓縮餘數的十進位制校正

[編輯 | 編輯原始碼]

AAS 指令(AAS = Adjust After Subtraction)將非壓縮十進位制數字減法後在 AX 暫存器中獲得的二進位制餘數轉換為適當的非壓縮十進位制字,每個位元組包含一個十進位制數字(有關壓縮十進位制格式中餘數的校正,請參見 7.03-19)。

AAS 指令檢查 AX 中的二進位制餘數是否違反了十進位制溢位條件。違規情況體現在 AF 標誌被設定為 AC 狀態,或者 AL 的最低四位(低級別)超過 9。如果未發生十進位制溢位,則 AAS 指令不執行任何操作,而是清除 CF 標誌(將其重置為 NC 狀態)。否則,AAS 指令將減去 AL = (AL - 6),AH = AH - 1,並將標誌 AF 和 CF 分別設定為狀態 AC 和 CY。無論哪種情況,AL 中的最高四位(高級別)都會被清零。標誌 OF、SF、ZF 和 PF 處於不確定的狀態。

程式碼 示例
3F AAS

7.03-05 ADC – 帶進位的二進位制加法

[編輯 | 編輯原始碼]

ADC 指令執行指定整數的加法,考慮最低位的進位。進位反映了先前操作的結果,並且必須保留,由 CF 標誌的狀態表示。加法後,標誌 OF、SF、ZF、AF、PF、CF 根據總和獲取新的狀態,總和替換 ADC 指令的第一個運算元。

ADC 是一個二進位制操作,但有兩個例外。如果第一個運算元在 AX 暫存器中,則 ADC 指令可以應用於非壓縮十進位制數,並且 AX 中獲得的二進位制總和應由 AAA 指令轉換為適當的非壓縮十進位制數(7.03-01)。如果第一個運算元在 AL 暫存器中,則 ADC 指令可以應用於壓縮十進位制位元組,並且 AL 中獲得的二進位制總和應由 DAA 指令轉換為適當的壓縮十進位制位元組(7.03-18)。

第一
byte
第二個位元組 資料
位元組
示例
10 (0-B)(0-F) 0-2 ADC [bp+si+ffff],bl
10 (C-F)(0-F)   ADC bl,bl
11 (0-B)(0-F) 0-2 ADC [bp+si+ffff],bx
11 (C-F)(0-F)   ADC bx,bx
12 (0-B)(0-F) 0-2 ADC bl,[bp+si+ffff]
13 (0-B)(0-F) 0-2 ADC bx,[bp+si+ffff]
14   1 ADC AL,ff
15   2 ADC AX,ffff
80 (1,5,9)(0-7) 1-3 ADC byte ptr [bp+si+ffff],ff
80 D(1-7) 1 ADC bl,ff
81 (1,5,9)(0-7) 2-4 ADC word ptr [bp+si+ffff],ffff
81 D(1-7) 2 ADC bx,ffff
83 (1,5,9)(0-7) 1-3 ADC word ptr [bp+si+ffff],±7f
83 D(1-7) 1 ADC bx,±7f
註釋
  1. 機器程式碼 "1(2,3) (C-F)(0-F)" 和 "82 (1,5,9,D)(0-7)" 也被 DEBUG.EXE 反彙編為 ADC 指令。

7.03-06 ADD – 二進位制加法

[編輯 | 編輯原始碼]

ADD 指令執行指定整數的加法,忽略由 CF 標誌狀態表示的最低位的進位。加法後,標誌 OF、SF、ZF、AF、PF、CF 根據總和獲取新的狀態,總和替換 ADD 指令的第一個運算元。

ADD 是一個二進位制操作,但有兩個例外。如果第一個運算元在 AX 暫存器中,則 ADD 指令可以應用於非壓縮十進位制數,並且 AX 中獲得的二進位制總和應由 AAA 指令轉換為適當的非壓縮十進位制數(7.03-01)。如果第一個運算元在 AL 暫存器中,則 ADD 指令可以應用於壓縮十進位制位元組,並且 AL 中獲得的二進位制總和應由 DAA 指令轉換為適當的壓縮十進位制位元組(7.03-18)。

第一
byte
第二個位元組 資料
位元組
示例
00 (0-B)(0-F) 0-2 ADD [bp+si+ffff],bl
00 (C-F)(0-F)   ADD bl,bl
01 (0-B)(0-F) 0-2 ADD [bp+si+ffff],bx
01 (C-F)(0-F)   ADD bx,bx
02 (0-B)(0-F) 0-2 ADD bl,[bp+si+ffff]
03 (0-B)(0-F) 0-2 ADD bx,[bp+si+ffff]
04   1 ADD AL,ff
05   2 ADD AX,ffff
80 (0,4,8)(0-7) 1-3 ADD byte ptr [bp+si+ffff],ff
80 C(1-7) 1 ADD bl,ff
81 (0,4,8)(0-7) 2-4 ADD word ptr [bp+si+ffff],ffff
81 C(1-7) 2 ADD bx,ffff
83 (0,4,8)(0-7) 1-3 ADD word ptr [bp+si+ffff],±7f
83 C(1-7) 1 ADD bx,±7f
註釋
  1. 機器程式碼 "0(2,3) (C-F)(0-F)" 和 "82 (0,4,8,C)(0-7)" 也被 DEBUG.EXE 反彙編為 ADD 指令。

7.03-07 AND – 邏輯“AND”運算

[編輯 | 編輯原始碼]

AND 指令分析兩個運算元中對應位的對。如果在一對中至少有一個位處於 FALSE(零)狀態,則結果的對應位被清零。如果一對中的兩個位都處於 TRUE 狀態,則結果的對應位也被設定為 TRUE 狀態。結果替換第一個運算元。標誌 SF、ZF、PF 根據結果獲取新的狀態。標誌 CF 和 OF 被分別清除為狀態 NC(無進位)和 NV(無溢位)。

第一
byte
第二個位元組 資料
位元組
示例
20 (0-B)(0-F) 0-2 AND [bp+si+ffff],bl
20 (C-F)(0-F)   AND bl,bl
21 (0-B)(0-F) 0-2 AND [bp+si+ffff],bx
21 (C-F)(0-F)   AND bx,bx
22 (0-B)(0-F) 0-2 AND bl,[bp+si+ffff]
23 (0-B)(0-F) 0-2 AND bx,[bp+si+ffff]
24   1 AND AL,ff
25   2 AND AX,ffff
80 (2,6,A)(0-7) 1-3 AND byte ptr [bp+si+ffff],ff
80 E(1-7) 1 AND bl,ff
81 (2,6,A)(0-7) 2-4 AND word ptr [bp+si+ffff],ffff
81 E(1-7) 2 AND bx,ffff
83 (2,6,A)(0-7) 1-3 AND word ptr [bp+si+ffff],±7f
83 E(1-7) 1 AND bx,±7f
註釋
  1. 機器程式碼 "2(2-3) (C-F)(0-F)" 和 "82 (2,6,A,E)(0-7)" 也被 DEBUG.EXE 反彙編為 AND 指令。

7.03-08 CALL – 呼叫子程式

[編輯 | 編輯原始碼]

CALL 指令將返回地址儲存到堆疊中,然後根據指定的目標地址跳轉到子程式。標誌的狀態不會因 CALL 指令而改變。

CALL 指令有幾種形式。呼叫呼叫程式程式碼段之外的子程式是 CALL FAR,它使用完整的 4 位元組目標地址(段:偏移量)。呼叫呼叫程式程式碼段內的子程式是 "近" CALL,它不改變當前程式碼段,只使用 2 位元組目標偏移量。

"近" CALL 指令有兩種不同的形式,機器程式碼分別為 FFh 和 E8h。

機器程式碼為 FFh 的 "近" CALL 指令將 IP(指令指標)暫存器的當前內容壓入堆疊,然後用目標偏移量覆蓋 IP 暫存器,目標偏移量是從記憶體或通用暫存器讀取的。

機器程式碼為 E8h 且後跟資料字的 "近" CALL 指令則不同:在將 IP 的內容儲存到堆疊中之後,它將此資料字新增到 IP 中的偏移量。在 CALL 指令之後找到明確的目標偏移量後,DEBUG.EXE 會自動計算給定目標偏移量與當前位於 IP 暫存器中的下一個機器指令偏移量之間的差。該差值構成緊隨 E8h 位元組之後寫入彙編的可執行程式碼中的資料字。

由於 "近" CALL 指令的兩種形式都執行當前程式碼段內的跳轉,因此從用 "近" CALL 指令呼叫的子程式返回到呼叫程式必須由 RET 指令(7.03-73)執行,該指令僅從堆疊中恢復 IP 暫存器的內容。

CALL FAR 命令將 CS(程式碼段)和 IP 暫存器的值壓入堆疊。CALL FAR 命令的雙字運算元替換 CS 和 IP 暫存器中的前一個值。因此,執行了跳轉到另一個段的操作。因此,從使用 CALL FAR 命令呼叫的子程式返回到呼叫程式,必須使用 RETF 命令(7.03-74)執行,該命令從堆疊中恢復 CS 和 IP 暫存器的值。

第一
byte
第二個位元組 資料
位元組
示例 註釋
9A   4 CALL FAR ffff:ffff [注意 1]
E8   2 CALL ffff
FF (1,5,9)(0-7) 0-2 CALL [bp+si+ffff] [注意 2]
FF (1,5,9)(8-F) 0-2 CALL FAR [bp+si+ffff] [注意 2]
FF D(0-7)   CALL bx [注意 3]
註釋
  1. ^ 在所示示例中,第一個數字是目標段地址,第二個數字是目標偏移量。此行中允許指定標記 FAR,但不是必需的:在任何情況下,都會執行 CALL FAR。
  2. ^ a b 當從記憶體中讀取目標地址時,操作取決於是否存在標記 FAR。如果存在,則讀取一個 4 位元組的目標地址,並執行 CALL FAR。如果未指定標記 FAR,則讀取一個 2 位元組的目標偏移量,並執行“近”呼叫。
  3. ^ 如果 CALL 命令的運算元在暫存器中,則必須事先將目標偏移量寫入該暫存器。CALL 命令對 16 位暫存器的呼叫始終會導致“近”呼叫。
  4. 機器程式碼“FF D(8-F)”由 DEBUG.EXE 解碼為“CALL far bx”。
  5. 重複字首 F2h (7.02-03)、F3h (7.02-04) 不能應用於 CALL 命令。

7.03-09 CBW – 位元組到字轉換

[編輯 | 編輯原始碼]

CBW 命令(CBW = Convert Byte to Word)將 AL 暫存器中的帶符號位元組轉換為 AX 暫存器中的帶符號字(2 位元組),方法是用原始帶符號位元組的符號位填充 AX 的 AH 部分。CBW 命令不會改變標誌的狀態。

程式碼 示例
98 CBW

7.03-10 CLC – 進位標誌復位

[編輯 | 編輯原始碼]

CLC 命令將進位標誌 CF 清除為預設的“NC”(無進位)狀態,這通常稱為 CF=0。

程式碼 示例
F8 CLC

7.03-11 CLD – 方向標誌復位

[編輯 | 編輯原始碼]

CLD 命令(CLD = CLear Direction)將方向標誌 DF 重置為其預設狀態“UP”。這會導致在執行字串操作(CMPSB、LODSB、MOVSB、SCASB、STOSB 等)期間,索引暫存器(DI 和/或 SI)中的偏移量計數方向為升序。

程式碼 示例
FC CLD

7.03-12 CLI – 中斷標誌復位

[編輯 | 編輯原始碼]

CLI 命令(CLI = Clear Interrupt Flag)將中斷標誌 IF 重置為“DI”(= 停用中斷)狀態。CLI 命令強制 CPU 忽略外部中斷,除了不可遮蔽中斷 INT 02 (8.01-03)。

程式碼 示例
FA CLI
註釋
  1. 無論 IF 標誌狀態如何,可程式設計中斷始終透過 INT 命令(7.03-28)執行。
  2. 如果當前程式的特權級別低於標誌暫存器(A.11-4)中位 0Ch 和 0Dh 定義的 I/O 操作特權級別,則不會執行 CLI 命令。

7.03-13 CMC – 進位標誌狀態反轉

[編輯 | 編輯原始碼]

CMC 命令(CMC = CompleMentary Carry)將進位標誌 CF 的任何當前狀態更改為相反狀態:NC(無進位)更改為 CY(進位),反之亦然。

程式碼 示例
F5 CMC

7.03-14 CMP – 運算元比較

[編輯 | 編輯原始碼]

CMP 命令根據第一個運算元(被減數)和第二個運算元(減數)之間的差值設定標誌 OF、SF、ZF、AF、PF、CF。差值本身不會被儲存。兩個運算元都保持不變。

CMP 命令留下的標誌狀態的解釋取決於運算元是帶符號數還是無符號數。比較無符號數後,應使用條件跳轉命令 JA、JB、JBE、JNB。比較帶符號數後,應使用其他條件跳轉命令 JG、JGE、JL、JLE。所有條件跳轉命令和迴圈命令的全名反映了 CMP 命令第一個(左側)運算元與第二個(右側)運算元之間的狀態關係。例如,JA =“如果大於則跳轉”表示 CMP 命令的左側運算元必須大於或等於右側運算元。

第一
byte
第二個位元組 資料
位元組
示例
38 (0-B)(0-F) 0-2 CMP [bp+si+ffff],bl
38 (C-F)(0-F)   CMP bl,bl
39 (0-B)(0-F) 0-2 CMP [bp+si+ffff],bx
39 (C-F)(0-F)   CMP bx,bx
3A (0-B)(0-F) 0-2 CMP bl,[bp+si+ffff]
3B (0-B)(0-F) 0-2 CMP bx,[bp+si+ffff]
3C   1 CMP AL,ff
3D   2 CMP AX,ffff
80 (3,7,B)(8-F) 1-3 CMP byte ptr [bp+si+ffff],ff
80 F(9-F) 1 CMP bl,ff
81 (3,7,B)(8-F) 2-4 CMP word ptr [bp+si+ffff],ffff
81 F(9-F) 2 CMP bx,ffff
83 (3,7,B)(8-F) 1-3 CMP word ptr [bp+si+ffff],±7f
83 F(9-F) 1 CMP bx,±7f
註釋
  1. 機器程式碼“3(A,B) (C-F)(0-F)”和“82 (3,7,B,F)(8-F)”也由 DEBUG.EXE 解碼為 CMP 命令。

7.03-15 CMPSB – 位元組對序列比較

[編輯 | 編輯原始碼]

雖然 CMPSB 代表“CoMPare Strings of Bytes”(比較位元組字串),但 CMPSB 命令實際上只比較一對位元組。要比較的位元組的地址必須事先載入到 DS:SI 和 ES:DI 暫存器對中。如果位元組相等,則 CF(進位標誌)被清除為 NC(無進位)狀態,ZF(零標誌)被設定為 ZR 狀態。如果位元組不相等,則 CF 標誌被設定為 CY 狀態,ZF 標誌被清除為 NZ(非零)狀態。標誌 OF、SF、AF、PF 接收與比較位元組之間的差值相對應,但差值本身不會被儲存。

比較後,SI(源索引)暫存器和 DI(目標索引)暫存器中的兩個偏移量都會增加 1 或減少 1,具體取決於方向標誌 DF 的狀態(“UP”或“DN”)。DF 標誌的狀態可以透過 CLD(7.03-11)和 STD(7.03-85)命令更改。索引暫存器內容的自動更改為比較下一對位元組做準備。

CMPSB 命令之前通常會有重複字首 F2h (7.02-03) 或 F3h (7.02-04),這使得它可以迴圈執行,從而比較位元組字串。CMPSB 命令也可以在前面加上一個段覆蓋字首(2Eh 或 26h 或 36h,參見 7.02-01);它使能夠引用其他段暫存器,而不是用於比較位元組之一的段暫存器 DS。對於另一個比較位元組,預設段暫存器 ES 不能被字首覆蓋。

程式碼 示例
A6 CMPSB
註釋
  1. 當 CMPSB 命令前面有重複字首 F2h 或 F3h 時,迴圈內的操作順序包括分配標誌狀態,然後增加(或減少)索引暫存器的內容,之後是迴圈終止條件檢查。因此,在迴圈終止時,索引暫存器中的偏移量不會指向導致迴圈終止的那些位元組,而是指向下一對位元組。

7.03-16 CMPSW – 字對序列比較

[編輯 | 編輯原始碼]

CMPSW 指令(CMPSW = CoMPare Strings of Words)比較一對字,然後將 SI 和 DI 索引暫存器的值增加(或減少)2,從而準備地址以比較下一對字。運算元大小覆蓋字首 66h(7.02-06)強制 CMPSW 指令比較一對四位元組運算元(DWORD 型別)並將索引暫存器的內容增加(或減少)4。CMPSW 指令執行的所有其他特性與 CMPSB 指令相同(7.03-15)。

程式碼 示例
A7 CMPSW

7.03-17 CWD – 字到雙字轉換。

[edit | edit source]

CWD 指令(CWD = Convert Word into Double word)將 AX 暫存器中的帶符號字轉換為一個四位元組帶符號數(DWORD 型別)。DX 暫存器專用於 dword 運算元的兩個最高有效位元組。轉換是透過用原始帶符號字的符號位填充 DX 暫存器來完成的。CWD 指令不會改變標誌狀態。

程式碼 示例
99 CWD

7.03-18 DAA – 打包和的十進位制修正

[edit | edit source]

DAA 指令(DAA = Decimal Adjustment after Addition)將 AL 暫存器中打包的十進位制位元組的二進位制和轉換為一個正確的打包的十進位制位元組,表示和的 2 個十進位制數字(有關非打包和的十進位制修正,請參見 7.03-01)。

打包的十進位制位元組的二進位制和可能違反 AL 暫存器的低位和高位 4 位部分(半位元組)中的十進位制溢位條件。首先檢查低位部分:如果那裡的值超過 9 或 AF 標誌設定為 AC 狀態,那麼 DAA 指令將新增 AL = (AL + 6)。之後,對 AL 暫存器的高位 4 位部分(半位元組)應用類似的檢查:如果那裡的值超過 9Fh 或 CF 標誌設定為 CY 狀態,那麼 DAA 指令將新增 AL = (AL + 60h)。AF、CF、SF、ZF、PF 標誌根據結果獲取新的狀態。OF 標誌保持在不確定的狀態。

程式碼 示例
27 DAA

7.03-19 DAS – 打包餘數的十進位制修正

[edit | edit source]

DAS 指令(DAS = Decimal Adjustment after Subtraction)將 AL 暫存器中打包的十進位制位元組的二進位制差轉換為一個正確的打包的十進位制位元組,表示餘數的 2 個十進位制數字(有關非打包差的十進位制修正,請參見 7.03-04)。

打包的十進位制位元組的二進位制差可能違反 AL 暫存器的低位和高位 4 位部分(半位元組)中的十進位制溢位條件。首先檢查低位部分:如果那裡的值超過 9 或 AF 標誌設定為 AC 狀態,那麼 DAS 指令將減去 AL = (AL – 6)。之後,對 AL 暫存器的高位 4 位部分(半位元組)應用類似的檢查:如果那裡的值超過 9Fh 或 CF 標誌設定為 CY 狀態,那麼 DAS 指令將減去 AL = (AL – 60h)。AF、CF、SF、ZF、PF 標誌根據結果獲取新的狀態。OF 標誌保持在不確定的狀態。

程式碼 示例
2F DAS

7.03-20 DEC – 單位減量

[edit | edit source]

DEC 指令將它的運算元減 1。OF、SF、ZF、AF、PF 標誌根據結果獲取新的狀態。CF 標誌保留其以前的狀態。

第一
byte
第二個位元組 資料
位元組
示例
4(8-F)     DEC bx
FE (0,4,8)(8-E) 0-2 DEC byte ptr [bp+si+ffff]
FE C(8-F)   DEC bl
FF (0,4,8)(8-E) 0-2 DEC word ptr [bp+si+ffff]
註釋
  1. 位元組 48h–4Fh 可以被 64 位處理器解釋為字首。因此,2 位元組程式碼 "FF C(8-F)" 應該優先於 1 位元組程式碼 4(8-F)。程式碼 "FF C(8-F)" 被所有 x86 平臺的處理器解釋為 "DEC bx" 指令,並且被 DEBUG.EXE 正確地反彙編,但在彙編時,這些程式碼應該透過 DB 指令(7.01-01)作為資料提供給 DEBUG.EXE。

處理器,並且被 DEBUG.EXE 正確地反彙編,但在彙編時,這些程式碼應該透過 DB 指令(7.01-01)作為資料提供給 DEBUG.EXE。

7.03-21 DIV – 無符號整數的除法

[edit | edit source]

DIV 指令執行無符號二進位制整數的除法(有關帶符號整數的除法,請參見 7.03-24)。顯式運算元是除數。如果除數是位元組,則被除數被隱式地認為存在於 AX 暫存器中,商被保留在 AL 中,餘數被放置在 AH 中。如果除數是字,則被除數被隱式地認為存在於 DX 暫存器(最高有效 2 個位元組)和 AX 暫存器(最低有效 2 個位元組)中,商被保留在 AX 中,餘數被放置在 DX 中。OF、SF、ZF、AF、PF、CF 標誌獲取不確定的狀態。

雖然 DIV 是一個二進位制運算,但非打包十進位制字可以被二進位制除法運算,如果它們事先透過 AAD 指令(7.03-02)轉換為可接受的準二進位制形式。

第一
byte
第二個位元組 資料
位元組
示例
F6 (3,7,B)(0-7) 0–2 DIV byte ptr [bp+si+ffff]
F6 F(0-7)   DIV bl
F7 (3,7,B)(0-7) 0–2 DIV word ptr [bp+si+ffff]
F7 F(0-7)   DIV bx
註釋
  1. 如果除法運算導致商暫存器溢位,CPU 將自動生成一個異常:呼叫 INT 00 處理程式(8.01-01)。結果取決於該處理程式。

7.03-22 ESC – 程式碼傳輸到非同步協處理器

[edit | edit source]

最初,ESC(= ESCape)指令用於將資料和指令從 CPU 傳送到外部非同步協處理器。每個 ESC 指令之前都是 WAIT 字首(7.02-05),強制 CPU 等待協處理器到達 CPU 的 "BUSY" 引腳的準備就緒確認訊號。後來,算術協處理器的指令獲得了它們特有的名稱(7.04),但其餘的機器程式碼(以位元組 D8h–DFh 開頭)仍然被 DEBUG.EXE 反彙編為 ESC 指令

D9 (0,4,8)(8-F), D9 D(1-7), DA (C-F)(0-F), DB (0,4,8,C,D,F)(8-F),
DB (2,3,6,7,A-D,F)(0-7), DB E(4 – F), DD (0,2,6)(8-F),
DD (E,F)(0-F), DE D(8,A-F), DF (0,4,8)(8-F), DF (E,F)(0-F).

上述程式碼中的一些已被分配給現代算術協處理器的新的指令。作為所有以位元組 D8h–DFh 開頭的協處理器指令,如果控制暫存器 CR0(A.11-4)的位 02h("協處理器模擬")被清除為零,則 ESC 指令由 CPU 執行。但如果位 02h 被設定,則 CPU 對每個這樣的指令的響應是呼叫 INT 07 處理程式(8.01-08)。這意味著應該載入一個特殊的 INT 07 處理程式,它能夠模擬算術協處理器或其他非同步裝置的功能。

理論上,ESC 指令可以用於將資料和指令傳送到外部非同步裝置,但對於現代處理器,這個功能沒有被記錄在案。ESC 指令的第一個運算元是一個十六進位制數,第二個運算元從指定的源讀取。這兩個運算元的解釋是每個特定目標裝置的權利。ESC 指令不會改變標誌狀態。

第一
byte
第二個位元組 示例
DA C(0-7) ESC 10,bl
DA C(8-F) ESC 11,bl
DA D(0-7) ESC 12,bl
DA D(8-F) ESC 13,bl
DA E(0-7) ESC 14,bl
DA E(8-F) ESC 15,bl
DA F(0-7) ESC 16,bl
DA F(8-F) ESC 17,bl

7.03-23 HLT – 將 CPU 設定為停止狀態

[edit | edit source]

HLT 指令(= HaLT)強制處理器停止。處理器停止後,會保留 CS:IP 暫存器的值和標誌狀態,從而確保可以正確啟用。處理器可以透過重新啟動或透過外部中斷訊號(透過 NMI 引腳(8.01-03)或中斷控制器(8.01-09)接收)恢復正常執行。

程式碼 示例
F4 HLT
註釋
  1. HLT 指令可以在最高特權級別執行的程式中使用。在最高特權級別之外,HLT 指令會被忽略。
  2. 確定將 CPU 從停止狀態恢復的特定外部中斷的方法在文章 8.01-09 中介紹。

7.03-24 IDIV – 帶符號整數的除法

[edit | edit source]

IDIV (= Integer DIVision) 命令執行帶符號二進位制整數的除法(無符號整數的除法見 7.03-21)。顯式運算元是除數。如果除數是位元組,則被除數隱含地存在於 AX 暫存器中,商留在 AL 中,餘數放在 AH 中。如果除數是字,則被除數隱含地存在於 DX 暫存器中(較重要的 2 個位元組)以及 AX 暫存器中(較不重要的 2 個位元組),商留在 AX 中,餘數放在 DX 中。餘數的符號始終與被除數的符號相同。標誌 OF、SF、ZF、AF、PF、CF 進入不確定的狀態。儘管 IDIV 是一個二進位制運算,但如果在預先使用 AAD 命令(7.03-02)將其轉換為可接受的準二進位制形式,則可以對非壓縮十進位制字進行二進位制除法。

第一
byte
第二個位元組 資料
位元組
示例
F6 (3,7,B)(8-F) 0-2 IDIV byte ptr [bp+si+ffff]
F6 F(8-F)   IDIV bl
F7 (3,7,B)(8-F) 0-2 IDIV word ptr [bp+si+ffff]
F7 F(8-F)   IDIV bx
註釋
  1. 如果除法運算導致商暫存器溢位,CPU 會自動生成異常:呼叫 INT 00 處理程式(8.01-01)。結果取決於該處理程式。

7.03-25 IMUL – 帶符號整數的乘法

[edit | edit source]

IMUL(Integer MULtiplcation)命令將帶符號整數相乘(無符號整數見 7.03-61)。IMUL 命令的顯式運算元表示乘數。如果此運算元是位元組,則另一個運算元隱含地存在於 AL 暫存器中;乘法後,積留在 AX 暫存器中。如果顯式運算元是字,則另一個運算元必須存在於 AX 暫存器中;乘法後,積的較不重要的 2 個位元組留在 AX 暫存器中,積的較重要的 2 個位元組留在 DX 暫存器中。

如果 AH 或 DX 暫存器中積的最高有效部分表示非零值,則 IMUL 命令會相應地將 OF 和 CF 標誌設定為 OV 和 CY 狀態。相反,這些標誌的清除狀態 NV 和 NC 表示積的最高有效部分僅填充了符號位。標誌 SF、ZF、AF、PF 進入不確定的狀態。

IMUL 命令可以應用於二進位制整數和非壓縮十進位制數。壓縮十進位制運算元必須先解壓縮。解壓縮十進位制數的積需要透過 AAM 命令(7.03-03)轉換為解壓縮十進位制格式。

第一
byte
第二個位元組 資料
位元組
示例
F6 (2,6,A)(8-F) 0-2 IMUL byte ptr [bp+si+ffff]
F6 E(8-F)   IMUL bl
F7 (2,6,A)(8-F) 0-2 IMUL word ptr [bp+si+ffff]
F7 E(8-F)   IMUL bx
註釋
  1. DEBUG.EXE 不支援具有 2 個顯式運算元的 IMUL 命令的其他形式(程式碼 69h 和 6Bh)。

7.03-26 IN – 從埠輸入資料

[span>edit | edit source]

執行 IN 命令時,CPU 會發出訊號,將 CPU 的匯流排從記憶體切換到 I/O 埠,並啟用非同步資料傳輸。IN 命令的第一個運算元指定接收到的資料應寫入的暫存器。應根據接收到的資料的格式選擇此暫存器:如果要接收位元組,則為位元組暫存器 AL,如果要接收字,則為雙位元組暫存器 AX。IN 命令的第二個運算元定義埠地址。後者可以明確地指定為兩位十六進位制數,也可以間接指定——作為 DX 暫存器的內容。CPU 標誌的狀態不會因 IN 命令而改變。

第一
byte
第二個位元組 資料
位元組
示例
E4   1 IN AL,ff
E5   1 IN AX,ff
EC     IN AL,DX
ED     IN AX,DX
註釋
  1. 選定的埠地址顯示在附錄 A.14-1 中。IN 命令的直接形式不允許超過 FFh 的埠地址。透過 DX 暫存器進行間接定址不受此限制。
  2. 如果當前程式的特權級別低於標誌暫存器中位 0Ch 和 0Dh 定義的 I/O 操作的特權級別(A.11-4),則不會執行 IN 命令。

7.03-27 INC – 單位增量

[edit | edit source]

INC 命令將運算元增加 1。標誌 OF、SF、ZF、AF、PF 根據結果獲取新的狀態。CF 標誌保留其以前的狀態。

第一
byte
第二個位元組 資料
位元組
示例
4(0-7)     INC bx
FE (0,4,8)(0-7) 0-2 INC byte ptr [bp+si+ffff]
FE C(0-7)   INC bl
FF (0,4,8)(0-7) 0-2 INC word ptr [bp+si+ffff]
註釋
  1. 64 位處理器可以將位元組 40h–47h 解釋為字首。因此,2 位元組程式碼“FF C(0-7)”應優先於 1 位元組程式碼 4(0-7)。程式碼“FF C(0-7)”被所有 x86 平臺處理器解釋為“INC bx”命令,並由 DEBUG.EXE 正確地反彙編,但在彙編期間,這些程式碼應透過 DB 指令(7.01-01)作為資料提供給 DEBUG.EXE。

7.03-28 INT – 呼叫中斷處理程式

[edit | edit source]

INT (= Interrupt) 命令將控制權轉移到該中斷處理程式,該處理程式的編號由 INT 命令的運算元定義。但在將控制權轉移之前,INT 命令會為中斷處理程式任務完成後進一步返回到當前程式做好準備。因此,INT 命令會執行以下操作:

  • 標誌暫存器的當前狀態儲存在堆疊中;
  • CS 暫存器(段地址)的當前狀態儲存在堆疊中;
  • 計算下一個命令的偏移量,並將其儲存在堆疊中,以便進一步恢復 IP 暫存器的狀態;
  • IF 標誌被清除為 DI 狀態,因此透過中斷控制器接收的中斷請求被阻止;
  • CPU 中預取的命令佇列被重置;
  • 將中斷號乘以 4,得到儲存中斷處理程式地址的記憶體單元的地址;
  • 將中斷處理程式的地址(段和偏移量)從記憶體單元複製到 CS:IP 暫存器中,將控制權轉移到處理程式。

INT 命令在堆疊中留下的資料的順序,可以透過 IRET 命令(7.03-30)返回到當前程式,IRET 命令必須是每個中斷處理程式執行的最後一個命令。中斷程式的恢復執行將從 INT 命令後面的命令開始。

幾乎每個中斷處理程式都需要滿足某些特定條件,或者在 CPU 暫存器或記憶體中存在一些必要的資料才能執行其任務。這些條件和資料必須在執行 INT 命令之前預先準備好。本書第 8 章描述了所選中斷處理程式的相關要求。

第一
byte
第二個位元組 資料
位元組
示例
CC     INT 3
CD   1 INT ff
註釋
  1. 中斷標誌 IF 的原始狀態不會影響 INT 命令的執行。IF 標誌隻影響透過中斷控制器接收的外部中斷請求。
  2. INT 3 命令(程式碼 CCh)的一個獨特之處在於它不依賴於特權級別:在任何特權級別下執行,就像在真實模式一樣。
  3. 下一個命令的偏移量僅由 INT 和 INTO 命令(7.03-29)儲存在堆疊中。所有其他內部中斷(異常)都在堆疊中保留當前命令的偏移量。
  4. 堆疊中的資料可供中斷處理程式使用。如果在控制權轉移後立即將堆疊指標 (SP) 的狀態儲存在 BP 暫存器中,則 [BP+00] 地址指向返回偏移量,[BP+02] 地址指向返回段,[BP+04] 地址指向被中斷程式的標誌狀態。

7.03-29 INTO – 呼叫溢位處理程式

[edit | edit source]

透過 INT 00(8.01-01)對溢位的立即響應有時並不方便。INTO 命令(INTO = INTerrupt if Overflow)可以提供對溢位更靈活和延遲的響應。如果 OF 標誌的 OV (= OVerflow) 狀態指示溢位,則 INTO 命令會呼叫中斷 INT 04 處理程式(8.01-05),該處理程式必須設計用於處理溢位錯誤。INTO 命令對 INT 04 處理程式的呼叫包括 INT 命令(7.03-28)採取的所有預防措施。

程式碼 示例
CE INTO
註釋
  1. 預設的 INT 04 處理程式除了將控制權返回給呼叫程式外,什麼也不做。為了獲得對溢位的理想響應,使用者必須準備另一個 INT 04 處理程式,而不是預設的處理程式。新處理程式從其地址被寫入中斷表(8.02-18)開始生效。

7.03-30 IRET – 從中斷處理程式返回

[edit | edit source]

IRET (= Interrupt RETurn) 命令從堆疊中恢復所有資料,以便返回到呼叫程式的執行:CS 暫存器中的段地址、標誌的以前狀態以及 IP 暫存器中準備好的下一個命令的偏移量。IRET 命令必須是每個中斷處理程式執行的最後一個命令。

程式碼 示例
CF IRET
註釋
  1. IRET 命令對標誌狀態的恢復不受對 POPF 命令(7.03-68)施加的限制。因此,IRET 命令提供了一種繞過這些限制的機會。
  2. IRET 命令重置 CPU 中預取的命令佇列。這是因為中斷處理程式的命令解碼規則可能與呼叫程式的命令解碼規則不同。

7.03-31 JA – 如果大於則跳轉

[edit | edit source]

JA 命令將它的資料位元組加到 IP 暫存器的值上,如果 CF 和 ZF 標誌都清除到 NC(無進位)和 NZ(無零)狀態。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JA 命令最常用於無符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在有符號整數運算之後,相同的“大於”條件由 JG 命令檢查,7.03-35)。

DEBUG.EXE 接受 JA 命令的另一個名稱:JNBE - “如果小於或等於則跳轉”,但程式碼 77h 始終被反彙編為 JA。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
77   1 JA aaaa

7.03-32 JB - 如果小於則跳轉

[edit | edit source]

JB 命令將它的資料位元組加到 IP 暫存器的值上,如果 CF 標誌設定為 CY(進位)狀態。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JB 命令用於在各種失敗後執行跳轉,這些失敗透過將 CF 標誌設定為 CY 狀態來標記。JB 命令也用於無符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在有符號整數運算之後,相同的“小於”條件由 JL 命令檢查,7.03-37)。

DEBUG.EXE 接受 JB 命令的另外兩個名稱:JNAE -“如果不大於或等於則跳轉”和 JC - “如果進位則跳轉”,但程式碼 72h 始終被反彙編為 JB。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
72   1 JB aaaa

7.03-33 JBE - 如果小於或等於則跳轉

[edit | edit source]

JBE 命令將它的資料位元組加到 IP 暫存器的值上,如果 CF 標誌設定為 CY(進位)狀態或 ZF 標誌設定為 ZR(零)狀態。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JBE 命令用於無符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在有符號整數運算之後,相同的“小於或等於”條件由 JLE 命令檢查,7.03-38)。

DEBUG.EXE 接受此命令的另一個名稱:JNA - “如果不大於則跳轉”,但程式碼 76h 始終被反彙編為 JBE。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
76   1 JBE aaaa

7.03-34 JCXZ - 如果 CX 為零則跳轉

[edit | edit source]

JCXZ 命令將它的資料位元組加到 IP 暫存器的值上,如果 CX 暫存器中的值為零。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

由於 CX 暫存器通常用作迭代計數器,因此 JCXZ 命令可以繞過迴圈,如果在進入迴圈之前不滿足必要條件。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
E3   1 JCXZ aaaa

7.03-35 JG - 如果大於則跳轉

[edit | edit source]

JG 命令將它的資料位元組加到 IP 暫存器的值上,如果 ZF 標誌清除到 NZ(無零)狀態,並且 SF 和 OF 標誌處於相同狀態,即它們都清除或都設定。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JG 命令用於有符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在無符號整數運算之後,相同的“大於”條件由 JA 命令檢查,7.03-31)。

DEBUG.EXE 接受 JG 命令的另一個名稱:JNLE - “如果小於或等於則跳轉”,但程式碼 7Fh 始終被反彙編為 JG。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
7F   1 JG aaaa

7.03-36 JGE - 如果大於或等於則跳轉

[edit | edit source]

JGE 命令將它的資料位元組加到 IP 暫存器的值上,如果 SF 和 OF 標誌處於相同狀態,即它們都清除或都設定。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JGE 命令用於有符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在無符號整數運算之後,相同的“大於或等於”條件由 JNB 命令檢查,7.03-40)。

DEBUG.EXE 接受此命令的另一個名稱:JNL - “如果不大於則跳轉”,但程式碼 7Dh 始終被反彙編為 JGE。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
7D   1 JGE aaaa

7.03-37 JL - 如果小於則跳轉

[edit | edit source]

JL 命令將它的資料位元組加到 IP 暫存器的值上,如果 SF 和 OF 標誌處於不同狀態,即當其中一個清除時,另一個設定。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JL 命令用於有符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在無符號整數運算之後,相同的“小於”條件由 JB 命令檢查,7.03-32)。

DEBUG.EXE 接受此命令的另一個名稱:JNGE - “如果不大於或等於則跳轉”,但程式碼 7Ch 始終被反彙編為 JL。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
7C   1 JL aaaa

7.03-38 JLE - 如果小於或等於則跳轉

[edit | edit source]

JLE 命令將它的資料位元組加到 IP 暫存器的值上,如果 ZF 標誌設定為 ZR(零)狀態或 SF 和 OF 標誌處於不同狀態,即當其中一個清除時,另一個設定。由於資料位元組代表目標和當前偏移量之間的差,它的加法會導致一個“短”轉移(跳轉)到指定目標偏移量,該偏移量在最接近的下一個命令的 ±7Fh 範圍內。

JLE 命令用於有符號整數運算之後,特別是 CMP、SBB、SUB 命令之後(在無符號整數運算之後,相同的“小於或等於”條件由 JBE 命令檢查,7.03-33)。

DEBUG.EXE 接受 JLE 命令的另一個名稱:JNG - “如果不大於則跳轉”,但程式碼 7Eh 始終被反彙編為 JLE。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
7E   1 JLE aaaa

7.03-39 JMP - 無條件跳轉

[edit | edit source]

JMP 指令透過更改 IP(指令指標)暫存器或同時更改 CS(程式碼段)和 IP 暫存器的原有內容,執行到另一個機器指令(跳轉)。如果 JMP 指令給定一個雙字運算元,則它將作為“JMP FAR”執行:第一個字替換 CS 暫存器中以前的段地址,第二個字替換 IP 暫存器中以前的偏移量。帶有單字運算元的 JMP 指令僅替換 IP 暫存器中的偏移量,從而在同一段內執行“近”跳轉。帶有單個位元組資料的 JMP 指令執行“短”跳轉,否則:它將資料位元組新增到 IP 暫存器中的當前偏移量。

當 CPU 在真實模式下執行時,JMP 指令不會影響標誌。

第一
byte
第二個位元組 資料
位元組
示例 註釋
E9   2 JMP ffff 註釋 1
EA   4 JMP ffff:ffff 註釋 2
EB   1 JMP aaaa 註釋 1
FF (2,6,A)(0-7) 0-2 JMP [bp+si+ffff] 註釋 3
FF (2,6,A)(8-F) 0-2 JMP FAR [bp+si+ffff] 註釋 3
FF E(0-7)   JMP bx 註釋 4
註釋
  1. ^ a b 在彙編指令行中給定目標偏移量後,DEBUG.EXE 會自動計算指定目標偏移量與下一條指令偏移量之間的差值。如果此差值不超過 ±7fh,則 JMP 指令將轉換為機器程式碼 EBh(“短”跳轉),否則將轉換為機器程式碼 E9h(“近”跳轉)。
  2. ^ 在所示示例中,第一個數字是段地址,第二個數字是目標偏移量。在這樣的指令行中允許使用 FAR 標記,但並非必需:無論如何都會執行 FAR 跳轉。
  3. ^ a b 當 JMP 指令透過間接定址獲取目標地址時,跳轉型別取決於是否指定 FAR 標記:如果指定,則將從記憶體中讀取一個 4 位元組完整地址,並執行遠跳轉。如果未指定 FAR 標記,則將從記憶體中讀取一個 2 位元組字。這個字將被解釋為目標偏移量,並將執行“近”跳轉。
  4. ^ 如果 JMP 指令引用暫存器,則必須事先在該暫存器中準備目標偏移量。JMP 指令對 16 位暫存器的引用始終會導致“近”跳轉。
  5. 幾乎每一次 CPU 從真實模式切換到保護模式或從保護模式切換回真實模式後,都會緊跟著一條 JMP FAR 指令,將控制權轉移到同一程式碼段中的下一條指令。這條 JMP 指令並非為了跳轉,而是用於其他目的。首先,它使 CS 暫存器中的字(段地址或選擇器)狀態與 CPU 的模式相一致。其次,這條 JMP 指令會重置 CPU 中的預取指令佇列,因為這些指令是根據 CPU 之前模式的規則進行解碼的。
  6. 程式碼“FF E(8-F)”被 DEBUG.EXE 解彙編為指令“JMP far bx”。

7.03-40 JNB – 若不低於則跳轉

[edit | edit source]

如果 CF 標誌被清除為 NC(無進位)狀態,則 JNB 指令將其資料位元組新增到 IP 暫存器的內容。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

JNB 指令用於在成功結束(由將 CF 標誌清除為 NC 狀態標記)後執行跳轉。JNB 指令也用於無符號整數的操作之後,特別是 CMP、SBB、SUB 指令之後(在有符號整數的操作之後,相同的“大於或等於”條件由 JGE 指令檢查,7.03-36)。

DEBUG.EXE 接受 JNB 指令的另外兩個名稱:JAE – “若大於或等於則跳轉” 和 JNC – “若無進位則跳轉”,但程式碼 73h 始終被解彙編為 JNB。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
73   1 JNB aaaa

7.03-41 JNO – 若無溢位則跳轉

[edit | edit source]

如果 OF 標誌被清除為 NV(無溢位)狀態,則 JNO 指令將其資料位元組新增到 IP 暫存器的內容。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
71   1 JNO aaaa

7.03-42 JNS – 若無符號則跳轉

[edit | edit source]

如果 SF 標誌被清除為 PL 狀態,則 JNS 指令將其資料位元組新增到 IP 暫存器的內容,PL 狀態表示先前操作的結果為正整數。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
79   1 JNS aaaa

7.03-43 JNZ – 若不為零則跳轉

[edit | edit source]

如果 ZF 標誌被清除為 NZ(非零)狀態,則 JNZ 指令將其資料位元組新增到 IP 暫存器的內容,NZ 狀態表示先前操作的結果不等於或不為零。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

DEBUG.EXE 接受 JNZ 指令的另外一個名稱:JNE – “若不等於則跳轉”,但程式碼 75h 始終被解彙編為 JNZ。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
75   1 JNZ aaaa

7.03-44 JO – 若溢位則跳轉

[edit | edit source]

如果 OF 標誌被設定為 OV(溢位)狀態,則 JO 指令將其資料位元組新增到 IP 暫存器的內容。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
70   1 JO aaaa

7.03-45 JPE – 若奇偶性為偶數則跳轉

[edit | edit source]

如果 PF 標誌被設定為 PE(奇偶性為偶數)狀態,則 JPE 指令將其資料位元組新增到 IP 暫存器的內容,PE 狀態表示先前操作結果的最低有效位元組中的位數之和為偶數(不考慮結果的其他位元組)。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

DEBUG.EXE 接受 JPE 指令的另外一個名稱:JP – “若奇偶性為偶數則跳轉”,但程式碼 7Ah 始終被解彙編為 JPE。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
7A   1 JPE aaaa

7.03-46 JPO – 若奇偶性為奇數則跳轉

[edit | edit source]

如果 PF 標誌被清除為 PO(奇偶性為奇數)狀態,則 JPO 指令將其資料位元組新增到 IP 暫存器的內容,PO 狀態表示先前操作結果的最低有效位元組中的位數之和為奇數(不考慮結果的其他位元組)。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

DEBUG.EXE 接受 JPO 指令的另外一個名稱:JNP – “若奇偶性不為偶數則跳轉”,但程式碼 7Bh 始終被解彙編為 JPO。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
7B   1 JPO aaaa

7.03-47 JS – 若有符號則跳轉

[edit | edit source]

如果 SF 標誌被設定為 NG 狀態,則 JS 指令將其資料位元組新增到 IP 暫存器的內容,NG 狀態表示先前操作的結果為負整數。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
78   1 JS aaaa

7.03-48 JZ – 若為零則跳轉

[edit | edit source]

如果 ZF 標誌被設定為 ZR(零)狀態,則 JZ 指令將其資料位元組新增到 IP 暫存器的內容,ZR 狀態表示先前操作的結果相等或為零。由於資料位元組表示目標和當前偏移量之間的差值,因此新增它會導致“短”跳轉(轉移)到指定目標偏移量,該偏移量位於最近下一條指令的 ±7Fh 範圍內。

DEBUG.EXE 接受 JZ 指令的另一個名稱:JE - "jump if equal",但程式碼 74h 始終被反彙編為 JZ。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
74   1 JZ aaaa

7.03-49 LAHF - 將標誌複製到 AH 暫存器

[編輯 | 編輯原始碼]

LAHF 指令 (LAHF = Load AH with Flags) 將標誌暫存器低位元組的標誌狀態複製到 AH 暫存器。AH 中的位 0 對應於 CF (進位標誌),位 2 對應於 PF (奇偶校驗標誌),位 4 對應於 AF (輔助標誌),位 6 對應於 ZF (零標誌),位 7 對應於 SF (符號標誌)。位 5、3、1 沒有相應的標誌。位 1 始終設定為二進位制 1,位 5 和位 3 始終清零。

程式碼 示例
9F LAHF

7.03-50 LDS - 載入 DS 暫存器

[編輯 | 編輯原始碼]

LDS 指令將其第二個運算元視為雙字的地址。該雙字中的位元組 1 和 2 被解釋為偏移量,位元組 3 和 4 被解釋為段地址。LDS 指令將此段地址複製到 DS 段暫存器,並將偏移量複製到指定為 LDS 指令第一個運算元的暫存器。因此,該暫存器與 DS 段暫存器一起,就可以作為段:偏移量對被引用。LDS 指令不會改變標誌的狀態。

第一
byte
第二個位元組 資料
位元組
示例
C5 (1,5,9)(8-F) 0-2 LDS bx,[bp+si+ffff]
註釋
  1. 程式碼 "C5 (C-F)(0-F)" 也被 DEBUG.EXE 反彙編為 LDS 指令。
  2. 預設情況下,DS:SI 暫存器對錶示源地址;因此,SI 暫存器是 LDS 指令示例中 "bx" 的最常見替代。
  3. DS 暫存器中的段和指定暫存器中的偏移量都可用於定址,並且可以在同一個操作中重新分配;例如,命令 DS: LDS SI,[SI] 是有效的。

7.03-51 LEA - 偏移量計算

[編輯 | 編輯原始碼]

LEA 指令 (LEA = Load Effective Address) 計算方括號內的表示式,該表示式作為第二個運算元給出。計算結果表示一個特定的偏移量。該偏移量被寫入到指定為 LEA 指令第一個運算元的暫存器中。LEA 指令不會改變標誌的狀態。

第一
byte
第二個位元組 資料
位元組
示例
8D (0-B)(0-F) 0-2 LEA bx,[bp+si+ffff]

7.03-52 LES - 載入 ES 暫存器

[編輯 | 編輯原始碼]

LES 指令將其第二個運算元視為雙字的地址。該雙字中的位元組 1 和 2 被解釋為偏移量,位元組 3 和 4 被解釋為段地址。LES 指令將此段地址複製到 ES 段暫存器,並將偏移量複製到指定為 LES 指令第一個運算元的暫存器。因此,該暫存器與 ES 段暫存器一起,就可以作為段:偏移量對被引用。LES 指令不會改變標誌的狀態。

第一
byte
第二個位元組 資料
位元組
示例
C4 (1,5,9)(8-F) 0-2 LES bx,[bp+si+ffff]
註釋
  1. 程式碼 "C4 (C-F)(0-F)" 也被 DEBUG.EXE 反彙編為 LES 指令。
  2. 預設情況下,ES:DI 暫存器對錶示目標地址;因此,DI 暫存器是 LES 指令示例中 "bx" 的最常見替代。
  3. ES 暫存器中的段和指定暫存器中的偏移量都可用於定址,並且可以在同一個操作中重新分配;例如,命令 ES: LES DI,[DI] 是有效的。

7.03-53 LODSB - 位元組的串行復制

[編輯 | 編輯原始碼]

雖然 LODSB 的名稱代表 "LOaD String of Bytes",但實際上 LODSB 指令將根據預先寫入 DS:SI 暫存器對的地址從記憶體中讀取單個位元組並複製到 AL 暫存器。複製後,SI (源索引) 暫存器中的偏移量將增加 1 或減少 1:這取決於方向標誌 DF 的狀態 ("UP" 或 "DN")。DF 標誌的狀態可以透過 CLD (7.03-11) 和 STD (7.03-85) 指令改變。SI 暫存器內容的自動更改為複製下一個位元組準備了條件。LODSB 指令不會改變標誌的狀態。

LODSB 指令可以由段覆蓋字首 (7.02-01) précéder ; 它允許引用其他段暫存器,而不是預設的源段暫存器 DS。

程式碼 示例
AC LODSB

7.03-54 LODSW - 字的串行復制

[編輯 | 編輯原始碼]

LODSW 指令 (LODSW = LOaD a String of Words) 將單個字複製到 AX 暫存器,然後將 SI 索引暫存器的內容增加 (或減少) 2,從而為複製下一個字準備偏移量。運算元大小覆蓋字首 66h (7.02-06) 強制 LODSW 指令複製四位元組運算元 (DWORD 型別) 並將 SI 暫存器的內容增加 (或減少) 4。LODSW 指令執行的其他所有特殊情況與 LODSB 指令 (7.03-53) 相同。

程式碼 示例
AD LODSW

7.03-55 LOOP - 迴圈的安排

[編輯 | 編輯原始碼]

LOOP 指令首先將 CX 暫存器中的一個整數減少 1,然後檢查餘數是否為零。只要餘數不為零,LOOP 指令就會將其資料位元組新增到 IP 暫存器中的當前偏移量。因此,在最近的下一條指令的 ±7fh 範圍內執行 "短" 跳轉。但是,當 CX 暫存器中的餘數變為零時,LOOP 指令不會執行任何操作,因此 CPU 退出迴圈並繼續執行迴圈體之外的最近的下一條指令。LOOP 指令不會改變標誌的狀態。

CX 暫存器中的迭代次數基於 LOOP 指令位於迴圈體之後的假設。在這種情況下,迴圈體在迴圈進入條件第一次被 LOOP 指令檢查之前執行一次。為了防止迴圈體不受控制的執行,迴圈體之前應加上 JCXZ 指令 (7.03-34)。透過帶有匯出體的迴圈可以獲得相同的結果,但在這種情況下,CX 暫存器中預設的整數必須比所需的迭代次數大 1。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
E2   1 LOOP aaaa

7.03-56 LOOPNZ - 迴圈,以 ZF = ZR 為退出條件

[編輯 | 編輯原始碼]

LOOPNZ 指令 (LOOPNZ = Loop if Not Zero) 首先將 CX 暫存器中的一個整數減少 1,不影響標誌,然後檢查兩個條件 : CX 暫存器中的餘數是否為零以及 ZF 標誌是否被設定為 ZR (ZeRo) 狀態。只要這兩個條件都滿足,LOOPNZ 指令就會將其資料位元組新增到 IP 暫存器中的當前偏移量。因此,在最近的下一條指令的 ±7fh 範圍內執行 "短" 跳轉。但是,當其中一個條件滿足時,LOOPNZ 指令不會執行任何操作,因此 CPU 退出迴圈並繼續執行迴圈體之外的最近的下一條指令。使用 LOOPNZ 指令安排迴圈的其他特殊情況與 LOOP 指令 (7.03-55) 相同。

DEBUG.EXE 接受 LOOPNZ 指令的另一個名稱:LOOPNE (= loop, if not equal),但程式碼 E0h 始終被反彙編為 LOOPNZ。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
E0   1 LOOPNZ aaaa

7.03-57 LOOPZ - 迴圈,以 ZF = NZ 為退出條件

[編輯 | 編輯原始碼]

LOOPZ 指令 (LOOPZ = Loop if Zero) 首先將 CX 暫存器中的一個整數減少 1,不影響標誌,然後檢查兩個條件 : CX 暫存器中的餘數是否為零以及 ZF 標誌是否被清零為 NZ (No Zero) 狀態。只要這兩個條件都滿足,LOOPZ 指令就會將其資料位元組新增到 IP 暫存器中的當前偏移量。因此,在最近的下一條指令的 ±7fh 範圍內執行 "短" 跳轉。但是,當其中一個條件滿足時,LOOPZ 指令不會執行任何操作,因此 CPU 退出迴圈並繼續執行迴圈體之外的最近的下一條指令。使用 LOOPZ 指令安排迴圈的其他特殊情況與 LOOP 指令 (7.03-55) 相同。

DEBUG.EXE 接受 LOOPZ 指令的另一個名稱:LOOPE (loop, if equal),但程式碼 E1h 始終被反彙編為 LOOPZ。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
E1   1 LOOPZ aaaa

7.03-58 MOV - 資料複製指令

[edit | edit source]

MOV 命令將由第二個運算元直接或間接指定的一個位元組或一個字複製到由第一個運算元指定的暫存器或記憶體單元中。當可以透過涉及的暫存器的大小確定要複製的資料的大小(位元組或字)時,不需要明確指定要複製的資料的大小。除了呼叫控制、除錯和測試 CPU 暫存器的形式之外,普通形式的 MOV 命令不會更改標誌的狀態。這些形式,如以下 [註釋 1] 中所示,可能會將標誌 OF、SF、ZF、AF、PF、CF 留在不確定的狀態。

第一
byte
第二個位元組 資料
位元組
示例
88 (0-B)(0-5, 7-F) 0-2 MOV [bp+si+ffff],bl
88 (C-F)(0-F)   MOV bl,bl
89 (0-B)(0-5, 7-F) 0-2 MOV [bp+si+ffff],bx
89 (C-F)(0-F)   MOV bx,bx
8A (0-B)(0-5, 7-F) 0-2 MOV bl,[bp+si+ffff]
8B (0-B)(0-5, 7-F) 0-2 MOV bx,[bp+si+ffff]
8C (0,1,4,5,8,9)(0-F) 0-2 MOV [bp+si+ffff],ss
8C (C,D,E)(0-F)   MOV bx,ss
8E (0,1,4,5,8,9)(0-F) 0-2 MOV ss,[bp+si+ffff]
8E (C,D,E)(0-F)   MOV ss,bx
A0   2 MOV AL,[ffff]
A1   2 MOV AX,[ffff]
A2   2 MOV [ffff],AL
A3   2 MOV [ffff],AX
B(0-7)   1 MOV bl,ff
B(8-F)   2 MOV bx,ffff
C6 (0,4,8)(0-7) 1-3 MOV byte ptr [bp+si+ffff],ff
C7 (0,4,8)(0-7) 2-4 MOV word ptr [bp+si+ffff],ffff
註釋
  1. ^ a b DEBUG.EXE 不“知道”這些形式的 MOV 命令,這些命令呼叫 32 位 CPU 的除錯和控制暫存器,但這些命令的程式碼可以透過 DB 指令(7.01-01)作為資料輸入。這些命令的程式碼長度為 3 個位元組,以 OFh 位元組開頭。第二個位元組定義複製的方向
    20h – 來自控制暫存器 (CR0, CR2–CR4)
    21h – 來自除錯暫存器 (DR0–DR3, DR6, DR7)
    22h – 進入控制暫存器 (CR0, CR2–CR4)
    23h – 進入除錯暫存器 (DR0–DR3, DR6, DR7)
    第三個位元組在這些程式碼中定義特定的暫存器
    C0h – CR0 或 DR0,例如, 0F 20 C0 = MOV EAX,CR0
    C8h – DR1,例如, 0F 23 C8 = MOV DR1,EAX
    D0h – CR2 或 DR2,例如, 0F 20 D0 = MOV EAX,CR2
    D8h – CR3 或 DR3,例如, 0F 20 D8 = MOV EAX,CR3
    E0h – CR4,例如, 0F 22 E0 = MOV CR4,EAX
    F0h – DR6,例如, 0F 21 F0 = MOV EAX,DR6
    F8h – DR7,例如, 0F 23 F8 = MOV DR7,EAX

    為了使用 EAX 以外的其他暫存器,您必須在以下列表中將該暫存器的編號(從 00h 到 07h)加到第三個位元組中

    EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI,例如 0F 20 C3 = MOV EBX,CR0
    DEBUG.EXE 不能反彙編這些程式碼,但如果程式由 32 位 CPU 執行,則不會妨礙對包含這些程式碼的程式進行除錯。在這些命令之前,不需要運算元大小覆蓋字首(7.02-06)。
  2. DEBUG.EXE 不“知道”呼叫 32 位 CPU 的段暫存器 GS 和 FS 的命令,但這些命令的程式碼可以透過 DB 指令(7.01-01)作為資料輸入。這些命令的程式碼長度為 2 個位元組
    8C E0 = MOV AX,FS
    8C E8 = MOV AX,GS
    8E E0 = MOV FS,AX
    8E E8 = MOV GS,AX

    為了使用 AX 以外的其他暫存器,您必須在 表 7.00 的第二行中給出的列表中將該暫存器的編號(從 00h 到 07h)加到第二個位元組中,例如

    8E E3 = MOV FS,BX
    DEBUG.EXE 錯誤地將這些命令的程式碼反彙編為與 ES 和 CS 段暫存器相關聯,但這不會妨礙對包含這些程式碼的程式進行除錯,如果程式由 32 位 CPU 執行。
  3. MOV 命令不能將資料複製到 CS 段暫存器;這隻能透過控制轉移命令(CALL、JMP、RETF 等)來完成。
  4. 將資料複製到 SS 暫存器的 MOV 命令會在執行下一個命令的時間內觸發硬體阻塞外部中斷。這意味著下一個命令必須將新的偏移量寫入 SP 暫存器。只有這種命令順序才能排除在切換到另一個堆疊時由外部中斷引起的事故。
  5. 程式碼 8(A,B) (C-F)(0-F)、8(C,E)(2,3,6,7,A,B,F)(0-F) 和 C(6,7) (C-F)(0-F) 也由 DEBUG.EXE 反彙編為 MOV 命令。

7.03-59 MOVSB – 位元組串的串行復制

[edit | edit source]

雖然 MOVSB 代表“移動位元組串”,但 MOVSB 命令實際上只複製一個位元組。源位元組地址必須事先載入到 DS:SI 暫存器對中;目標地址載入到 ES:DI 暫存器中。複製後,SI(源索引)暫存器和 DI(目標索引)暫存器中的兩個偏移量都會增加 1 或減少 1:這取決於方向標誌 DF 的狀態(“UP”或“DN”)。DF 標誌的狀態可以透過 CLD(7.03-11)和 STD(7.03-85)命令更改。索引暫存器內容的自動更改為在下一個記憶體單元中複製下一個位元組準備了條件。MOVSB 命令不會更改標誌的狀態。

MOVSB 命令通常以重複字首 F2h(7.02-03)或 F3h(7.02-04)開頭,這些字首可以迴圈執行它,從而複製一個位元組串。MOVSB 命令也可以以段覆蓋字首(7.02-01)開頭;它可以引用其他段暫存器而不是預設的源段暫存器 DS。目標段暫存器 ES 無法透過字首更改。

程式碼 示例
A4 MOVSB

7.03-60 MOVSW – 字的串行復制

[edit | edit source]

MOVSW 命令(MOVSW = 移動字串)複製一個字,然後將 SI 和 DI 索引暫存器的內容增加(或減少) 2,從而將源和目標偏移量準備為將下一個字複製到下一對記憶體單元中。運算元大小覆蓋字首 66h(7.02-06)強制 MOVSW 命令複製 4 位元組的運算元(DWORD 型別)並將索引暫存器的內容增加(或減少) 4。MOVSW 命令執行的其他所有特性與 MOVSB 命令(7.03-59)相同。

程式碼 示例
A5 MOVSW

7.03-61 MUL – 無符號整數的乘法

[edit | edit source]

MUL 命令(MUL = 乘法)將無符號整數相乘(有關有符號整數的乘法,請參見 7.03-25)。MUL 命令的顯式運算元表示乘數。如果此運算元是一個位元組,則隱式認為另一個運算元存在於 AL 暫存器中;乘法後,積保留在 AX 暫存器中。如果顯式運算元是一個字,則隱式認為另一個運算元存在於 AX 暫存器中;乘法後,積的低 2 個位元組保留在 AX 暫存器中,積的高 2 個位元組保留在 DX 暫存器中。

如果積在 AH 或 DX 暫存器中的最高部分表示非零值,則 MUL 命令會將 OF 和 CF 標誌分別設定為 OV 和 CY 狀態。相反,這些標誌的清除狀態 NV 和 NC 表示積的最高部分已用零填充。標誌 SF、ZF、AF、PF 將獲取不確定的狀態。

MUL 命令可應用於二進位制整數和未打包的十進位制位元組。打包十進位制運算元必須事先解包。未打包的十進位制位元組的積需要透過 AAM 命令(7.03-03)轉換為未打包的十進位制格式。

第一
byte
第二個位元組 資料
位元組
示例
F6 (2,6,A)(0-7) 0-2 MUL byte ptr [bp+si+ffff]
F6 E(0-7)   MUL bl
F7 (2,6,A)(0-7) 0-2 MUL word ptr [bp+si+ffff]
F7 E(0-7)   MUL bx

7.03-62 NEG – 運算元的符號反轉

[edit | edit source]

NEG 命令(NEG = 否定)從零中減去其運算元。因此,非零運算元的符號被反轉,但零運算元保持不變。標誌(OF、SF、ZF、AF、PF、CF)根據結果獲取新的狀態。

第一
byte
第二個位元組 資料
位元組
示例
F6 (1,5,9)(8-F) 0-2 NEG byte ptr [bp+si+ffff]
F6 D(8-F)   NEG bl
F7 (1,5,9)(8-F) 0-2 NEG word ptr [bp+si+ffff]
F7 D(8-F)   NEG bx

7.03-63 NOP – 空操作

[edit | edit source]

雖然 NOP 命令(NOP = 無操作)已知什麼也不做,但它實際上將 IP(指令指標)增加 1,因此 IP 指向下一條命令。

程式碼 示例
90 NOP

7.03-64 NOT – 運算元位的反轉

[edit | edit source]

NOT 命令對運算元中的每一位執行邏輯非操作。NOT 命令不會更改標誌的狀態。

第一
byte
第二個位元組 資料
位元組
示例(“aaaa” - 目標偏移量)
F6 (1,5,9)(0-7) 0-2 NOT byte ptr [bp+si+ffff]
F6 D(0-7)   NOT bl
F7 (1,5,9)(0-7) 0-2 NOT word ptr [bp+si+ffff]
F7 D(0-7)   NOT bx

7.03-65 OR – 邏輯或運算

[edit | edit source]

OR 命令分析兩個運算元中對應位的對。如果一對中至少一位處於 TRUE 狀態,則結果的對應位也被設定為 TRUE 狀態。如果一對中的兩個位都被清除為 FALSE 狀態,則結果的對應位也被清除為 FALSE 狀態。結果替換第一個運算元。標誌 SF、ZF、PF 根據結果獲取新的狀態。標誌 CF 和 OF 分別被清除為狀態 NC(無進位)和 NV(無溢位)。標誌 AF 獲取不確定的狀態。

第一
byte
第二個位元組 資料
位元組
示例
08 (0-B)(0-F) 0-2 OR [bp+si+ffff],bl
08 (C-F)(0-F)   OR bl,bl
09 (0-B)(0-F) 0-2 OR [bp+si+ffff],bx
09 (C-F)(0-F)   OR bx,bx
0A (0-B)(0-F) 0-2 OR bl,[bp+si+ffff]
0B (0-B)(0-F) 0-2 OR bx,[bp+si+ffff]
0C   1 OR AL,ff
0D   2 OR AX,ffff
80 (0,4,8)(8-F) 1-3 OR byte ptr [bp+si+ffff],ff
80 C(9-F) 1 OR bl,ff
81 (0,4,8)(8-F) 2-4 OR word ptr [bp+si+ffff],ffff
81 C(9-F) 2 OR bx,ffff
83 (0,4,8)(8-F) 1-3 OR word ptr [bp+si+ffff],±7f
83 C(9-F) 1 OR bx,±7f
註釋
  1. 程式碼“0(A,B) (C-F)(0-F)” 和 “82 (0,4,8,C)(8-F)” 也會被 DEBUG.EXE 反彙編為 OR 命令。
  2. 當 OR 命令應用於相等的運算元時,這些運算元不會被更改。例如,OR AX,AX 命令通常僅用於設定標誌。

7.03-66 OUT – 資料輸出到埠

[編輯 | 編輯原始碼]

執行 OUT 命令時,CPU 生成一個訊號,該訊號將 CPU 的匯流排從記憶體切換到 I/O 埠。OUT 命令的第一個運算元明確地指定目標埠地址,以兩位十六進位制數表示,或間接地指定 DX 暫存器的內容。OUT 命令的第二個運算元定義資料來源暫存器:如果要傳送位元組,則為位元組暫存器 AL;如果要傳送字,則為雙位元組暫存器 AX。CPU 標誌的狀態不受 OUT 命令影響。

第一
byte
第二個位元組 資料
位元組
示例
E6   1 OUT ff,AL
E7   1 OUT ff,AX
EE     OUT DX,AL
EF     OUT DX,AX
註釋
  1. 選定的埠地址顯示在附錄 A.14-1 中。OUT 命令的直接形式不允許埠地址高於 FFh。透過 DX 暫存器進行的間接定址不受此限制。
  2. 如果當前程式的特權級別低於標誌暫存器中位 0Ch 和 0Dh 定義的 I/O 操作的特權級別 (A.11-4),則不會執行 OUT 命令。

7.03-67 POP – 資料從堆疊中彈出

[編輯 | 編輯原始碼]

POP 命令將一個數據字(2 位元組)從堆疊頂部複製到指定的暫存器或記憶體單元,然後透過將 SP 暫存器(堆疊指標)中的偏移量增加 2 來移動堆疊頂部。標誌的狀態不受 POP 命令影響。

第一
byte
第二個位元組 資料
位元組
示例 註釋
07     POP ES
0F A1   DB 0F A1 = POP FS
0F A9   DB 0F A9 = POP GS
17     POP SS
1F     POP DS
5(8-F)     POP bx
8F (0,8)(0-7) 0-2 POP [bp+si+ffff]
註釋
  1. 從堆疊中彈出資料到 FS 和 GS 段暫存器的命令不被 DEBUG.EXE “識別”,但可以透過 DB 指令 (7.01-01) 輸入。DEBUG.EXE 無法反彙編這些命令的程式碼。然而,如果程式由 32 位處理器執行,DEBUG.EXE 允許除錯包含這些程式碼的程式。
  2. 程式碼“8F (C-F)(0-F)” 被 DEBUG.EXE 反彙編為“POP bx”。

7.03-68 POPF – 從堆疊中恢復標誌狀態

[編輯 | 編輯原始碼]

POPF 命令將資料字(2 位元組)從堆疊頂部複製到標誌暫存器,然後透過將 SP 暫存器(堆疊指標)中的偏移量增加 2 來移動堆疊頂部。標誌獲取新的狀態,這些狀態由彈出的資料字的位定義。

程式碼 示例
9D POPF
註釋
  1. 如果當前程式在任何非最高特權級別執行,POPF 命令無法更改標誌暫存器中 I/O 特權級別欄位(位 0Ch 和 0Dh)的狀態 (A.11-4)。
  2. 如果當前程式的特權級別低於標誌暫存器中位 0Ch 和 0Dh 定義的 I/O 操作的特權級別 (A.11-4),POPF 命令無法更改 IF 標誌的狀態。
  3. 在運算元大小覆蓋字首 66h (7.02-06) 之前,POPF 命令從堆疊中彈出 4 個位元組到擴充套件的 32 位標誌暫存器中。但是,這種訪問 V86 模式標誌的方法被硬體阻止(有關更多資訊,請參閱A.11-4 的註釋 4 和 5)。

7.03-69 PUSH – 將資料字複製到堆疊中。

[編輯 | 編輯原始碼]

PUSH 命令將 SP 暫存器(堆疊指標)遞減 2,從而為新資料擴充套件堆疊兩個記憶體單元。然後,資料從 PUSH 命令的運算元定義的源中複製到這些記憶體單元中。標誌的狀態不受 PUSH 命令影響。

第一
byte
第二個位元組 資料
位元組
示例 註釋
06     PUSH ES
0E     PUSH CS
0F A0   DB 0F A0 = PUSH FS
0F A8   DB 0F A8 = PUSH GS
16     PUSH SS
1E     PUSH DS
5(0-7)     PUSH bx
68   2 DB 68 ff ff = PUSH ffff
6A   1 DB 6A ff = PUSH 00ff
FF (3,7,B)(0-7) 0-2 PUSH [bp+si+ffff]
註釋
  1. 將顯式整數和段地址從 FS 和 GS 暫存器中壓入的命令不被 DEBUG.EXE “識別”,但可以透過 DB 指令 (7.01-01) 作為資料輸入。DEBUG.EXE 無法反彙編這些命令的程式碼。然而,如果程式由 32 位處理器執行,DEBUG.EXE 允許除錯包含這些程式碼的程式。
  2. 建議避免 PUSH SP 操作。舊的 CPU 先遞減 SP,然後複製其值。大多數現代 CPU 儲存原始 SP 內容。因此,在某些計算機中,PUSH SP 操作可能會導致不可預測的程式行為。
  3. 程式碼“FF F(0-7)” 也會被 DEBUG.EXE 反彙編為“PUSH bx”。

7.03-70 PUSHF – 將標誌狀態複製到堆疊中

[編輯 | 編輯原始碼]

PUSHF 命令(PUSHF = PUSH Flags)將兩個位元組從標誌暫存器複製到堆疊中,就像 PUSH 命令 (7.03-69) 複製一個數據字一樣。執行的所有特殊之處都相同。

程式碼 示例
9C PUSHF
註釋
  1. 在運算元大小覆蓋字首 66h (7.02-06) 之前,PUSHF 命令將擴充套件的 32 位標誌暫存器中的 4 個位元組複製到堆疊中。[註釋 4 到 A.11-4] 但是,PUSHF 命令複製 V86 模式標誌狀態的操作被硬體阻止。

7.03-71 RCL – 透過進位標誌向左移位

[編輯 | 編輯原始碼]

RCL 命令(RCL = Rotate through Carry Leftward)透過進位標誌向左排列其第一個運算元的迴圈移位,朝向更重要的位位置。在每一步,最高有效位都變成 CF 標誌的狀態,而運算元的最低有效位則獲得 CF 標誌的先前狀態。OV 標誌的狀態也可能改變,但其他標誌保留其以前的狀態。

第二個運算元(1 或 CL)定義向左移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (1,5,9)(0-7) 0-2 RCL byte ptr [bp+si+ffff],1
D0 D(0-7)   RCL bl,1
D1 (1,5,9)(0-7) 0-2 RCL word ptr [bp+si+ffff],1
D1 D(0-7)   RCL bx,1
D2 (1,5,9)(0-7) 0-2 RCL byte ptr [bp+si+ffff],CL
D2 D(0-7)   RCL bl,CL
D3 (1,5,9)(0-7) 0-2 RCL word ptr [bp+si+ffff],CL
D3 D(0-7)   RCL bx,CL

7.03-72 RCR – 透過進位標誌向右移位

[編輯 | 編輯原始碼]

RCR 命令(RCR = Rotate through Carry to the Right)透過進位標誌向右排列其第一個運算元的迴圈移位,朝向更不重要的位位置。在每一步,最低有效位都變成 CF 標誌的狀態,而運算元的最高有效位則獲得 CF 標誌的先前狀態。OV 標誌的狀態也可能改變,但其他標誌保留其以前的狀態。

第二個運算元(1 或 CL)定義向右移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (1,5,9)(8-F) 0-2 RCR byte ptr [bp+si+ffff],1
D0 D(8-F)   RCR bl,1
D1 (1,5,9)(8-F) 0-2 RCR word ptr [bp+si+ffff],1
D1 D(8-F)   RCR bx,1
D2 (1,5,9)(8-F) 0-2 RCR byte ptr [bp+si+ffff],CL
D2 D(8-F)   RCR bl,CL
D3 (1,5,9)(8-F) 0-2 RCR word ptr [bp+si+ffff],CL
D3 D(8-F)   RCR bx,CL

7.03-73 RET – 在同一段中返回

[編輯 | 編輯原始碼]

RET 命令從子程式中執行返回到呼叫程式,子程式位於同一個程式碼段中,並透過 CALL 命令呼叫,目標地址為雙位元組(對於透過 CALL FAR 命令呼叫,目標地址為 4 位元組的子程式,必須使用 RETF 命令,7.03-74)。

RET 命令表示堆疊暫存器頂部包含返回偏移量,即呼叫程式中下一條指令的偏移量。如果終止子程式在堆疊中不留任何內容,則不需要 RET 命令的運算元。但是,子程式可能透過堆疊接受引數,在終止時,必須刪除這些引數。因此,RET 命令的運算元定義了要從堆疊中刪除的位元組數。RET 命令將返回偏移量從堆疊彈出到 IP(指令指標)暫存器,然後將其運算元加到 SP(堆疊指標)暫存器的內容中。這樣就執行了返回到呼叫程式的操作,並且恢復了堆疊頂部的原始位置。RET 命令不會更改標誌的狀態。

第一
byte
第二個位元組 資料
位元組
示例
C2   2 RET ffff
C3     RET
註釋
  1. 如果透過 RET FFFE 命令執行返回,則可以將返回偏移量處的堆疊頂部位置保留。
  2. 如果透過 DEBUG.EXE 彙編的程式碼將在偵錯程式的環境中執行,則可以使用 RET 命令來終止此程式碼的執行(9.02-03 中的示例)。

7.03-74 RETF – 從另一個段返回

[編輯 | 編輯原始碼]

RETF 命令 (RETF = RETurn Far) 執行 RET 命令 (7.03-73) 的所有操作,此外,它還從堆疊中恢復 CS 暫存器中的段地址。因此,實現了從另一個程式碼段返回到呼叫程式的操作。

RETF 命令用作那些透過 CALL FAR 命令 (7.02-08) 從其他程式碼段呼叫的子程式和驅動程式的退出,這些子程式和驅動程式使用完整的 4 位元組地址,以便將呼叫程式的原始段地址儲存到堆疊中。

第一
byte
第二個位元組 資料
位元組
示例
CA   2 RETF ffff
CB     RETF

7.03-75 ROL – 迴圈左移

[編輯 | 編輯原始碼]

ROL 命令 (ROL = ROtate Leftward) 對其第一個運算元進行迴圈左移,向更重要的位位置移動。在每一步中,最低有效位獲取最有效位的“彈出”的先前狀態。CF 和 OV 標誌的狀態根據結果更改,但所有其他標誌保持其先前狀態。

第二個運算元(1 或 CL)定義向左移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (0,4,8)(0-7) 0-2 ROL byte ptr [bp+si+ffff],1
D0 C(0-7)   ROL bl,1
D1 (0,4,8)(0-7) 0-2 ROL word ptr [bp+si+ffff],1
D1 C(0-7)   ROL bx,1
D2 (0,4,8)(0-7) 0-2 ROL byte ptr [bp+si+ffff],CL
D2 C(0-7)   ROL bl,CL
D3 (0,4,8)(0-7) 0-2 ROL word ptr [bp+si+ffff],CL
D3 C(0-7)   ROL bx,CL

7.03-76 ROR – 迴圈右移

[編輯 | 編輯原始碼]

ROR 命令 (ROR = ROtate to the Right) 對其第一個運算元進行迴圈右移,向最低有效位位置移動。在每一步中,最有效位獲取最低有效位的“彈出”的先前狀態。CF 和 OV 標誌的狀態根據結果更改,但所有其他標誌保持其先前狀態。

第二個運算元(1 或 CL)定義向右移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (0,4,8)(8-F) 0-2 ROR byte ptr [bp+si+ffff],1
D0 C(8-F)   ROR bl,1
D1 (0,4,8)(8-F) 0-2 ROR word ptr [bp+si+ffff],1
D1 C(8-F)   ROR bx,1
D2 (0,4,8)(8-F) 0-2 ROR byte ptr [bp+si+ffff],CL
D2 C(8-F)   ROR bl,CL
D3 (0,4,8)(8-F) 0-2 ROR word ptr [bp+si+ffff],CL
D3 C(8-F)   ROR bx,CL

7.03-77 SAHF – 將 AH 複製到標誌暫存器

[編輯 | 編輯原始碼]

SAHF 命令 (SAHF = Store AH in Flags) 將 AH 暫存器中的一個位元組複製到標誌暫存器的下半部分。位 7 將定義 SF(符號標誌)的狀態,位 6 – ZF(零標誌)的狀態,位 4 – AF(輔助標誌)的狀態,位 2 – PF(奇偶標誌)的狀態,位 0 – CF(進位標誌)的狀態。雖然 SAHF 命令沒有定義溢位標誌 OF 的狀態,但它可能會獲得不確定的狀態。AH 暫存器中的位 5、3、1 不對應於實際標誌,它們的狀態將被忽略。

程式碼 示例
9E SAHF

7.03-78 SAR – 有符號整數右移

[編輯 | 編輯原始碼]

SAR 命令 (SAR = Shift Arithmetic to the Right) 將其有符號整數運算元右移,向最低有效位位置移動。在每一步移位中,最右邊的位的狀態將丟失,最左邊的位將獲得符號位的狀態。ZF、PF、CF 標誌根據結果獲取新的狀態。OF 和 AF 標誌獲得不確定的狀態。

第二個運算元(1 或 CL)定義向右移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (3,7,B)(8-F) 0-2 SAR byte ptr [bp+si+ffff],1
D0 F(8-F)   SAR bl,1
D1 (3,7,B)(8-F) 0-2 SAR word ptr [bp+si+ffff],1
D1 F(8-F)   SAR bx,1
D2 (3,7,B)(8-F) 0-2 SAR byte ptr [bp+si+ffff],CL
D2 F(8-F)   SAR bl,CL
D3 (3,7,B)(8-F) 0-2 SAR word ptr [bp+si+ffff],CL
D3 F(8-F)   SAR bx,CL

7.03-79 SBB – 帶借位的二進位制整數減法

[編輯 | 編輯原始碼]

SBB 命令從第一個運算元(被減數)中減去其第二個運算元(減數),同時考慮前一個操作後留下的借位,該借位由 CF(進位標誌)的狀態表示。餘數將替換第一個運算元。OF、SF、ZF、AF、PF、CF 標誌根據結果獲取新的狀態。

SBB 命令留下的標誌狀態的解釋取決於運算元是有符號數還是無符號數。在減去無符號數後,應使用條件跳轉命令 JA、JB、JBE、JNB。在減去有符號數後,應使用其他條件跳轉命令 JG、JGE、JL、JLE。所有條件跳轉和迴圈命令的全名反映了 SBB 命令的第一個(左)運算元與第二個(右)運算元的狀態關係。例如,JA = “如果大於則跳轉”意味著 SBB 命令的左運算元(被減數)必須大於或等於右運算元(減數)。

SBB 是一個二進位制操作,但有兩個例外。如果第一個運算元位於 AX 暫存器中,則 SBB 命令可以應用於非壓縮十進位制字:AX 暫存器中非壓縮十進位制字的二進位制差可以透過 AAS 命令 (7.03-04) 轉換為有效的非壓縮十進位制字。如果第一個運算元位於 AL 暫存器中,則 SBB 命令可以應用於壓縮十進位制位元組:AL 暫存器中壓縮十進位制位元組的二進位制差可以透過 DAS 命令 (7.03-19) 轉換為有效的壓縮十進位制位元組。

第一
byte
第二個位元組 資料
位元組
示例
18 (0-B)(0-F) 0-2 SBB [bp+si+ffff],bl
18 (C-F)(0-F)   SBB bl,bl
19 (0-B)(0-F) 0-2 SBB [bp+si+ffff],bx
19 (C-F)(0-F)   SBB bx,bx
1A (0-B)(0-F) 0-2 SBB bl,[bp+si+ffff]
1B (0-B)(0-F) 0-2 SBB bx,[bp+si+ffff]
1C   1 SBB AL,ff
1D   2 SBB AX,ffff
80 (1,5,9)(8-F) 1-3 SBB byte ptr [bp+si+ffff],ff
80 D(9-F) 1 SBB bl,ff
81 (1,5,9)(8-F) 2-4 SBB word ptr [bp+si+ffff],ffff
81 D(9-F) 2 SBB bx,ffff
83 (1,5,9)(8-F) 1-3 SBB word ptr [bp+si+ffff],±7f
83 D(9-F) 1 SBB bx,±7f
註釋
  1. 程式碼“1(A,B) (C-F)(0-F)” 和 “82 (1,5,9,D)(8-F)” 也被 DEBUG.EXE 作為 SBB 命令進行反彙編。

7.03-80 SCASB – 搜尋特定位元組

[edit | edit source]

儘管 SCASB 的名稱代表“掃描位元組字串”,但實際上 SCASB 命令將 AL 暫存器中的一個位元組與另一個位元組進行比較,另一個位元組從記憶體中讀取。另一個位元組的地址必須事先載入到 ES:DI 暫存器對中。如果位元組相等,ZF(零標誌)被設定為 ZR 狀態。如果位元組不相等,ZF 標誌被清除為 NZ(非零)狀態。標誌 OF、SF、AF、PF、CF 根據比較位元組之間的差異獲取狀態,但差異本身不會被儲存。

比較後,DI(目標索引)暫存器中的偏移量增加或減少 1:這取決於方向標誌 DF 的狀態(“向上”或“向下”)。DF 標誌的狀態可以透過 CLD(7.03-11)和 STD(7.03-85)命令更改。索引暫存器內容的自動更改為將 AL 內容與下一個記憶體單元中的位元組進行比較準備條件。

SCASB 命令通常由重複字首 F2h(7.02-03)或 F3h(7.02-04)引導,這使它能夠迴圈執行,從而在位元組字串中搜索特定位元組。該位元組字串的預設段暫存器 ES 無法透過段覆蓋字首更改。

程式碼 示例
AE SCASB
註釋
  1. 當 SCASB 命令由重複字首 F2h 或 F3h 引導時,迴圈內操作的順序包括分配標誌狀態,然後增加(或減少)索引暫存器的內容,然後檢查迴圈終止條件。因此,DI 暫存器中迴圈終止時的偏移量指向的不是導致迴圈終止的資料位元組,而是下一個位元組。

7.03-81 SCASW – 搜尋特定字

[edit | edit source]

SCASW 命令(SCASW = 掃描字字串)將 AX 暫存器中的一個字與另一個字進行比較,另一個字從記憶體中讀取,然後將另一個字在 DI 索引暫存器中的偏移量增加(或減少) 2,從而準備將 AX 內容與下一個記憶體單元中的字進行比較。運算元大小覆蓋字首 66h(7.02-06)強制 SCASW 命令將 EAX 暫存器中的一個四位元組運算元與相同 DWORD 型別的另一個運算元進行比較,並將 DI 索引暫存器中的偏移量增加(或減少) 4。SCASW 命令執行的其他所有特殊之處與 SCASB 命令(7.03-80)相同。

程式碼 示例
AF SCASW

7.03-82 SHL – 左移

[edit | edit source]

SHL 命令將它的第一個運算元逐步左移,移向更重要的位位置。在每一步中,最高有效位的狀態被移入進位標誌 CF,而最低有效位獲得零(清除)狀態。標誌 SF、ZF、PF 根據結果獲取新狀態。標誌 AF 和 OV 獲取不確定的狀態。

第二個運算元(1 或 CL)定義向左移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (2,6,A)(0-7) 0-2 SHL byte ptr [bp+si+ffff],1
D0 E(0-7)   SHL bl,1
D1 (2,6,A)(0-7) 0-2 SHL word ptr [bp+si+ffff],1
D1 E(0-7)   SHL bx,1
D2 (2,6,A)(0-7) 0-2 SHL byte ptr [bp+si+ffff],CL
D2 E(0-7)   SHL bl,CL
D3 (2,6,A)(0-7) 0-2 SHL word ptr [bp+si+ffff],CL
D3 E(0-7)   SHL bx,CL
C0 E(0-7) 1 參見 註釋 2
C1 E(0-7) 1 參見 註釋 2
註釋
  1. SHL 命令與其他彙編器接受的 SAL 命令完全等效,但 DEBUG.EXE 不接受 SAL 名稱。
  2. ^ a b 自 CPU 模型 80286 起,處理器執行 SHL 命令時明確指定了移位步數。DEBUG.EXE 不知道這種形式的 SHL 命令,但可以透過 DB 指令(7.01-01)作為資料輸入。例如,左移 4 步的機器碼可能如下所示:
    C0 E0 04 = SHL AL,4
    C1 E0 04 = SHL AX,4
    
    最後一個位元組定義了移位步數。要將移位應用於其他暫存器,您需要在第二個位元組(E0h)中新增 表 7.00 中第一行和第二行中顯示的列表中所需暫存器的編號(00h–07h)。

7.03-83 SHR – 右移

[edit | edit source]

SHR 命令將它的第一個運算元逐步右移,移向較低的位位置。在每一步中,最低有效位的狀態被移入進位標誌 CF,而最高有效位獲得零(清除)狀態。標誌 SF、ZF、PF 根據結果獲取新狀態。標誌 AF 和 OV 獲取不確定的狀態。

第二個運算元(1 或 CL)定義向左移位的步數。當移位步數從 CL 暫存器中讀取時,只考慮 5 個最低有效位;因此,最大移位步數為 31。CL 暫存器中預設的移位步數保持不變。

第一
byte
第二個位元組 資料
位元組
示例
D0 (2,6,A)(8-F) 0-2 SHR byte ptr [bp+si+ffff],1
D0 E(8-F)   SHR bl,1
D1 (2,6,A)(8-F) 0-2 SHR word ptr [bp+si+ffff],1
D1 E(8-F)   SHR bx,1
D2 (2,6,A)(8-F) 0-2 SHR byte ptr [bp+si+ffff],CL
D2 E(8-F)   SHR bl,CL
D3 (2,6,A)(8-F) 0-2 SHR word ptr [bp+si+ffff],CL
D3 E(8-F)   SHR bx,CL
C0 E(8-F) 1 參見 註釋 1
C1 E(8-F) 1 參見 註釋 1
註釋
  1. ^ a b 自 CPU 模型 80286 起,處理器執行 SHR 命令時明確指定了移位步數。DEBUG.EXE 不知道這種形式的 SHL 命令,但可以透過 DB 指令(7.01-01)作為資料輸入。例如,右移 4 步的機器碼可能如下所示:
    C0 E8 04 = SHR AL,4
    C1 E8 04 = SHR AX,4
    
    最後一個位元組定義了移位步數。要將移位應用於其他暫存器,您需要在第二個位元組(E0h)中新增 表 7.00 中第一行和第二行中顯示的列表中所需暫存器的編號(00h–07h)。

7.03-84 STC – 設定進位標誌

[edit | edit source]

STC 命令將進位標誌 CF 設定為“CY”(進位)狀態,通常稱為 CF=1。

程式碼 示例
F9 STC

7.03-85 STD – 設定方向標誌

[edit | edit source]

STD 命令將方向標誌 DF 設定為它的非預設狀態“DN”。這意味著在執行字串操作(CMPSB、LODSB、MOVSB、SCASB、STOSB 等)期間,索引暫存器(DI 和/或 SI)中的偏移量計數遞減。

程式碼 示例
FD STD

7.03-86 STI – 設定中斷標誌

[edit | edit source]

STI 命令將中斷標誌 IF 設定為它的預設“EI”(= 啟用中斷)狀態,從而啟用透過中斷控制器接收中斷請求。

程式碼 示例
FB STI
註釋
  1. 如果當前程式的特權級別低於標誌暫存器(A.11-4)中位 0Ch 和 0Dh 定義的 I/O 操作的特權級別,則 STI 命令不會執行。

7.03-87 STOSB – 用位元組填充記憶體

[edit | edit source]

儘管 STOSB 的名稱代表“儲存位元組字串”,但實際上 STOSB 命令將 AL 暫存器中的一個位元組複製到一個記憶體單元中。該記憶體單元的地址必須事先載入到 ES:DI 暫存器對中。STOSB 命令不會更改標誌的狀態。

複製後,DI(目標索引)暫存器中的偏移量增加或減少 1:這取決於方向標誌 DF 的狀態(“向上”或“向下”)。DF 標誌的狀態可以透過 CLD(7.03-11)和 STD(7.03-85)命令更改。索引暫存器內容的自動更改為將 AL 暫存器中的一個位元組複製到下一個記憶體單元中準備條件。STOSB 命令通常由重複字首 F2h(7.02-03)或 F3h(7.02-04)引導,這使它能夠迴圈執行,從而用相同位元組的副本填充一系列記憶體單元。這些記憶體單元的預設段暫存器 ES 無法透過段覆蓋字首更改。

程式碼 示例
AA STOSB

7.03-88 STOSW – 用字填充記憶體

[edit | edit source]

STOSW 命令(STOSW = 儲存字字串)將 AX 暫存器中的一個字複製到記憶體中,記憶體地址由 ES:DI 暫存器對給出,然後將 DI 索引暫存器中的偏移量增加(或減少) 2,從而準備將 AX 內容複製到下一個記憶體單元中。運算元大小覆蓋字首 66h(7.02-06)強制 STOSW 命令將 EAX 暫存器中的一個四位元組 DWORD 型別的運算元複製到記憶體中,並將 DI 索引暫存器中的偏移量增加(或減少) 4。STOSW 命令執行的其他所有特殊之處與 STOSB 命令(7.03-87)相同。

程式碼 示例
AB STOSW

7.03-89 SUB – 二進位制整數減法

[編輯 | 編輯原始碼]

SUB 命令從第一個運算元(被減數)中減去第二個運算元(減數),忽略 CF 標誌(借位)的狀態。餘數替換第一個運算元。標誌 OF、SF、ZF、AF、PF、CF 根據結果獲取新的狀態。

SUB 命令留下的標誌狀態的解釋取決於運算元是有符號數還是無符號數。在減去無符號數之後,應使用條件跳轉命令 JA、JB、JBE、JNB。其他條件跳轉命令 JG、JGE、JL、JLE 應在減去有符號數之後使用。所有條件跳轉和迴圈命令的全名反映了 SUB 命令的第一個(左側)運算元與第二個(右側)運算元的狀態關係。例如,JA = "如果大於則跳轉" 表示 SUB 命令的左側運算元(被減數)必須大於或等於右側運算元(減數)。

SUB 是一個二元運算,但有兩個例外。如果第一個運算元在 AX 暫存器中,那麼 SUB 命令可以應用於非壓縮十進位制字:AX 暫存器中非壓縮十進位制字的二進位制差可以透過 AAS 命令 (7.03-04) 轉換為有效的非壓縮十進位制字。如果第一個運算元在 AL 暫存器中,那麼 SUB 命令可以應用於壓縮十進位制位元組:AL 暫存器中壓縮十進位制位元組的二進位制差可以透過 DAS 命令 (7.03-19) 轉換為有效的壓縮十進位制位元組。

第一
byte
第二個位元組 資料
位元組
示例
28 (0-B)(0-F) 0-2 SUB [bp+si+ffff],bl
28 (C-F)(0-F)   SUB bl,bl
29 (0-B)(0-F) 0-2 SUB [bp+si+ffff],bx
29 (C-F)(0-F)   SUB bx,bx
2A (0-B)(0-F) 0-2 SUB bl,[bp+si+ffff]
2B (0-B)(0-F) 0-2 SUB bx,[bp+si+ffff]
2C   1 SUB AL,ff
2D   2 SUB AX,ffff
80 (2,6,A)(8-F) 1-3 SUB byte ptr [bp+si+ffff],ff
80 E(9-F) 1 SUB bl,ff
81 (2,6,A)(8-F) 2-4 SUB word ptr [bp+si+ffff],ffff
81 E(9-F) 2 SUB bx,ffff
83 (2,6,A)(8-F) 1-3 SUB word ptr [bp+si+ffff],±7f
83 E(9-F) 1 SUB bx,±7f
註釋
  1. 程式碼“2(A,B) (C-F)(0-F)” 和 “82 (2,6,A,E)(8-F)” 也被 DEBUG.EXE 反彙編為 SUB 命令。

7.03-90 TEST – 邏輯測試位狀態

[編輯 | 編輯原始碼]

TEST 命令根據對運算元進行按位邏輯 AND 運算的結果設定標誌 SF(符號標誌)、ZF(零標誌)和 PF(奇偶標誌),但該結果本身不會儲存。TEST 命令的兩個運算元都保持不變。進位標誌 CF 和溢位標誌 OF 被 TEST 命令分別清除為 NC(無進位)和 NV(無溢位)狀態。AF 標誌獲得不確定的狀態。

第一
byte
第二個位元組 資料
位元組
示例
84 (0-B)(0-F) 0-2 TEST [bp+si+ffff],bl
84 (C-F)(0-F)   TEST bl,bl
85 (0-B)(0-F) 0-2 TEST [bp+si+ffff],bx
85 (C-F)(0-F)   TEST bx,bx
A8   1 TEST AL,ff
A9   2 TEST AX,ffff
F6 (0,4,8)(0-7) 1-3 TEST byte ptr [bp+si+ffff],ff
F6 C(1-7) 1 TEST bl,ff
F7 (0,4,8)(0-7) 2-4 TEST word ptr [bp+si+ffff],ffff
F7 C(1-7) 2 TEST bx,ffff

7.03-91 XCHG – 運算元交換

[編輯 | 編輯原始碼]

XCHG 命令交換指定暫存器之間或記憶體單元與暫存器之間的內容。標誌的狀態不會被 XCHG 命令改變。

第一
byte
第二個位元組 資料
位元組
示例
86 (0-B)(0-F) 0-2 XCHG [bp+si+ffff],bl
86 (C-F)(1-7,9-F)   XCHG bl,bl
87 (0-B)(0-F) 0-2 XCHG [bp+si+ffff],bx
87 (C-F)(1-7,9-F)   XCHG bx,bx
  9(1-7)   XCHG bx,AX

7.03-92 XLAT – 表格轉換

[編輯 | 編輯原始碼]

XLAT 命令計算一個和 (AL + BX),然後將 DS:(AL + BX) 地址處的位元組複製到 AL 暫存器中,替換其以前的內容。標誌的狀態和 BX 暫存器的內容不會被 XLAT 命令改變。

XLAT 命令用於透過程式碼表 (最多 256 位元組長) 轉換程式碼,該程式碼表必須事先從 DS:BX 地址開始載入。如果 XLAT 命令之前有適當的段覆蓋字首 (7.02-01),則可以使用其他段暫存器代替預設的段暫存器 DS。

程式碼 示例
D7 XLAT

7.03-93 XOR – 異或邏輯運算

[編輯 | 編輯原始碼]

XOR 命令分析兩個運算元中對應位的對。如果一對中兩個位的狀態相同(都設定或都清除),那麼結果的對應位被清除為 FALSE(零)。如果分析的這對中位的狀態不同,那麼結果的對應位被設定為 TRUE 狀態。結果替換第一個運算元。

標誌 SF、ZF、PF 根據結果獲取新的狀態。標誌 CF 和 OF 分別被清除為 NC(無進位)和 NV(無溢位)狀態。標誌 AF 獲取不確定的狀態。

第一
byte
第二個位元組 資料
位元組
示例
30 (0-B)(0-F) 0-2 XOR [bp+si+ffff],bl
30 (C-F)(0-F)   XOR bl,bl
31 (0-B)(0-F) 0-2 XOR [bp+si+ffff],bx
31 (C-F)(0-F)   XOR bx,bx
32 (0-B)(0-F) 0-2 XOR bl,[bp+si+ffff]
33 (0-B)(0-F) 0-2 XOR bx,[bp+si+ffff]
34   1 XOR AL,ff
35   2 XOR AX,ffff
80 (3,7,B)(0-7) 1-3 XOR byte ptr [bp+si+ffff],ff
80 F(1-7) 1 XOR bl,ff
81 (3,7,B)(0-7) 2-4 XOR word ptr [bp+si+ffff],ffff
81 F(1-7) 2 XOR bx,ffff
83 (3,7,B)(0-7) 1-3 XOR word ptr [bp+si+ffff],±7f
83 F(1-7) 1 XOR bx,±7f
註釋
  1. XOR 命令使用相同的源作為兩個運算元中的每一個的運算元規範通常用於將該源清除為零。
  2. 程式碼“3(2,3) (C-F)(0-F)” 和 “82 (3,7,B,F)(0-7)” 也被 DEBUG.EXE 反彙編為 XOR 命令。

7.04 算術協處理器的命令

[編輯 | 編輯原始碼]

那些彙編器命令,其名稱以字母 "F"(浮點數)開頭,被轉移到數學協處理器以執行。所有現代計算機都能夠執行這些命令,因為它們的協處理器整合在主 CPU 中。

具有過時處理器的計算機,包括一些 486 型號,可能沒有數學協處理器。然後可以透過軟體模擬執行協處理器的命令,但這必須滿足兩個條件 

  • 首先,必須確保在響應每個協處理器的命令時生成對 INT 07 處理程式 (8.01-08) 的呼叫。這是透過在控制暫存器 CR0 (A.11-4) 中設定位 02h(“協處理器模擬”)來實現的。
  • 其次,必須載入適當的 INT 07 處理程式,該處理程式能夠模擬執行協處理器的命令。

在一些舊計算機中,這兩個條件會由於其 BIOS 系統而自動滿足,而在其他一些計算機中,使用者必須對此進行處理。在任何情況下,INT 11 處理程式 (8.01-36, A.11-1) 都報告了算術協處理器的存在與否。

如果您的程式有可能由具有獨立協處理器晶片的舊 CPU 執行,那麼每個協處理器的命令都應以 WAIT 字首 (7.02-05) 開頭,該字首將命令從 CPU 同步到協處理器。現代 CPU 具有整合在硬體中的協處理器,具有硬體同步機制。因此,對於現代 CPU,WAIT 字首是不需要的,允許其存在,但很可能被忽略。

7.04-01 F2XM1 – 2 的分數次冪的近似值

[編輯 | 編輯原始碼]

F2XM1 命令計算一個級數的和,用於在冪指數從 -1 到 +1 的範圍內近似 2 的分數次冪函式。冪指數隱含地準備在協處理器的頂部堆疊暫存器 ST(0) 中。計算的級數和替換 ST(0) 暫存器中的冪指數。最終結果可以透過公式 ST(0) = -1+2^ST(0) 表示。

程式碼 示例
D9 F0 F2XM1

7.04-02 FABS – 絕對值

[編輯 | 編輯原始碼]

FABS 指令將協處理器頂部堆疊暫存器 ST(0) 中的符號位清零,從而使 ST(0) 中的運算元變為正值。

程式碼 示例
D9 E1 FABS

7.04-03 FADD – 實數加法

[edit | edit source]

FADD 指令將從記憶體中讀取的實數值或協處理器暫存器中的任何實數值(如果指定為第二個運算元)新增到協處理器頂部堆疊暫存器 ST(0) 中的另一個實數值或任何其他暫存器 ST(1-7) 中(如果後者指定為第一個運算元)。 如果指定為第一個運算元,則和將替換 ST(0) 或 ST(1-7) 中的先前值。

第一
byte
第二個位元組 資料
位元組
示例
D8 (0,4,8)(0-7) 0-2 FADD dword ptr [bp+si+ffff]
D8 C(0-7)   FADD ST,ST(0-7)
DC (0,4,8)(0-7) 0-2 FADD qword ptr [bp+si+ffff]
DC C(0-7)   FADD ST(1-7),ST

7.04-04 FADDP – 加法和堆疊上移

[edit | edit source]

FADDP 指令(FADDP = “ADD and Pop”)將協處理器頂部堆疊暫存器 ST(0) 中的第二個運算元新增到任何其他指定的堆疊暫存器 ST(1-7) 中的第一個運算元。 和將替換指定的 ST(1-7) 堆疊暫存器中的先前值,然後協處理器堆疊指標加 1,因此對先前 ST(0) 的訪問將丟失,所有其他堆疊暫存器 ST(1-7),包括儲存和的暫存器,將被重新命名為 ST(0-6),就好像它們的編號減 1 一樣。

程式碼 示例
DE C(0-7) FADDP ST(1-7),ST

7.04-05 FBLD – 二進位制轉換載入

[edit | edit source]

FBLD 指令(FBLD = “Binary LoaD”)從記憶體中讀取從指定地址開始的 10 位元組壓縮十進位制整數,每個位元組包含兩位十進位制數。 此十進位制整數將轉換為實數二進位制值,並載入到協處理器暫存器 ST(7) 中,該暫存器此時必須為空。 然後 FBLD 指令將協處理器堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),這樣最後載入的值將出現在頂部堆疊暫存器 ST(0) 中。

第一
byte
第二個位元組 資料
位元組
示例
DF (2,6,A)(0-7) 0-2 FBLD tbyte ptr [bp+si+ffff]
註釋
  1. FBLD 指令不檢查其運算元是否真的是壓縮十進位制數。 如果不是,則執行的二進位制轉換結果無效。
  2. 預設的 10 位元組二進位制實數格式包括尾數(位 0-63)、冪指數(位 64-78)和符號位 79。 透過更改 CWR 暫存器中精度控制欄位的內容 (7.04-35 的註釋 2),協處理器可以切換到 8 位元組雙精度格式(52 位 - 尾數,11 位 - 冪指數)或 4 位元組單精度格式(23 位 - 尾數,8 位 - 冪指數)。

7.04-06 FBSTP – 十進位制轉換儲存

[edit | edit source]

FBSTP 指令(FBSTP = Binary STore and Pop)將協處理器頂部堆疊暫存器 ST(0) 中的實數二進位制值轉換為 10 位元組壓縮十進位制整數,每個位元組包含兩位十進位制數。 轉換包括對小數部分進行舍入。 轉換後的整數將寫入記憶體,從指定的偏移量開始。 然後 FBSTP 指令將協處理器堆疊指標加 1,因此對先前 ST(0) 的訪問將丟失,暫存器 ST(1-7) 被重新命名為 ST(0-6)。

第一
byte
第二個位元組 資料
位元組
示例
DF (3,7,B)(0-7) 0-2 FBSTP tbyte ptr [bp+si+ffff]

7.04-07 FCHS – 改變符號

[edit | edit source]

FCHS 指令反轉協處理器頂部堆疊暫存器 ST(0) 中的實數二進位制值的符號。

程式碼 示例
D9 E0 FCHS

7.04-08 FCLEX – 清除異常標誌

[edit | edit source]

FCLEX 指令清除協處理器狀態字暫存器 SWR 中用於註冊協處理器狀態和異常的位。 特別是,以下位被清除 

位 0 – 無效操作標誌
位 1 – 非規格化運算元標誌
位 2 – 除以零標誌
位 3 – 協處理器溢位標誌
位 4 – 反溢位(丟失結果)標誌
位 5 – 丟失精度標誌
blt 7 – 中斷請求標誌
位 15 – “協處理器繁忙”標誌
程式碼 示例
DB E2 FCLEX

7.04-09 FCOM – 實數比較

[edit | edit source]

FCOM 指令將協處理器頂部堆疊暫存器 ST(0) 中的實數值與指定暫存器或記憶體單元的內容進行比較。 協處理器暫存器 SWR 中的標誌 C0、C2 和 C3 根據結果獲取新的狀態。 首先應檢查 C2 標誌的狀態:C2 = 1 表示不可比較的運算元,因此沒有進一步檢查的意義。 如果運算元相等,則 C3 = 1。 如果 ST(0) 中的值小於另一個運算元,則 C0 = 1。 檢查協處理器 SWR 暫存器中的標誌 C0、C2 和 C3 的方法在文章 7.04-64 中描述。

第一
byte
第二個位元組 資料
位元組
示例
D8 (1,5,9)(0-7) 0-2 FCOM dword ptr [bp+si+ffff]
D8 D(0-7)   FCOM ST(0-7)
DC (1,5,9)(0-7) 0-2 FCOM qword ptr [bp+si+ffff]
註釋
  1. 程式碼“DC D(0-7)”也被 DEBUG.EXE 解碼為 FCOM ST(0-7)。

7.04-10 FCOMP – 比較和堆疊上移

[edit | edit source]

FCOMP 指令執行比較的方式與 FCOM 操作相同(7.04-09),但隨後將協處理器堆疊指標加 1,因此對先前 ST(0) 的訪問將丟失,暫存器 ST(1-7) 被重新命名為 ST(0-6)。

第一
byte
第二個位元組 資料
位元組
示例
D8 (1,5,9)(8-F) 0-2 FCOMP dword ptr [bp+si+ffff]
D8 D(8-F)   FCOMP ST(0-7)
DC (1,5,9)(8-F) 0-2 FCOMP qword ptr [bp+si+ffff]
註釋
  1. 程式碼“DC D(8-F)”和“DE D(0-7)”也被 DEBUG.EXE 解碼為 FCOMP 指令。

7.04-11 FCOMPP – 比較和兩次堆疊上移

[edit | edit source]

FCOMPP 指令比較協處理器堆疊暫存器 ST(0) 和 ST(1) 中的運算元,然後將協處理器堆疊指標加 2,因此對 ST(0) 和 ST(1) 中先前運算元的訪問將丟失。 暫存器 ST(2-7) 被重新命名為 ST(0-5)。 比較結果會影響協處理器 SWR 暫存器中標誌 C0、C2 和 C3 的狀態,就像在 FCOM 指令(7.04-09)之後一樣。

程式碼 示例
DE D9 FCOMPP
註釋
  1. DEBUG.EXE 將程式碼“DE D9”解碼為“FCOMPP ST(1)”,但在彙編時不接受“ST(1)”。

7.04-12 FDECSTP – 遞減堆疊頂部指標

[edit | edit source]

FDECSTP 指令將協處理器堆疊指標減 1,因此暫存器 ST(0-6) 被重新命名為 ST(1-7)。 最後一個堆疊暫存器 ST(7) 被重新命名為 ST(0)。 所有堆疊暫存器的內容仍然可以訪問,並且不會被更改。

程式碼 示例
D9 F6 FDECSTP
註釋
  1. 協處理器堆疊指標是一個三級可逆計數器,涉及狀態字暫存器 SWR 的位 11、12 和 13。
  2. 大多數將資料推入協處理器堆疊的命令都是透過將資料複製到 ST(7) 暫存器並將協處理器堆疊指標減 1 來執行的,這樣 ST(7) 暫存器將被重新命名為 ST(0)。 如果 ST(7) 暫存器最初不為空,則所有此類命令都無法執行。

7.04-13 FDISI – 停用中斷

[edit | edit source]

FDISI 指令停用過時的 8087 算術協處理器的中斷。 由於模型 80287 協處理器不需要此命令並忽略它。

程式碼 示例
DB E1 FDISI

7.04-14 FDIV – 實數除法

[edit | edit source]

FDIV 命令將協處理器棧頂暫存器 ST(0) 中的實數值,或任何非棧頂暫存器 ST(1-7) 中的實數值(如果指定為第一個運算元),除以指定記憶體單元或協處理器其他暫存器中的實數除數(如果指定為第二個運算元)。商將替換 ST(0) 中的被除數,或其他棧暫存器 ST(1-7) 中的被除數,如果它被指定為第一個運算元。

第一
byte
第二個位元組 資料
位元組
示例
D8 (3,7,B)(0-7) 0-2 FDIV dword ptr [bp+si+ffff]
D8 F(0-7)   FDIV ST,ST(0-7)
DC (3,7,B)(0-7) 0-2 FDIV qword ptr [bp+si+ffff]
DC F(8-F)   FDIV ST(1-7),ST

7.04-15 FDIVP – 除並向上移棧

[edit | edit source]

FDIVP 命令將協處理器非棧頂暫存器 ST(1-7) 中的實數值除以棧頂暫存器 ST(0) 中的除數。商將替換非棧頂暫存器 ST(1-7) 中的被除數。然後 FDIVP 命令將協處理器棧指標加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6),包括寫入商的那一個。ST(0) 暫存器被重新命名為 ST(7) 並宣佈為空閒。無法訪問其以前的內容(除數)。

程式碼 示例
DE F(8-F) FDIVP ST(1-7),ST

7.04-16 FDIVR – 反序除法

[edit | edit source]

FDIVR 命令將從記憶體單元中讀取的實數值,或從協處理器棧暫存器中讀取的實數值(如果指定為第二個運算元),除以協處理器棧頂暫存器 ST(0) 中的實數除數,或任何非棧頂暫存器 ST(1-7) 中的實數除數(如果指定為第一個運算元)。商將替換 ST(0) 暫存器中的除數,或非棧頂暫存器 ST(1-7) 中的除數,如果它被指定為第一個運算元。

第一
byte
第二個位元組 資料
位元組
示例
D8 (3,7,B)(8-F) 0-2 FDIVR dword ptr [bp+si+ffff]
D8 F(8-F)   FDIVR ST,ST(0-7)
DC (3,7,B)(8-F) 0-2 FDIVR qword ptr [bp+si+ffff]
DC F(0-7)   FDIVR ST(1-7),ST

7.04-17 FDIVRP – 反序除並向上移棧

[edit | edit source]

FDIVRP 命令將協處理器棧頂暫存器 ST(0) 中的實數值除以任何其他棧暫存器 ST(1-7) 中的除數,用商替換非棧頂暫存器 ST(1-7) 中的除數,然後將協處理器棧指標加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6),包括寫入商的那一個。ST(0) 暫存器被重新命名為 ST(7) 並宣佈為空閒。無法訪問其以前的內容(被除數)。

程式碼 示例
DE F(0-7) FDIVRP ST(1-7),ST

7.04-18 FENI – 啟用中斷

[edit | edit source]

FENI 命令為過時的 8087 算術協處理器啟用中斷。由於 80287 協處理器不需要此命令,因此會忽略它。

程式碼 示例
DB E0 FENI

7.04-19 FFREE – 宣佈暫存器為空閒

[edit | edit source]

FFREE 命令透過將“11”二進位制值寫入協處理器標記暫存器 TWR 的對應位,將指定的協處理器棧暫存器標記為空閒。

程式碼 示例
DD C(0-7) FFREE ST(0-7)
註釋
  1. 程式碼“DF C(0-7)”也被 DEBUG.EXE 解碼為 FFREE 命令。

7.04-20 FIADD – 整數加法

[edit | edit source]

FIADD 命令將指定記憶體單元中的整數加到協處理器棧頂暫存器 ST(0) 中的實數值。和是一個實數值,它替換 ST(0) 暫存器中的以前內容。

第一
byte
第二個位元組 資料
位元組
示例
DA (0,4,8)(0-7) 0-2 FIADD dword ptr [bp+si+ffff]
DE (0,4,8)(0-7) 0-2 FIADD word ptr [bp+si+ffff]

7.04-21 FICOM – 整數比較

[edit | edit source]

FICOM 命令從指定記憶體單元中讀取整數,將其轉換為實數值,並將結果與協處理器棧頂暫存器 ST(0) 中的實數值進行比較。比較本身與 FCOM 命令 (7.04-09) 所執行的比較相同。

第一
byte
第二個位元組 資料
位元組
示例
DA (1,5,9)(0-7) 0-2 FICOM dword ptr [bp+si+ffff]
DE (1,5,9)(0-7) 0-2 FICOM word ptr [bp+si+ffff]

7.04-22 FICOMP – 與整數比較並向上移棧

[edit | edit source]

FICOMP 命令從指定記憶體單元中讀取整數,將其轉換為實數值,並將結果與協處理器棧頂暫存器 ST(0) 中的實數值進行比較。比較本身與 FCOM 命令 (7.04-09) 所執行的比較相同,但隨後 FICOMP 命令將協處理器棧指標加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6)。ST(0) 暫存器被重新命名為 ST(7) 並宣佈為空閒。無法訪問其以前的內容。

第一
byte
第二個位元組 資料
位元組
示例
DA (1,5,9)(8-F) 0-2 FICOMP dword ptr [bp+si+ffff]
DE (1,5,9)(8-F) 0-2 FICOMP word ptr [bp+si+ffff]

7.04-23 FIDIV – 整數除法

[edit | edit source]

FIDIV 命令將協處理器棧頂暫存器 ST(0) 中的實數值除以從指定記憶體單元中讀取的整數除數。商將替換棧頂暫存器 ST(0) 中的被除數。

第一
byte
第二個位元組 資料
位元組
示例
DA (3,7,B)(0-7) 0-2 FIDIV dword ptr [bp+si+ffff]
DE (3,7,B)(0-7) 0-2 FIDIV word ptr [bp+si+ffff]

7.04-24 FIDIVR – 反序整數除法

[edit | edit source]

FIDIVR 命令執行從指定記憶體單元中讀取的整數被除數除以協處理器棧頂暫存器 ST(0) 中的除數。商將替換棧頂暫存器 ST(0) 中的除數。

第一
byte
第二個位元組 資料
位元組
示例
DA (3,7,B)(8-F) 0-2 FIDIVR dword ptr [bp+si+ffff]
DE (3,7,B)(8-F) 0-2 FIDIVR word ptr [bp+si+ffff]

7.04-25 FILD – 整數載入

[edit | edit source]

FILD 命令將從指定記憶體單元中讀取的整數轉換為實數值,並將此值載入到協處理器棧暫存器 ST(7) 中,該暫存器此時必須為空。然後 FILD 命令將協處理器棧指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的值將在棧頂暫存器 ST(0) 中找到。

第一
byte
第二個位元組 資料
位元組
示例
DB (0,4,8)(0-7) 0-2 FILD dword ptr [bp+si+ffff]
DF (0,4,8)(0-7) 0-2 FILD word ptr [bp+si+ffff]
DF (2,6,A)(8-F) 0-2 FILD qword ptr [bp+si+ffff]

7.04-26 FIMUL – 整數乘法

[edit | edit source]

FIMUL 命令將協處理器頂端堆疊暫存器 ST(0) 中的實數乘以從指定記憶體單元讀取的整數值。乘積將替換協處理器頂端堆疊暫存器 ST(0) 中的原值。

第一
byte
第二個位元組 資料
位元組
示例
DA (0,4,8)(8-F) 0-2 FIMUL dword ptr [bp+si+ffff]
DE (0,4,8)(8-F) 0-2 FIMUL word ptr [bp+si+ffff]

7.04-27 FINCSTP – 增量堆疊頂指標

[edit | edit source]

FINCSTP 命令將協處理器的堆疊指標增量 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6)。頂端堆疊暫存器 ST(0) 被重新命名為 ST(7)。所有堆疊暫存器的內容仍然可以訪問且不會被更改。

程式碼 示例
D9 F7 FINCSTP
註釋
  1. 協處理器的堆疊指標是一個三級可逆計數器,涉及狀態字暫存器 SWR 的位 11、12 和 13。
  2. 當其他命令執行協處理器的堆疊指標增量時,頂端堆疊暫存器 ST(0) 在被重新命名為 ST(7) 後將獲得空暫存器的狀態(標記 11b)。因此,對 ST(0) 的原內容的訪問將丟失。此操作通常被稱為將 ST(0) 的內容彈出堆疊。

7.04-28 FINIT – 設定協處理器的初始狀態

[edit | edit source]

FINIT 命令將初始狀態寫入算術協處理器的 CWR、SWR、TWR、IPR 和 DPR 暫存器。控制字暫存器 CWR 獲取狀態 037Fh:它定義運算元的 80 位格式、所有異常的遮蔽和四捨五入到最接近的整數。標籤暫存器 TWR 被設定為 FFFFh 狀態,這意味著所有協處理器的堆疊暫存器都是空閒的。其他協處理器暫存器(SWR、IPR 和 DPR)被清除為 0000h。

程式碼 示例
DB E3 FINIT

7.04-29 FIST – 儲存一個整數

[edit | edit source]

FIST 命令(FIST = Integer STore)從協處理器的頂端堆疊暫存器 ST(0) 讀取一個實數,將其轉換為整數,根據指定的格式四捨五入,並將結果寫入指定的記憶體地址。

第一
byte
第二個位元組 資料
位元組
示例
DB (1,5,9)(0-7) 0-2 FIST dword ptr [bp+si+ffff]
DF (1,5,9)(0-7) 0-2 FIST word ptr [bp+si+ffff]

7.04-30 FISTP – 儲存一個整數並向上移動堆疊

[edit | edit source]

FISTP 命令將 ST(0) 暫存器中轉換後的值儲存到記憶體中,就像 FIST 命令一樣(7.04-29)。除此之外,FISTP 命令將協處理器的堆疊指標增量 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6)。對頂端堆疊暫存器 ST(0) 中的原值的訪問將丟失。

第一
byte
第二個位元組 資料
位元組
示例
DB (1,5,9)(8-F) 0-2 FISTP dword ptr [bp+si+ffff]
DF (1,5,9)(8-F)   FISTP word ptr [bp+si+ffff]
DF (3,7,B)(8-F) 0-2 FISTP qword ptr [bp+si+ffff]

7.04-31 FISUB – 整數減法

[edit | edit source]

FISUB 命令從協處理器的頂端堆疊暫存器 ST(0) 中的實數 - 被減數 - 減去儲存在指定記憶體單元中的整數減數。餘數將替換頂端堆疊暫存器 ST(0) 中的被減數。

第一
byte
第二個位元組 資料
位元組
示例
DA (2,6,A)(0-7) 0-2 FISUB dword ptr [bp+si+ffff]
DE (2,6,A)(0-7) 0-2 FISUB word ptr [bp+si+ffff]

7.04-32 FISUBR – 反向順序減法

[edit | edit source]

FISUBR 命令執行協處理器頂端堆疊暫存器 ST(0) 中的實數減數從儲存在指定記憶體單元中的整數被減數的減法。餘數將替換頂端堆疊暫存器 ST(0) 中的原減數。

第一
byte
第二個位元組 資料
位元組
示例
DA (2,6,A)(8-F) 0-2 FISUBR dword ptr [bp+si+ffff]
DE (2,6,A)(8-F) 0-2 FISUBR word ptr [bp+si+ffff]

7.04-33 FLD – 載入實數

[edit | edit source]

FLD 命令從指定的暫存器或指定的記憶體單元讀取一個實數,並將此值載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後,FLD 命令將協處理器的堆疊指標減量 1;因此,暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),這樣最終載入的實數就位於頂端堆疊暫存器 ST(0) 中。

第一
byte
第二個位元組 資料
位元組
示例
D9 (0,4,8)(0-7) 0-2 FLD dword ptr [bp+si+ffff]
D9 C(0-7)   FLD ST(0-7)
DB (2,6,A)(8-F) 0-2 FLD tbyte ptr [bp+si+ffff]
DD (0,4,8)(0-7) 0-2 FLD qword ptr [bp+si+ffff]

7.04-34 FLD1 – 載入一個單位常數

[edit | edit source]

FLD1 命令將一個單位常數載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後,FLD1 命令將協處理器的堆疊指標減量 1;因此,暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),這樣最終載入的常數就被儲存到頂端堆疊暫存器 ST(0) 中。

程式碼 示例
D9 E8 FLD1

7.04-35 FLDCW – 載入 CWR 暫存器

[edit | edit source]

FLDCW 命令(FLDCW = LoaD Control Word)將 FSTCW 命令(7.04-55)儲存的資料字從指定的記憶體單元複製到協處理器的控制字暫存器 CWR 中。如果此資料字中選定的位已被有意更改,則在使用 FLDCW 命令載入後,更改將生效。

第一
byte
第二個位元組 資料
位元組
示例
D9 (2,6,A)(8-F) 0-2 FLDCW word ptr [bp+si+ffff]
註釋
  1. CWR 暫存器中的位 5-0 代表 SWR 暫存器(7.04-08)中對應位 5-0 中的異常標誌的掩碼。預設情況下,CWR 暫存器中的掩碼被設定,但如果清除掩碼,則異常的發生將呼叫中斷處理程式 INT 75(8.03-75)的請求 IRQ 13,該中斷處理程式必須能夠處理問題。
  2. ^ CWR 暫存器中的位 9 和 8 代表 PC (= 精度控制) 欄位。PC 欄位的預設狀態 11b 定義運算元的 10 位元組格式。PC 欄位的狀態 10b 定義四捨五入到 8 位元組格式,狀態 00b - 四捨五入到 4 位元組格式(7.04-05)。但是,降低精度並不會使計算速度更快。

7.04-36 FLDENV – 載入到服務暫存器

[edit | edit source]

FLDENV(= LoaD ENVironment)根據記錄恢復協處理器服務暫存器(CWR、SWR、TWR、IPR、DPR)的狀態,該記錄從指定地址開始從記憶體讀取。此記錄必須由 FSTENV 命令(7.04-56)預先形成並存儲。

第一
byte
第二個位元組 資料
位元組
示例
D9 (2,6,A)(0-7) 0-2 FLDENV word ptr [bp+si+ffff]

7.04-37 FLDL2E – 載入“log e”常數

[edit | edit source]

FLDL2E 命令將 log e = 1.44269... 常數(即 e = 2.71828... 的以 2 為底的對數)載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後 FLDL2E 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的常數被儲存在頂部堆疊暫存器 ST(0) 中。

程式碼 示例
D9 EA FLDL2E

7.04-38 FLDL2T – 載入“log10”常數

[edit | edit source]

FLDL2T 命令將 log10 = 3.32192... 常數(即 10 的以 2 為底的對數)載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後 FLDL2T 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的常數被儲存在頂部堆疊暫存器 ST(0) 中。

程式碼 示例
D9 E9 FLDL2T

7.04-39 FLDLG2 – 載入“lg2”常數

[edit | edit source]

FLDLG2 命令將 lg2 = 0.301029... 常數(即 2 的以 10 為底的對數)載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後 FLDLG2 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的常數被儲存在頂部堆疊暫存器 ST(0) 中。

程式碼 示例
D9 EC FLDLG2

7.04-40 FLDLN2 – 載入“ln2”常數

[edit | edit source]

FLDLN2 命令將 ln2 = 0.693147... 常數(即 2 的以 e = 2.71828... 為底的對數)載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後 FLDLN2 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的常數被儲存在頂部堆疊暫存器 ST(0) 中。

程式碼 示例
D9 ED FLDLN2

7.04-41 FLDPI – 載入“PI”常數

[edit | edit source]

FLDPI 命令將 PI = 3.14159... 常數載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後 FLDPI 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的常數被儲存在頂部堆疊暫存器 ST(0) 中。

程式碼 示例
D9 EB FLDPI

7.04-42 FLDZ – 載入零常數

[edit | edit source]

FLDZ 命令將 0(即零)常數載入到協處理器的堆疊暫存器 ST(7) 中,該暫存器此時必須為空。然後 FLDZ 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後載入的常數被儲存在頂部堆疊暫存器 ST(0) 中。

程式碼 示例
D9 EE FLDZ

7.04-43 FMUL – 實數相乘

[edit | edit source]

FMUL 命令將協處理器頂部堆疊暫存器 ST(0) 中的實數或任何非頂部暫存器 ST(1-7) 中的實數(如果指定為第一個運算元),乘以另一個實數 - 乘數,該乘數從記憶體讀取或從其他堆疊暫存器讀取,如果指定為第二個運算元。乘積替換頂部堆疊暫存器 ST(0) 或其他堆疊暫存器 ST(1-7) 中的先前內容,如果指定為第一個運算元。

第一
byte
第二個位元組 資料
位元組
示例
D8 (0,4,8)(8-F) 0-2 FMUL dword ptr [bp+si+ffff]
D8 C(8-F)   FMUL ST,ST(0-7)
DC (0,4,8)(8-F) 0-2 FMUL qword ptr [bp+si+ffff]
DC C(8-F)   FMUL ST(1-7),ST

7.04-44 FMULP – 乘法並向上移位堆疊

[edit | edit source]

FMULP 命令將指定協處理器非頂部堆疊暫存器 ST(1-7) 中的實數乘以頂部堆疊暫存器 ST(0) 中的實數乘數。乘積覆蓋指定非頂部堆疊暫存器 ST(1-7) 中的先前值。然後 FMULP 命令將協處理器的堆疊指標加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6),包括寫入乘積的那個暫存器。ST(0) 暫存器被重新命名為 ST(7) 並被宣佈為可用。對以前內容(乘數)的訪問已丟失。

程式碼 示例
DE С(8-F) FMULP ST(1-7),ST

7.04-45 FNOP – 空操作

[edit | edit source]

雖然 FNOP 命令已知什麼也不做,但實際上它將 IP(指令指標)加 2,因為 FNOP 命令的機器碼本身佔用 2 個位元組,因此 IP 指向下一個命令。

程式碼 示例
D9 D0 FNOP

7.04-46 FPATAN – 部分反正切

[edit | edit source]

FPATAN 命令將協處理器頂部堆疊暫存器 ST(0) 中的正實數被除數除以堆疊暫存器 ST(1) 中的正實數除數。除數必須等於或大於被除數。商用於計算以弧度為單位的 Arctg(ST(0)/ST(1)) 函式的近似值。結果替換堆疊暫存器 ST(1) 中的除數,然後 FPATAN 命令將協處理器的堆疊指標加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6)。以前 ST(1) 暫存器(寫入結果的暫存器)變為頂部堆疊暫存器 ST(0)。對 ST(0) 暫存器(除數)先前內容的訪問已丟失。

程式碼 示例
D9 F3 FPATAN

7.04-47 FPREM – 部分餘數

[edit | edit source]

FPREM 命令的主要功能是將週期性三角函式的引數簡化為其主區間的限制。FPREM 命令將協處理器頂層堆疊暫存器 ST(0) 中的實數被除數除以堆疊暫存器 ST(1) 中的實數除數。餘數替換頂層堆疊暫存器 ST(0) 中的被除數。如果此餘數大於 ST(1) 暫存器中的除數,則它被視為部分餘數,並透過設定 SWR 暫存器中的標誌 C2 = 1 來標記。在這種情況下,FPREM 命令應重複執行,直到 SWR 暫存器中標誌 C2 的清除狀態指示獲得最終餘數。

獲得最終餘數後,SWR 暫存器中標誌 C3、C1 和 C0 的狀態指向與三角函式引數的最終值相對應的圓的扇區。在協處理器 SWR 暫存器中檢查標誌 C3、C2、C1 和 C0 的方式在第 7.04-64 條中進行了描述。

程式碼 示例
D9 F8 FPREM

7.04-48 FPTAN – 部分正切

[編輯 | 編輯原始碼]

FPTAN 命令在協處理器頂層堆疊暫存器 ST(0) 中接受以弧度表示的角引數,用於計算 Tg(ST(0)) 值的近似值。FPTAN 命令將協處理器的堆疊指標減 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),角引數出現在暫存器 ST(1) 中。計算出的正切函式值替換暫存器 ST(1) 中的引數,並將一個單位常數寫入暫存器 ST(0)。如果 SWR 暫存器中的成功位 C2 被清除為 0,否則它被設定為 1。

程式碼 示例
D9 F2 FPTAN
註釋
  1. 如果協處理器的堆疊暫存器 ST(7) 不為空,則堆疊指標不能遞減,然後 FPTAN 命令將不會執行。
  2. 過時的算術協處理器(最高到 80287 型號)要求 FPTAN 命令的引數在 0 到 PI/4 的範圍內。

7.04-49 FRNDINT – 四捨五入到整數

[編輯 | 編輯原始碼]

FRNDINT 命令透過舍入操作將協處理器頂層堆疊暫存器 ST(0) 中的實數值轉換為整數。舍入方式取決於 CWR 暫存器中 RC(舍入控制)欄位的狀態:如果 RC=00 – 四捨五入到最接近的整數,如果 RC=01 – 四捨五入到最接近的較小整數,如果 RC=10 – 四捨五入到最接近的較大整數,如果 RC=11 – 四捨五入透過省略原始實數值的小數部分。

程式碼 示例
D9 FC FRNDINT
註釋
  1. 協處理器 CWR 暫存器中的位 11 和 10 構成 RC(舍入控制)欄位。CWR 暫存器中所有位的狀態可以透過 FSTCW 命令(7.04-55)寫入記憶體,然後可以有意地更改所需位的狀態。更改後的狀態在透過 FLDCW 命令(7.04-35)載入回 CWR 暫存器後生效。

7.04-50 FRSTOR – 恢復協處理器的狀態

[編輯 | 編輯原始碼]

FRSTOR 命令(FRSTOR = ReSTORe)從長度為 96 或 108 位元組的記錄中載入所有協處理器暫存器的狀態,包括控制暫存器和堆疊,從指定的記憶體地址開始。此記錄必須事先由 FSAVE 命令(7.04-51)儲存在記憶體中。此記錄的實際長度取決於 CPU 的模式:真實模式或保護模式。因此,重要的是在完全與儲存此記錄的 CPU 模式相同的模式下執行協處理器狀態的恢復。

第一
byte
第二個位元組 資料
位元組
示例
DD (2,6,A)(0-7) 0-2 FRSTOR [bp+si+ffff]

7.04-51 FSAVE – 儲存協處理器的狀態

[編輯 | 編輯原始碼]

FSAVE 命令在計算機記憶體中儲存所有堆疊暫存器和算術協處理器中的控制暫存器的狀態,從指定的地址開始,然後重置協處理器的暫存器 CWR、SWR、TWR、IPR、DPR,就像 FINIT 命令所做的那樣(7.04-28)。由 FSAVE 命令形成的整個記錄長度為 96 或 108 位元組 - 這取決於 CPU 的模式:真實模式或保護模式。稍後,此記錄可以透過 FRSTOR 命令(7.04-50)讀取,這使能夠恢復協處理器的先前狀態。

第一
byte
第二個位元組 資料
位元組
示例
DD (3,7,B)(0-7) 0-2 FSAVE [bp+si+ffff]

7.04-52 FSCALE – 乘以 2 的冪

[編輯 | 編輯原始碼]

FSCALE 命令將協處理器頂層堆疊暫存器 ST(0) 中的實數值乘以 2 的冪,其中冪指數為整數,可以是正數或負數。冪指數必須在 ST(1) 暫存器中作為實數值準備。如果它不是整數,它將四捨五入到最接近的較小整數。最終的乘積替換頂層堆疊暫存器 ST(0) 中的第一個乘數。

程式碼 示例
D9 FD FSCALE

7.04-53 FSQRT – 平方根

[編輯 | 編輯原始碼]

FSQRT 計算協處理器頂層堆疊暫存器 ST(0) 中的正實數值的平方根。平方根值替換頂層堆疊暫存器 ST(0) 中的運算元。

程式碼 示例
D9 FA FSQRT

7.04-54 FST – 儲存實數值

[編輯 | 編輯原始碼]

FST 命令將協處理器頂層堆疊暫存器 ST(0) 中的實數值複製到任何其他堆疊暫存器 ST(1-7) 中,或者根據指定的地址和格式複製到記憶體中。如果指定的格式比協處理器堆疊暫存器中的原始 10 位元組格式短,則儲存的值將根據指定的格式進行舍入。

第一
byte
第二個位元組 資料
位元組
示例
D9 (1,5,9)(0-7) 0-2 FST dword ptr [bp+si+ffff]
DD (1,5,9)(0-7) 0-2 FST qword ptr [bp+si+ffff]
DD D(0-7)   FST ST(1-7)
註釋
  1. 程式碼“DF D(0-7)”也被 DEBUG.EXE 解碼為 FST 命令。
  2. FST 命令使能夠將新內容複製到非空堆疊暫存器中。該暫存器的舊內容將被覆蓋。

7.04-55 FSTCW – 儲存 CWR 暫存器的狀態

[編輯 | 編輯原始碼]

FSTCW 命令將協處理器控制暫存器 CWR 的當前狀態複製到一個數據字中,該資料字儲存在記憶體中,根據指定的地址。

第一
byte
第二個位元組 資料
位元組
示例
D9 (3,7,B)(8-F) 0-2 FSTCW [bp+si+ffff]
註釋
  1. 稍後,可以透過 FLDCW 命令(7.04-35)恢復儲存的 CWR 暫存器狀態。

7.04-56 FSTENV – 儲存服務暫存器的狀態

[編輯 | 編輯原始碼]

FSTENV(= 儲存環境)命令將所有協處理器服務暫存器的狀態寫入記憶體,從指定的地址開始:CWR(控制字暫存器)、SWR(狀態字暫存器)、TWR(標籤字暫存器)、IPR(指令指標暫存器)、DPR(資料指標暫存器)。與 FSAVE 命令(7.04-51)相反,FSTENV 命令不會重置協處理器的服務暫存器,也不會儲存堆疊暫存器的內容。由 FSTENV 命令形成的記錄中的資料可以稍後用於透過 FLDENV 命令(7.04-36)恢復服務暫存器的先前狀態。

第一
byte
第二個位元組 資料
位元組
示例
D9 (3,7,B)(0-7) 0-2 FSTENV [bp+si+ffff]

7.04-57 FSTP – 儲存並向上移動堆疊

[編輯 | 編輯原始碼]

FSTP 命令將協處理器頂層堆疊暫存器 ST(0) 中的實數值複製到任何其他堆疊暫存器 ST(1-7) 中,該暫存器不一定是空閒的,或者根據指定的地址和格式複製到記憶體中。如果指定的格式比協處理器堆疊暫存器中的原始 10 位元組格式短,則儲存的值將根據指定的格式進行舍入。然後 FSTP 命令將協處理器的堆疊指標加 1,使得暫存器 ST(1-7) 被重新命名為 ST(0-6)。ST(0) 暫存器被重新命名為 ST(7) 並被宣佈為空閒。無法訪問 ST(0) 暫存器的舊內容。

第一
byte
第二個位元組 資料
位元組
示例
D9 (1,5,9)(8-F) 0-2 FSTP dword ptr [bp+si+ffff]
DB (3,7,B)(8-F) 0-2 FSTP tbyte ptr [bp+si+ffff]
DD (1,5,9)(8-F) 0-2 FSTP qword ptr [bp+si+ffff]
DD D(8-F)   FSTP ST(1-7)
註釋
  1. 程式碼“D9 D(8-F)”和“DF D(8-F)”也被 DEBUG.EXE 解碼為 FSTP 命令。

7.04-58 FSTSW – 儲存狀態字

[編輯 | 編輯原始碼]

FSTSW 指令將協處理器狀態字暫存器 SWR 的狀態複製到指定的地址,主要用於分析比較後的結果。SWR 暫存器中一些位的角色在文章 7.04-08 和 7.04-64 中有描述。

第一
byte
第二個位元組 資料
位元組
示例
DD (3,7,B)(8-F) 0-2 FSTSW [bp+si+ffff]
DF E0   ESC 3C,AL [注意 1]
註釋
  1. ^ 80486 及更高版本的 CPU 執行 FSTSW AX 操作(程式碼 "DF E0"),將協處理器狀態字複製到 CPU 的 AX 暫存器中。此操作對於 DEBUG.EXE 來說是“未知”的,但 DEBUG.EXE 在其舊名稱 ESC 3C,AL 下接受它。

7.04-59 FSUB – 實數減法

[編輯 | 編輯原始碼]

FSUB 指令(FSUB = SUBtract)從協處理器頂部的堆疊暫存器 ST(0) 中的實數被減數(如果它被指定為第二個運算元)中減去一個實數減數,該實數減數儲存在記憶體單元或協處理器堆疊暫存器 ST(0-7) 中。如果減數被指定為第一個運算元,則從協處理器頂部的堆疊暫存器 ST(0) 或其他堆疊暫存器 ST(1-7) 中的實數被減數中減去。餘數替換協處理器頂部的堆疊暫存器 ST(0) 中的被減數或其他堆疊暫存器 ST(1-7) 中的被減數,如果它被指定為第一個運算元。

第一
byte
第二個位元組 資料
位元組
示例
D8 (2,6,A)(0-7) 0-2 FSUB dword ptr [bp+si+ffff]
D8 E(8-F)   FSUB ST,ST(0-7)
DC (2,6,A)(0-7) 0-2 FSUB qword ptr [bp+si+ffff]
DC E(8-F)   FSUB ST(1-7),ST

7.04-60 FSUBP – 減並向上移位堆疊

[編輯 | 編輯原始碼]

FSUBP 指令從協處理器頂部的堆疊暫存器 ST(0) 中的另一個實數值(被減數)中減去一個實數值(減數),該實數值儲存在指定的協處理器非頂部的堆疊暫存器 ST(1-7) 中。餘數將覆蓋指定的非頂部的堆疊暫存器 ST(1-7) 中的被減數。然後 FSUBP 指令將協處理器的堆疊指標增加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6),包括寫入餘數的那個暫存器。ST(0) 暫存器被重新命名為 ST(7) 並被宣佈為可用。對它的以前內容(減數)的訪問將丟失。

程式碼 示例
DE E(8-F) FSUBP ST(1-7),ST

7.04-61 FSUBR – 逆序減法

[編輯 | 編輯原始碼]

FSUBR 指令從指定的記憶體單元或另一個協處理器堆疊暫存器中儲存的實數被減數(指定為第二個運算元)中減去一個實數值(減數),該實數值儲存在協處理器頂部的堆疊暫存器 ST(0) 中,或者儲存在任何非頂部的堆疊暫存器 ST(1-7) 中(如果它被指定為第一個運算元)。餘數替換協處理器頂部的堆疊暫存器 ST(0) 中的減數,或者替換其他堆疊暫存器 ST(1-7) 中的減數,如果它被指定為第一個運算元。

第一
byte
第二個位元組 資料
位元組
示例
D8 (2,6,A)(8-F) 0-2 FSUBR dword ptr [bp+si+ffff]
D8 E(0-7)   FSUBR ST,ST(0-7)
DC (2,6,A)(8-F) 0-2 FSUBR qword ptr [bp+si+ffff]
DC E(0-7)   FSUBR ST(1-7),ST

7.04-62 FSUBRP – 逆序減並向上移位堆疊

[編輯 | 編輯原始碼]

FSUBRP 指令從任何協處理器非頂部的堆疊暫存器 ST(1-7) 中的實數減數中減去一個實數值(減數),該實數值從頂部的堆疊暫存器 ST(0) 中的實數被減數中減去。餘數將替換協處理器非頂部的堆疊暫存器 ST(1-7) 中的減數。然後 FSUBRP 指令將協處理器的堆疊指標增加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6),包括寫入餘數的那個暫存器。ST(0) 暫存器被重新命名為 ST(7) 並被宣佈為可用。對它的以前內容(被減數)的訪問將丟失。

程式碼 示例
DE E(0-7) FSUBRP ST(1-7),ST

7.04-63 FTST – 與零比較

[編輯 | 編輯原始碼]

FTST (= TeST) 指令將協處理器頂部的堆疊暫存器 ST(0) 中的實數值與零常數進行比較。協處理器狀態字暫存器 SWR 中的標誌 C3、C2 和 C0 的狀態根據結果進行更改。首先應檢查標誌 C2 的狀態:如果 C2 = 1,則運算元不可比較,因此沒有進一步檢查的意義。標誌 C3 = 1 表示相等,即頂部的堆疊暫存器 ST(0) 中的值為零。標誌 C0 = 1 表示頂部的堆疊暫存器 ST(0) 中的值為負數。如果頂部的堆疊暫存器 ST(0) 包含一個正實數,則所有三個標誌 C3、C2、C0 都將被清除為零。在協處理器 SWR 暫存器中檢查標誌 C0、C2、C3 的方法在文章 7.04-64 中有描述。

程式碼 示例
D9 E4 FTST

7.04-64 FXAM – 運算元型別檢查

[編輯 | 編輯原始碼]

FXAM (= eXAMine) 指令確定協處理器頂部的堆疊暫存器 ST(0) 中運算元的型別。協處理器狀態字暫存器 SWR 中的標誌 C3、C2、C1 和 C0 的狀態指示結果。標誌 C1 反映運算元的符號。標誌 C3、C2 和 C0 的狀態解釋在下表中給出

C3 C2 C0 運算元型別
0 0 0 - 未知格式
0 0 1 - 任何非數字格式
0 1 0 - 正確的實數
0 1 1 - 無窮大 (tag = 10)
1 0 0 - 零 (tag = 01)
1 0 1 - 空的 ST(0) 暫存器 (tag = 11)。
1 1 0 - 任何非規格化數

為了分析結果,狀態字應該透過 FSTSW 指令 (7.04-58) 從協處理器的 SWR 暫存器中複製到 CPU 的 AX 暫存器中(最好)。然後,狀態可以被 TEST 指令 (7.03-90) 測試,也可以透過 SAHF 指令 (7.03-77) 載入到 CPU 的標誌中。由於標誌 C0、C1、C2、C3 在 SWR 暫存器(以及 AX 暫存器)中分別由位 08、09、10 和 14 表示,所以在 AH 暫存器中,相同的標誌分別由位 0、1、2、6 表示。透過 SAHF 指令載入到 CPU 的標誌後,C3 標誌的狀態由 CPU 的零標誌 ZF 表示,C2 標誌的狀態由 CPU 的奇偶標誌 PF 表示,C0 標誌的狀態由 CPU 的進位標誌 CF 表示。

程式碼 示例
D9 E5 FXAM

7.04-65 FXCH – 暫存器內容交換

[編輯 | 編輯原始碼]

FXCH (= eXCHange) 指令交換協處理器頂部的堆疊暫存器 ST(0) 與任何其他指定的堆疊暫存器 ST(1-7) 之間的內容。

程式碼 示例
D9 C(8-F) FXCH ST(1-7)
註釋
  1. 程式碼 "DD C(8-F)" 和 "DF C(8-F)" 也被 DEBUG.EXE 解碼為 FXCH 指令。

7.04-66 FXTRACT – 分離尾數和指數

[編輯 | 編輯原始碼]

FXTRACT (= eXTRACT) 指令將協處理器頂部的堆疊暫存器 ST(0) 中的實數值分解為它的尾數(即有效數字)和二進位制指數(即二進位制冪指數)。尾數被寫入堆疊暫存器 ST(7) 中,該暫存器在此時必須為空。指數替換頂部的堆疊暫存器 ST(0) 中的原始值。然後 FXTRACT 指令將協處理器的堆疊指標減少 1;因此暫存器 ST(0-6) 被重新命名為 ST(1-7),暫存器 ST(7) 被重新命名為 ST(0),因此最後尾數出現在協處理器頂部的堆疊暫存器 ST(0) 中,而指數出現在暫存器 ST(1) 中。

程式碼 示例
D9 F4 FXTRACT

7.04-67 FYL2X – 任意底的對數

[編輯 | 編輯原始碼]

FYL2X 指令計算協處理器頂部的堆疊暫存器 ST(0) 中正實數值的以 2 為底的對數,然後將對數乘以暫存器 ST(1) 中的實數乘數。乘法可以將以 2 為底的對數轉換為任何任意底。積覆蓋暫存器 ST(1) 中的乘數。然後 FYL2X 指令將協處理器的堆疊指標增加 1,因此暫存器 ST(1-7) 被重新命名為 ST(0-6)。寫入積的那個暫存器成為頂部的堆疊暫存器 ST(0)。以前的 ST(0) 暫存器被重新命名為 ST(7) 並被宣佈為可用,對其內容的訪問將丟失。FYL2X 指令的最終結果由公式 ST(0)=ST(1)•log(ST(0)) 表示。

程式碼 示例
D9 F1 FYL2X

7.04-68 FYL2XP1 – 級數對數的和

[編輯 | 編輯原始碼]

FYL2XP1 命令計算任意底的對數,與 FYL2X 命令 (7.04-67) 一樣,但 FYL2XP1 命令暗示其協處理器頂端堆疊暫存器 ST(0) 中的引數是由 F2XM1 命令 (7.04-01) 計算的級數和。為了獲得高精度的計算,該級數和必須在 (−1 + 1/SQRT2) 到 (−1 + SQRT2) 的範圍內,對應於以 2 為底的對數的值從 −1/2 到 +1/2。協處理器堆疊指標的進一步乘以堆疊暫存器 ST(1) 中的乘數和增量操作與 FYL2X 命令 (7.04-67) 中的操作相同。計算的對數保留在頂端堆疊暫存器 ST(0) 中。FYL2XP1 命令的最終結果由公式 ST(0)=ST(1)•log(1+ST(0)) 表示。

程式碼 示例
D9 F9 FYL2XP1
華夏公益教科書