ASM - 條件判斷

技術交流,DH講解.web

正式以前,咱們看看寄存器和CPU的標誌位:
image函數

OD中的截圖,下方的CPAZSTDO就是標誌位.
image 
Delphi的FPU窗口,右邊一列就是標誌位.
爲何要給你們看標誌位呢?由於ASM中的跳轉語句都是由相應的標誌位控制的.
而標誌位又是因爲如下的狀況影響的:
1.運算結果爲0,Zero Flag(ZF)被設定
2.運算結果太大或者過小,超容了,Carry Flag(CF)被設定
3.Sign Flag(SF)是運算結果的最高位發生變化的時候,結果爲正SF=1,爲負SF=0
4.指令無效時(al=+127, al+1爆 , al = -128 , al-1爆),Over Flag會被設定
5.運算形成結果的地位中1的個數是偶數個的時候Parity Flag會被設定oop

指令講解:
具體指令以前,先說一下:reg表明寄存器,mem表明內存上的數(變量),imm表明當即數(常量)
AND,二元操做符,位與
合法形式:spa

1
2
3
4
5
AND   reg , reg
AND   reg , mem
AND   reg , imm
AND   mem , reg
AND   mem , imm

標誌位:老是清除OF和CF,根據結果來設置SF,ZF,PF.
來看個例子吧:code

1
2
3
4
5
6
7
8
9
10
11
12
function   TestAnd(a,b: Integer ): Integer   ;
asm
   and   eax,edx
end ;
 
procedure   TForm4 . FormCreate(Sender: TObject);
var
   a: Integer ;
begin
   a:= $F ; //00001111
   ShowMessage(IntToStr(TestAnd(a, 1 )));
end ;

image 運算前
image 運算後
來個有用的函數,字符轉換成大寫:orm

1
2
3
4
function   UpcaseChar(a: AnsiChar ): AnsiChar ;
asm
   and   al, $DF
end ;

OR,二元操做符,位或
合法形式:blog

1
2
3
4
5
OR   reg , reg
OR   reg , mem
OR   reg , imm
OR   mem , reg
OR   mem , imm

標誌位:和AND同樣.
例子將0~9的整數變成對應的Char形式:內存

1
2
3
4
function   _0_9ToChar(n: Byte ): AnsiChar ;
asm
   or   al, $30
end ;

image 運算前
image 運算後ci

XOR,二元操做符,位異或(相同爲0,不一樣爲1)
合法形式:同AND
標誌位:同AND
咱們有時候須要將某個寄存器清零,咱們有2種方式:字符串

1
2
3
4
5
procedure   TestXor;
asm
   xor   eax,eax
   mov eax, 0
end ;

反彙編看:
image 
第一個指令:$31C0只用了2個字節.第二個指令就用了5個字節.
NOT,一元操做符,位非(1變0,0變1)
合法形式:

1
2
NOT   reg
NOT   mem

標誌位:不影響任何標誌位
TEST,二元操做符,和AND的同樣,可是不改變2個操做數的值,隻影響標誌位.
合法形式:同AND
標誌位:同AND
咱們常常須要判斷一個string變量是否爲nil

1
2
3
4
5
function   TestTest( const   s: string ): Integer ;
asm
   test eax,eax //if s=nil then
   jz @@nExit
end ;

CMP,二元操做符,比較2個數大小
合法形式:同SUB指令
標誌位:
                CF ZF
目的<來源 | 0 | 1
目的>來源 | 0 | 0
目的=來源 | 1 | 0
帶正負號的數比較:
目的<來源 | SF≠OF
目的>來源 | SF=OF
目的=來源 | ZF=1

經常使用的設置個別標誌位的方法:
1 ZF

1
2
and   al, 0   //ZF=1,任何數和0進行與
or   al, 1   //ZF=0,任何數和1進行或

2 SF

1
2
or   al, $80   //SF=1,最高位與1進行或
and   al, $7F   //SF=0,最高位與0進行與

3 CF

1
2
stc //CF=1
clc //CF=0

4 OF

1
2
3
mov al, $7F
inc al //OF=1
or   al, 0   //OF=0

 

跳轉指令
通常跳轉根據:1 標誌位 2 參與運算的2個數
第一組:N表明Not,J就是Jump,而後其餘字母對應相應的標誌位
JZ   | 若為零則跳     | ZF=1
JNZ | 若為不零則跳 | ZF=0
JC   | 若進位則跳     | CF=1
JNC | 若不進位則跳 | CF=0
JO   | 若溢位則跳     | OF=1
JNO | 若不溢位則跳 | OF=0
JS    | 若負號則跳    | SF=1
JNS  | 若非負號則跳 | SF=0
JP    | 同位(偶)則跳  | PF=1
JNP | 非同位(奇)則跳 | PF=0
第二組:根據參與運算的2個數的值
JE     | 相等則跳(leftOp=rightOp)
JNE   | 不相等則跳(leftOp≠rightOp)
JCXZ | 若 CX = 0 則跳
JECXZ | 若 ECX = 0 則跳
無符號2個數比較時候:
JA     | 較大則跳 大於
JNBE | 不是較小或相等則跳(=JA) 大於
JAE   | 較大或相等則跳 大於等於
JNB   | 不是較小則跳(=JAE)大於等於
JB     | 較小則跳 小於
JNAE | 不是較大或相等則跳(=JB)小於
JBE   | 較小或相等則跳 小於等於
JNA   | 不是較大則跳(=JBE)小於等於
有符號2個數比較時候:
JG      | 較大則跳
JNLE  | 非較小或相等則跳(=JG)
JGE    | 較大或相等則跳
JNL    | 不是較小則跳(=JGE)
JL      | 較小則跳
JNGE | 非較大或相等則跳(=JL)
JLE    | 較小或相等則跳
JNG   | 不是較大則跳(=JLE) | 不是較大則跳(=JBE)

好咱們來看下怎麼寫一個求2個數中較小的一個數的函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function   IntegerMin(a,b: Integer ): Integer ;
asm
   cmp eax,edx
   jg @@nBmin
   ret
@@nBmin:
   mov eax,edx
end ;
 
function   CardinalMin(a,b: Cardinal ): Cardinal   ;
asm
   cmp eax,edx
   ja @@nBmin
   ret
@@nBmin:
   mov eax,edx
end ;

關鍵處的跳轉指令不同的,由於數據類型不同.

最後來看一下循環指令
LOOPELOOPZ,一元操做符,知足條件就跳轉,條件是ZF=1 and ecx>0
合法形式:LOOPE/LOOPZ 標籤

LOOPNELOOPNZ,一元操做符,條件ZF=0 AND ECX>0
合法形式:和LOOPE
咱們用LoopE來在一個字符串中查找一個字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function   FindChar(a: AnsiChar ; const   s: AnsiString ): Integer   ;
asm
   test edx,edx   //s=nil
   jz @@nNotFound
   mov ecx,[edx - 4 ]
   //length(s)=0
   jz @@nNotFound
   push edx
   dec edx
@@nLoop:
   inc edx
   cmp al, Byte   ptr [edx]
   loopne @@nLoop
   pop edx
   test ecx,ecx
   jz @@nNotFound
   mov eax,[edx - 4 ]
   sub eax,ecx
   dec eax
   ret
@@nNotFound:
   xor   eax,eax
end ;
相關文章
相關標籤/搜索