匯編語言之標志寄存器
1、標志寄存器
CPU內部的寄存器中,有一種特殊的寄存器(對于不同的處理機,個數和結構都可能不同)具有以下3種作
用:
1. 用來存儲相關指令的某些執(zhí)行結果。
2. 用來為CPU執(zhí)行相關指令提供行為依據。
3. 用來控制CPU的相關工作方式。
這種特殊的寄存器在8086CPU中,被稱為標志寄存器。8086CPU的寄存器,在前面已經學過13個了,現
在學習最后一個寄存器FR-標志寄存器。
FR與其它寄存器不一樣,其它寄存器是用來存放數據的,都是整個寄存器具有一個含義,而FR寄存器是按位
起作用的,也就是說它的每一位都有專門的含義,記錄特定的信息。
8086CPU的FR寄存器的結構如下圖所示:
FR的第1、3、5、12、13、14、15位是空白位,在8086CPU中沒有使用,不具有任何意義,而第0、2、
4、6、7、8、9、10、11位都具有特殊的含義。
2、CF標志
7.1 CF標志
FR的第0位是CF,進位標志位。一般情況下,在進行無符號數運算的時候,它記錄了運算結果的最高有效位
向更高位的進位值,或從更高位的借位值。
對于位數為N的無符號數來說,其對應的二進制信息的最高位,即第N-1位,就是它的最高有效位,而假想
存在的第N位,就是相對于最高有效位的更高位,如下圖所示:
我們知道,當兩個數據相加的時候,有可能產生從最高有效位向更高位的進位,比如,兩個8位數據:98H+
98H,將產生進位,這個進位值就用CF標志位來保存。
比如,下面的指令:
Mov al, 98H
Add al, al
執(zhí)行后,計算結果為130H,al=30H,CF=1,CF記錄了從最高有效位向更高位的進位值。
兩數相加,如果產生了進位,則CF=1,如果沒有產生進位,則CF=0。
當兩個數據做減法的時候,有可能向更高位借位,比如,兩個8位數據:97H-98H,將產生借位,借位后相
當于計算197H-98H,而FR的CF標志位也可以用來記錄這個借位值。
比如,下面的指令:
Mov al, 97H
Sub al, 98H
執(zhí)行后,計算結果為197H-98H=ffH,al=ffH,CF=1,CF記錄了向更高位的借位值。
兩數相減,如果產生借位,則CF=1,如果沒有產生借位,則CF=0。
3、adc指令
Adc是帶進位加法指令,它利用了CF位上記錄的進位值。
格式:adc 操作對象1,操作對象2
功能:操作對象1=操作對象1+操作對象2+CF
例1:mov ax, 1
Add ax, ax ;結果:ax=2,沒有產生進位值,CF=0。
Adc ax, 3 ;結果:ax=ax+3+CF=2+3+0=5。
例2:mov al, 98H
Add al, al ;結果=130H,產生了進位值,CF=1,al=30H。
Adc al, 3 ;結果:al=al+3+CF=30H+3+1=34H。
可以看出,adc指令比add指令多加了一個CF位的值,為什么要加上CF的值呢?CPU為什么要提供這樣一
條指令呢?
我們來看一下兩個數據:0198H和0183H是如何相加的,見下圖:
可以看出,加法可以分兩步來進行:1.低位相加(98+83)。2.高位相加再加上低位相加產生的進位值(1+1
+1)??磥鞢PU提供adc指令的目的,就是來進行加法的第二步運算的。用adc指令和add指令相配合就可以
對更大的數據進行加法運算。
例3:計算1EF000H+201000H,結果放在ax(高16位)和bx(低16位)中。
因為兩個數據的位數都大于16位,用add指令無法進行計算,我們將計算分兩步進行,先將低16位
(F000H和1000H)相加,然后將高16位(1EH和20H)和進位值相加,代碼如下:
Mov ax, 1eH
Mov bx, f000H
Add bx, 1000H ;低16位相加,結果:f000H+1000H=10000H 產生了進位值,CF=1,bx=0。
Adc ax, 20H ;高16位相加,結果:ax=ax+20H+CF=1eH+20H+1=3fH。
最終結果:ax=3fH,bx=0,1EF000H+201000H=3f0000H。
Adc指令執(zhí)行后,也可能產生進位值,所以也會對CF位進行設置,由于有這樣的功能,我們就可以對任意大
的數據進行加法運算。
例4:計算1EF0001000H+2010001EF0H,結果放在ax(最高16位),bx(次高16位),cx(低16位)
中。
計算分3步進行:
1. 先將低16位(1000H和1EF0H)相加,完成后,CF記錄本次相加的進位值。
2. 再將次高16位(F000H和1000H)和CF(來自低16位的進位值)相加,完成后,CF記錄本次相加
的進位值。
3.最后最高16位(1EH和20H)和CF(來自次高16位的進位值)相加,完成后,CF記錄本次相加的進位
值。
代碼如下:
Mov ax, 1eH
Mov bx, f000H
Mov cx, 1000H
Add cx, 1ef0H ;低16位相加,結果:1000H+1ef0H=2ef0H,沒有產生進位值,CF=0,cx=2ef0H。
Adc bx, 1000H ;次高16位相加,結果:f000H+1000H+0=10000H,產生進位值,CF=1,bx=0。
Adc ax, 20H ;最高16位相加,結果:ax=ax+20H+CF=1eH+20H+1=3fH,沒有產生進位,CF=0。
最終結果:ax=3fH,bx=0,cx=2ef0H。1EF0001000H+2010001EF0H=3F00002EF0H。
4、sbb指令
Sbb是帶借位減法指令,它利用了CF位上記錄的借位值。
格式:sbb 操作對象1,操作對象2
功能:操作對象1=操作對象1-操作對象2-CF。
Sbb指令執(zhí)行后,將對CF進行設置,利用sbb指令和sub指令配合使用可以對任意大的數據進行減法運算。
例1:計算3E1000H-202000H,結果放在ax(高16位),bx(低16位)。
計算分兩步進行,先將低16位(1000H和2000H)相減,然后將高16位(3EH和20H)和借位值相減,
代碼如下:
Mov bx, 1000H
Mov ax, 3eH
Sub bx, 2000H ;低16位相減,結果:1000H-2000H=11000H-2000H=f000H,產生了借位值,
CF=1,bx=f000H。
Sbb ax, 20H ;高16位相減,結果:ax=ax-20H-CF=3eH-20H-1=1dH,沒有產生借位值,CF=0。
最終結果:ax=1dH,bx=f000H,3E1000H-202000H=1DF000H。
例2:計算6E4F0031C0H-1FA2002700H。結果放在ax(最高16位),bx(次高16位),cx(低16
位)。
計算分3步進行:
1. 先將低16位(31C0H和2700H)相減,完成后,CF記錄本次相減的借位值。
2. 再將次高16位(4F00H和A200H)和CF(來自低16位的借位值)相減,完成后,CF記錄本次相減的
借位值。
3. 最后將最高16位(6EH和1FH)和CF(來自次高16位的借位值)相減,完成后,CF記錄本次相減的借
位值。
代碼如下:
Mov ax, 6eH
Mov bx, 4f00H
Mov cx, 31c0H
Sub cx, 2700H ;低16位相減,結果:31c0H-2700H=ac0H,沒有產生借位值,CF=0,cx=ac0H。
Sbb bx, a200H ;次高16位相減,結果:14f00H-a200H=ad00H,產生借位值,CF=1,bx=ad00H。
Sbb ax, 1fH ;最高16位相減,結果:ax=ax-1fH-CF=6eH-1fH-1=4eH,沒有產生借位值,CF=0。
最終結果:ax=4eH,bx=ad00H,cx=ac0H,6E4F0031C0H-1FA2002700H=4EAD000AC0H。
5、ZF標志
FR的第6位是ZF,零標志位。它記錄相關指令執(zhí)行后,其結果是否為0。如果(真),結果為0,那么ZF=1;
如果(假),結果非0,那么ZF=0。
對于ZF的值,我們可以這樣來看:在計算機中1表示邏輯真,表示肯定,所以當結果為0的時候,ZF=1;在
計算機中0表示邏輯假,表示否定,所以當結果不為0的時候,ZF=0。
下面的指令:
Mov ax, 5
Sub ax, ax
執(zhí)行后,結果為0,表示真,則ZF=1。
Mov ax, 5
Sub ax, 1
執(zhí)行后,結果不為0,表示假,則ZF=0。
6、cmp指令
Cmp是比較指令,它的功能相當于sub指令,只是不保存結果。Cmp指令執(zhí)行后,將對標志寄存器產生影
響,其它相關指令通過識別這些被影響的標志位來得知比較結果。
指令格式:cmp 操作對象1,操作對象2
功能:計算操作對象1-操作對象2,但并不保存結果,僅僅根據計算結果對標志寄存器的標志位進行設置。
Cmp指令執(zhí)行后,依據標志位的值就可以看出比較結果。
比如,cmp ax, bx執(zhí)行后:
如果ZF=1,說明ax=bx,因為ax-bx=0,那么ax必定等于bx。
如果ZF=0,說明ax≠bx,因為ax-bx≠0,那么ax與bx必定不相等。
如果CF=1,說明ax<bx,因為ax-bx產生了借位,那么ax必定小于bx。
如果CF=0,說明ax≥bx,因為ax-bx沒有產生借位,那么ax必定大于或等于bx。
如果CF=0,并且ZF=0,說明ax>bx,因為ax-bx沒有產生借位,并且ax-bx≠0,那么ax必定大于bx。
如果CF=1或ZF=1,說明ax≤bx,因為ax-bx產生了借位,又或者ax-bx=0,那么ax必定小于或等于
Bx。
7、檢測比較結果的條件轉移指令
轉移指的是它能夠修改IP,而條件指的是它可以根據某種條件,決定是否修改IP,所有條件轉移指令都是短
轉移,轉移的位移范圍為﹣128~127。
大多數條件轉移指令都檢測標志寄存器的相關標志位,根據檢測的結果來決定是否修改IP,它們所檢測的標
志位都是被cmp指令影響的那些表示比較結果的標志位。
下面是常用的根據無符號數的比較結果進行轉移的條件轉移指令。
指令 檢測的相關標志位 與cmp配合使用的邏輯含義
Je 如果ZF=1則轉移 如果等于則轉移
Jne 如果ZF=0則轉移 如果不等于則轉移
Jb 如果CF=1則轉移 如果低于則轉移
Jnb 如果CF=0則轉移 如果不低于則轉移
Ja 如果CF=0且ZF=0則轉移 如果高于則轉移
Jna 如果CF=1或ZF=1則轉移 如果不高于則轉移
以上這些條件轉移指令是根據檢測相關的標志位來決定是否轉移,比如:je是檢測ZF的值來決定是否轉移,
如果ZF=1則轉移,至于根據邏輯含義來決定是否轉移,則需要與cmp指令配合使用,這個在下一節(jié)會講到。
8、cmp與條件轉移指令配合使用
上一節(jié)介紹的條件轉移指令,所檢測的標志位都是cmp指令進行無符號數比較的時候,記錄比較結果的標志
位,比如,je檢測ZF位,當ZF=1時轉移,如果在je前面使用了cmp指令,那么je對ZF的檢測,實際上是間
接地檢測cmp的比較結果是否為兩數相等。
請看下面一段代碼:
Cmp ax, bx
Je s
Add ax, bx
Jmp short ok
S:add ax, ax
Ok: …
上面的代碼執(zhí)行時,如果ax=bx,則cmp ax, bx使ZF=1,而je檢測ZF是否為1,如果為1,則轉移到標號
S處執(zhí)行指令add ax, ax,我們也可以這樣說,cmp比較ax, bx后所得到的相等的結果使得je指令進行轉移,這
種說法很好地體現了je指令的邏輯含義,即“相等則轉移“。
“相等則轉移”這種邏輯含義是通過和cmp指令配合使用來體現的,我們用cmp指令與條件轉移指令配合使
用的時候,不必再考慮cmp指令對相關標志位的影響和je等指令對相關標志位的檢測,因為相關的標志位只是為
Cmp和je等指令傳遞比較結果,我們可以直接考慮cmp與je等指令配合使用時,表現出來的邏輯含義。
請看下面的指令:
Cmp byte ptr [bx], 8 ;和8比較
Je 標號 ;如果等于則轉移
Cmp byte ptr [bx], 8 ;和8比較
Jne 標號 ;如果不等于則轉移
Cmp byte ptr [bx], 8 ;和8比較
Jb 標號 ;如果低于則轉移
Cmp byte ptr [bx], 8 ;和8比較
Jnb 標號 ;如果不低于則轉移
Cmp byte ptr [bx], 8 ;和8比較
Ja 標號 ;如果高于則轉移
Cmp byte ptr [bx], 8 ;和8比較
Jna 標號 ;如果不高于則轉移
上面的指令,用[bx]中的數值和8比較,“如果怎么怎么樣則轉移”,我們在修改游戲時,可以根據這些邏輯含
義(即:如果怎么怎么樣則轉移),選擇合適的條件轉移指令。
9、其它標志位
標志寄存器的大部分標志位,我們都不必深入地去學習,因為這和修改游戲沒有多大關系,我們只需簡單了解
一下即可,FR一共有9個標志位,前面已學習了ZF和CF這兩個標志位,現在講講余下的7個標志位。
PF:奇偶標志位。它記錄相關指令執(zhí)行后,其結果的所有二進制位中1的個數是否為偶數,如果(真),1的
個數為偶數,PF=1,如果(假),1的個數為奇數,PF=0。
比如,某些指令執(zhí)行后,其結果二進制值為01001011,有4(偶數)個1,則PF=1;某些指令執(zhí)行后,其
結果二進制值為00001011,有3(奇數)個1,則PF=0。
SF:符號標志位。它記錄相關指令執(zhí)行后,其結果是否為負,如果(真),結果為負,SF=1,如果(假),結
果非負,SF=0。
OF:溢出標志位。一般情況下,OF記錄了有符號數運算的結果是否發(fā)生了溢出,如果(真),發(fā)生了溢出,
OF=1,如果(假),沒有發(fā)生溢出,0F=0。
什么是溢出?在進行有符號數運算的時候,如結果超過了機器所能表示的范圍稱為溢出。那么,機器所能表示
的范圍是多少呢?對于8位的有符號數據,機器所能表示的范圍就是﹣128~127;對于16位的有符號數據,機器
所能表示的范圍就是﹣32768~32767。如果運算結果超出了機器所能表達的范圍,將產生溢出。
比如,指令:
Mov al, 98
Add al, 99
執(zhí)行后,al=98+99=197,197超出了機器所能表示的8位有符號數的范圍:﹣128~127,所以產生了溢出。
DF:方向標志位。在串處理指令中,控制每次操作后SI、DI的增減。
DF=0,每次操作后SI、DI遞增;DF=1,每次操作后SI、DI遞減。
DF標志位與串傳送指令(movsb、movsw)有關,而串傳送指令與游戲修改無關,所以就不講解了。
TF:跟蹤標志位。用于程序調試。
如果TF=1,則CPU處于單步執(zhí)行指令的工作方式,此時,每執(zhí)行完一條指令,就顯示CPU各個寄存器的當
前值及CPU將要執(zhí)行的下一條指令。如果TF=0,則處于連續(xù)工作模式。
AF:輔助進位標志位。在下列情況下,AF的值被設置為1,否則其值為0。
1. 在字操作時,發(fā)生低字節(jié)向高字節(jié)進位或借位時。
2. 在字節(jié)操作時,發(fā)生低4位向高4位進位或借位時。
IF:中斷允許標志位。用來決定CPU是否響應CPU外部的可屏蔽中斷發(fā)出的中斷請求,當IF=1,響應中斷
請求,當IF=0,不響應中斷請求。
10、lea和nop指令
Lea為有效地址傳送指令。
格式:lea 操作對象1,操作對象2
功能:將源操作數給出的有效地址傳送到指定的寄存器中。
說明:操作對象1為目的操作數,可為任意一個16位的通用寄存器,操作對象2為源操作數,可為地址表達
式。
比如,指令:
Lea ax, [217a]
執(zhí)行后,ax=217aH。
Lea ax, [bx+si+200]
執(zhí)行后,ax= bx+si+200H。
Nop為空操作指令。格式:nop。
功能:本指令不產生任何結果,僅消耗幾個時鐘周期的時間,接著執(zhí)行后續(xù)指令,常用于程序的延時等。
在修改游戲的時候,可用于鎖定某些數據的數值。
作者:chen.yu
深信服三年半工作經驗,目前就職游戲廠商,希望能和大家交流和學習,
微信公眾號:編程入門到禿頭 或掃描下面二維碼
零基礎入門進階人工智能(鏈接)