汇编语言加法和减法详解
算術運算是匯編語言中一個大得令人驚訝的主題!本節重點在于加法和減法的運算。
?
先從最簡單、最有效的指令開始:INC(增加)和 DEC(減少)指令,即加 1 和減 1。然后是能提供更多操作的 ADD、SUB 和 NEG(非)指令。最后,將討論算術運算指令如何影響 CPU 狀態標志位(進位位、符號位、零標志位等)。請記住,匯編語言的細節很重要。
INC 和 DEC 指令
INC(增加)和DEC(減少)指令分別表示寄存器或內存操作數加 1 和減 1。語法如下所示:
INC reg/mem
DEC reg/mem
下面是一些例子:
.data myWord WORD 1000h .code inc myWord ; myWord = 1001h mov bx,myWord dec bx ; BX = 1000h根據目標操作數的值,溢岀標志位、符號標志位、零標志位、輔助進位標志位、進位標志位和奇偶標志位會發生變化。INC 和 DEC 指令不會影響進位標志位(這還真讓人吃驚)。
ADD 指令
ADD 指令將長度相同的源操作數和目的操作數進行相加操作。語法如下:
ADD dest,source
在操作中,源操作數不能改變,相加之和存放在目的操作數中。該指令可以使用的操作數與 MOV 指令相同。下面是兩個 32 位整數相加的短代碼示例:
.data var1 DWORD 10000h var2 DWORD 20000h .code mov eax,var1 ; EAX = 10000h add eax,var2 ; EAX = 30000h標志位:進位標志位、零標志位、符號標志位、溢出標志位、輔助進位標志位和奇偶標 志位根據存入目標操作數的數值進行變化。
SUB 指令
SUB 指令從目的操作數中減去源操作數。該指令對操作數的要求與 ADD 和 MOV 指令相同。指令語法如下:
SUB dest, source
下面是兩個 32 位整數相減的短代碼示例:
.data var1 DWORD 30000h var2 DWORD 10000h .code mov eax,var1 ;EAX = 30000h sub eax,var2 ;EAX = 20000h標志位:進位標志位、零標志位、符號標志位、溢出標志位、輔助進位標志位和奇偶標 志位根據存入目標操作數的數值進行變化。
NEG 指令
NEG(非)指令通過把操作數轉換為其二進制補碼,將操作數的符號取反。下述操作數可以用于該指令:
NEG reg
NEG mem
提示:將目標操作數按位取反再加 1,就可以得到這個數的二進制補碼。
標志位:進位標志位、零標志位、符號標志位、溢出標志位、輔助進位標志位和奇偶標志位根據存入目標操作數的數值進行變化。
執行算術表達式
使用 ADD、SUB 和 NEG 指令,就有辦法來執行匯編語言中的算術表達式,包括加法、減法和取反。換句話說,當有下述表達式時,就可以模擬 C++ 編譯器的行為:
Rval = -Xval + (Yval – Zval);
現在來看看,使用如下有符號 32 位變量,匯編語言是如何執行上述表達式的。
Rval SDWORD ?
Xval SDWORD 26
Yval SDWORD 30
Zval SDWORD 40
轉換表達式時,先計算每個項,最后再將所有項結合起來。首先,對 Xval 的副本進行取反,并存入寄存器:
; first term: -Xval mov eax,Xval neg eax ; EAX = -26然后,將 Yval 復制到寄存器中,再減去 Zval:
; second term: (Yval - Zval) mov ebx,Yval sub ebx,Zval ; EBX = -10最后,將兩個項(EAX 和 EBX 的內容)相加:
; add the terms and store: add eax,ebx mov Rval,eax ; -36加減法影響的標志位
執行算術運算指令時,常常想要了解結果。它是負數、正數還是零?對目的操作數來說,它是太大,還是太小?這些問題的答案有助于發現計算錯誤,否則可能會導致程序的錯誤行為。
檢查算術運算結果使用的是 CPU 狀態標志位的值,同時,這些值還可以觸發條件分支指令,即基本的程序邏輯工具。下面是對狀態標志位的簡要概述:
- 進位標志位意味著無符號整數溢出。比如,如果指令目的操作數為 8 位,而指令產生的結果大于二進制的 1111 1111,那么進位標志位置 1。
- 溢出標志位意味著有符號整數溢出。比如,指令目的操作數為 16 位,但其產生的負數結果小于十進制的 -32 768,那么溢出標志位置 1。
- 零標志位意味著操作結果為 0。比如,如果兩個值相等的操作數相減,則零標志位置 1。
- 符號標志位意味著操作產生的結果為負數。如果目的操作數的最高有效位(MSE)置 1,則符號標志位置 1。
- 奇偶標志位是指,在一條算術或布爾運算指令執行后,立即判斷目的操作數最低有效字節中 1 的個數是否為偶數。
- 輔助進位標志位置 1,意味著目的操作數最低有效字節中位 3 有進位。
要在調試時顯示 CPU 狀態標志位,打開 Register 窗口,右鍵點擊該窗口,并選擇 Flags。
1) 無符號數運算:零標志位、進位標志位和輔助進位標志位
當算術運算結果等于 0 時,零標志位置 1。下面的例子展示了執行 SUB、INC 和 DEC 指令后,目的寄存器和零標志位的狀態:
mov ecx,1 sub ecx,1 ;ECX = 0, ZF = 1 mov eax,0FFFFFFFFh inc eax ;EAX = 0, ZF = 1 inc eax ;EAX = 1, ZF = 0 dec eax ;EAX = 0, ZF = 1加法和進位標志位,如果將加法和減法分開考慮,那么進位標志位的操作是最容易解釋的。兩個無符號整數相加時,進位標志位是目的操作數最高有效位進位的副本。直觀地說,如果和數超過了目的操作數的存儲大小,就可以認為 CF = 1。在下面的例子里,ADD 指令將進位標志位置 1,原因是,相加的和數(100h)超過了 AL 的大小:
mov al,0FFh add al,1 ; AL = 00, CF = 1下圖演示了在 0FFh 上加 1 時,操作數的位是如何變化的。AL 最高有效位的進位復制到進位 標志位。
另一方面,如果 AX 的值為 00FFh,則對其進行加 1 操作后,和數不會超過 16 位,那么進位標志位清 0:
mov ax,00FFh add ax, 1 ; AX = 0100h, CF = 0但是,如果 AX 的值為 FFFFh,則對其進行加 1 操作后,AX 的高位就會產生進位:
mov ax,0FFFFh add ax, 1 ; AX = 0000, CF = 1減法和進位標志位,從較小的無符號整數中減去較大的無符號整數時,減法操作就會將進位標志位置 1。下圖說明了,操作數為 8 位時,計算(1-2)會出現什么情況。下面是相應的匯編代碼:
mov al, 1 sub al,2 ; AL = FFh, CF = 1?
提示:INC 和 DEC 指令不會影響進位標志位。在非零操作數上應用 NEG 指令總是會將進位標志位置 1。
輔助進位標志位,輔助進位(AC)標志位意味著目的操作數位 3 有進位或借位。它主要用于二進制編碼的十進制數(BCD)運算,也可以用于其他環境。現在,假設計算(1+0Fh),和數在位 4 上為 1,這是位 3 的進位:
mov al,0Fh add al, 1 ; AC = 1計算過程如下:
??? 00001111
+? 00000001
————–
??? 00010000
奇偶標志位,目的操作數最低有效字節中 1 的個數為偶數時,奇偶(PF)標志位置 1。下例中,ADD 和 SUB 指令修改了 AL 的奇偶性:
mov al,10001100b add al,00000010b ; AL = 10001110, PF = 1 sub al,10000000b ; AL = 00001110, PF = 0執行了 ADD 指令后,AL 的值為 1000 1110 (4 個 0, 4 個 1), PF=1。執行了 SUB 指令后,AL 的值包含了奇數個 1,因此奇偶標志位等于 0。
2) 有符號數運算:符號標志位和溢出標志位
符號標志位,有符號數算術操作結果為負數,則符號標志位置 1。下面的例子展示的是小數(4)減去大數(5):
mov eax, 4 sub eax,5 ; EAX = -1, SP = 1從機器的角度來看,符號標志位是目的操作數高位的副本。下面的例子表示產生了負數結果后,BL 中的十六進制的值:
mov bl,1 ; BL = 01h sub bl,2 ; BL = FFh(-1), SF = 1溢出標志位,有符號數算術操作結果與目的操作數相比,如果發生上溢或下溢,則溢出標志位置 1。例如,8 位有符號整數的最大值為 +127,再加 1 就會溢出:
mov al,+127 add al, 1 ; OF = 1同樣,最小的負數為-128,再減1就發生下溢。如果目的操作數不能容納一個有效算 術運算結果,那么溢出標志位置 1:
mov al,-128 sub al,1 ;OF = 1加法測試,兩數相加時,有個很簡單的方法可以判斷是否發生溢出。溢出發生的情況有:
- 兩個正數相加,結果為負數
- 兩個負數相加,結果為正數
如果兩個加數的符號相反,則不會發生溢出。
硬件如何檢測溢出,加法或減法操作后,CPU 用一種有趣的機制來檢測溢出標志位的狀態。計算結果的最高有效位產生的進位與結果的最高位進行 異或操作,異或的結果存入溢岀標志位。如下圖所示,兩個 8 位二進制數 1000 0000 和 1111 1110 相加,產生進位 CF=1,和數最高位(位 7)= 0,即 1 XOR 0=1,則 OF=1。
NEG 指令,如果 NEG 指令的目的操作數不能正確存儲,則該結果是無效的。例如, AL 中存放的是 -128,對其求反,正確的結果為 +128,但是這個值無法存入 AL。則溢出標志位置 1 就表示 AL 中存放的是一個無效的結果:
mov al,-128 ;AL = 10000000b neg al ;AL = 10000000b, OF = 1反之,如果對 +127 求反,結果是有效的,則溢出標志位清 0:
mov al,+127 ;AL = 01111111b neg al ;AL = 10000001b, OF = 0CPU 如何知道一個算術運算是有符號的還是無符號的?答案看上去似乎有點愚蠢:它不知道!在算術運算之后,不論標志位是否與之相關,CPU 都會根據一組布爾規則來設置所有的狀態標志位。程序員要根據執行操作的類型,來決定哪些標志位需要分析,哪些可以忽略。
示例程序(AddSubTest)
AddSubTest 程序利用 ADD、SUB、INC、DEC 和 NEG 指令執行各種算術運算表達式,并展示了相關狀態標志位是如何受到影響的:
;加法和減法 (AddSubTest.asm) .386 .model flat,stdcall .stack 4096 ExitProcess proto,dwExitCode:dword .data Rval SDWORD ? Xval SDWORD 26 Yval SDWORD 30 Zval SD4.1?操作數類型
4.2?MOV指令
4.3?MOVZX和MOVSX指令
4.4?LAHF和SAHF指令
4.5?XCHG指令
4.6?直接偏移量操作數
4.7?匯編語言數據傳送示例
4.8?加法和減法詳解
4.9?OFFSET運算符
4.10?ALIGN偽指令
4.11?PTR運算符
4.12?TYPE運算符
4.13?LENGTHOF運算符
4.14?LABEL偽指令
4.15?間接尋址
4.16?JMP和LOOP指令
4.17?64位MOV指令
4.18?64位加法和減法
總結
以上是生活随笔為你收集整理的汇编语言加法和减法详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 汇编语言数据传送示例
- 下一篇: python后台截屏_Python实现屏