最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

5.11 匯編語言:仿寫IF條件語句

2023-08-24 10:23 作者:bili_42682284418  | 我要投稿

條件語句,也稱為IF-ELSE語句,是計算機編程中的一種基本控制結(jié)構(gòu)。它允許程序根據(jù)條件的真假來執(zhí)行不同的代碼塊。條件語句在處理決策和分支邏輯時非常有用。一般來說,條件語句由IF關(guān)鍵字、一個條件表達式、一個或多個代碼塊以及可選的ELSE關(guān)鍵字和對應(yīng)的代碼塊組成。條件表達式的結(jié)果通常是布爾值(True或False),決定了程序?qū)?zhí)行IF代碼塊還是ELSE代碼塊。


在匯編語言中,條件跳轉(zhuǎn)指令用于根據(jù)條件語句的結(jié)果在不同的代碼塊之間跳轉(zhuǎn),標簽用于標記代碼塊的入口點。通過運用標簽與跳轉(zhuǎn)即可構(gòu)建不同的條件語句,本章將以C語言中條件語句為基礎(chǔ),并使用匯編語言介紹如何實現(xiàn)它們,以讓讀者能更加深入的理解C語言與匯編語言之間的差異,幫助讀者更好的理解并運用匯編語言。


### 11.1 IF中AND語句構(gòu)造


如下所示代碼定義了3個整型變量var1、var2和var3,并檢查它們的值是否滿足一定的條件,條件包括var1大于等于20,var2小于等于100,var3等于50。如果這些條件都成立,則輸出字符串"xor eax,eax"。


AND運算符是邏輯運算符之一,用于連接兩個條件,當且僅當兩個條件都成立時,才會返回真值。在C語言中,AND運算符使用`&&`表示。針對and語句的執(zhí)行順序,如果等式兩邊只要有一邊返回假,則整個等式就不需要繼續(xù)下去了,只有等式1成立的情況下才會繼續(xù)判斷等式2是否成立,兩邊都成立則會執(zhí)行表達式內(nèi)部。


```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int var1 = 20;

? int var2 = 10;

? int var3 = 50;


? if (var1 >= 20 and var2 <= 100 and var3 == 50)

? {

? ? printf("xor eax,eax");

? }

? return 0;

}

```

對于多重and比較運算,編寫匯編語句時,應(yīng)注意判斷的轉(zhuǎn)換,如果高級語言中是大于等于,那么低級語言則可轉(zhuǎn)換為不大于則跳轉(zhuǎn),如果是小于等于,則對應(yīng)的匯編語句則可直接轉(zhuǎn)換為不小于則跳轉(zhuǎn),最后and語句必須三者全部一致,所以判斷條件只需要順序向下寫即可,當所有條件全部滿足則執(zhí)行內(nèi)部的xor指令,否則直接跳轉(zhuǎn)結(jié)束本次判斷。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

? flag DWORD ?

.code

? main PROC

? ; if(var1 >= 20 and var2 <= 100 and var3 == 50)

? ? cmp dword ptr ds:[var1],20? ? ?; 判斷是否大于20

? ? jl L1? ? ? ? ? ? ? ? ? ? ? ? ? ; 不大于則跳轉(zhuǎn)

? ??

? ? cmp dword ptr ds:[var2],100? ? ; 判斷是否小于100

? ? jg L1? ? ? ? ? ? ? ? ? ? ? ? ? ; 不小于則跳轉(zhuǎn)

? ??

? ? cmp dword ptr ds:[var3],50? ? ?; 判斷是否等于50

? ? jne L1? ? ? ? ? ? ? ? ? ? ? ? ?; 不等于則跳轉(zhuǎn)


? ? mov dword ptr ds:[flag],1? ? ? ; 說明等式成立 flag=1

? ? jmp L2


? L1: mov dword ptr ds:[flag],0

? L2: cmp dword ptr ds:[flag],0

? ? je lop_end? ? ? ? ? ? ? ? ? ? ?; 為0則跳轉(zhuǎn),不為0則繼續(xù)執(zhí)行

? ??

? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ; 此處是執(zhí)行if語句內(nèi)部

? ? xor ebx,ebx

? ? xor ecx,ecx

? ? jmp lop_end


? lop_end:

? ? nop? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 直接結(jié)束

??

? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.2 IF中OR語句構(gòu)造


OR運算符的特點是,它表示兩個條件中只要有一個為真即可滿足整個語句的條件。在進行條件判斷時,如果其中一個子條件的結(jié)果為真,則整個表達式的后半部分將直接跳過,因為無論后半部分的條件是否成立,整個表達式已經(jīng)返回真值。這種行為稱為短路求值。

```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int var1 = 20;

? int var2 = 10;

? int var3 = 50;


? if (var1 > var2 || var2 <= var3)

? {

? ? printf("xor eax,eax");

? }

? else if(var3 == 50 || var2 > 10)

? {

? ? printf("xor ebx,ebx");

? }

? return 0;

}

```

此處由于表達式中使用了OR語句,該語句在比較時只需要兩個表達式一邊為假,則表達式后半部分會直接忽略判斷,所以在構(gòu)建判斷時,應(yīng)盡可能多的使用cmp語句對變量進行比較。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ; if (var1 > var2 || var2 <= var3)

? ? mov eax,dword ptr ds:[var1]

? ? cmp eax,dword ptr ds:[var2]? ? ?; var1 > var2

? ? jg L1

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,dword ptr ds:[var3]? ? ?; var2 <= var3

? ? jg L2? ? ? ? ? ? ? ? ? ? ? ? ? ?; 條件是 var2 > var3 則跳轉(zhuǎn)

? L1:

? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ?; printf("xor eax,eax")

? ? jmp lop_end

? L2:

? ; else if(var3 == 50 || var2 > 10)

? ? cmp dword ptr ds:[var3],50

? ? je L3

? ? cmp dword ptr ds:[var2],10? ? ? ; var2 > 10

? ? jle lop_end

? L3:

? ? xor ebx,ebx? ? ? ? ? ? ? ? ? ? ?; printf("xor ebx,ebx")

? ? jmp lop_end

??

? lop_end:

? ? nop

? ? int 3

? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.3 IF中AND與OR構(gòu)造


在C語言中,AND和OR運算符可以混合使用,實現(xiàn)更加靈活的條件判斷。在混合使用時,需要注意運算符的優(yōu)先級和結(jié)合性。AND運算符的優(yōu)先級高于OR運算符,因此,在混合使用AND和OR運算符時,AND的運算會先于OR運算進行。將AND與OR語句混用,混用后其匯編形式與單獨使用差距并不明顯。


```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int var1 = 20;

? int var2 = 10;

? int var3 = 50;


? if ((var1 >= 10 && var2 <= 20) || (var2 == 10 && var3 >= 40))

? {

? ? printf("xor eax,eax");

? }

? else

? {

? ? printf("xor ebx,ebx");

? }

? return 0;

}

```

如上如果將And語句與Or語句連用,編譯器會首先判斷等式兩邊是否為常量,如果是常量且外部使用OR包裹,那么通常情況下會只保留等式左邊的表達式,等式右邊將會被優(yōu)化掉,而對于人的編寫邏輯則是依次作比較。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ; if ((var1 >= 10 && var2 <= 20) && (var2 == 10 || var3 >= 40))

? ? cmp dword ptr ds:[var1],10? ? ?; var1 >= 10

? ? jl L1

? ? cmp dword ptr ds:[var2],20? ? ?; var2 <= 20

? ? jg L1

? ??

? ? cmp dword ptr ds:[var2],10? ? ?; var2 == 10

? ? je L2

? ? cmp dword ptr ds:[var3],40? ? ?; var3 >= 40

? ? jl L1

? ? jmp L2

??

? L1:

? ? xor ebx,ebx? ? ? ? ? ? ? ?; else

? ? jmp lop_end

? L2:

? ? xor eax,eax? ? ? ? ? ? ? ? ; printf("xor eax,eax")

? ? jmp lop_end

? lop_end:

? ? int 3


? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.4 IF語句條件測試


這段C++代碼定義了6個整型變量,并檢查它們的值是否滿足多個條件。首先,它檢查var1是否大于等于var2且var2小于等于var3,并進入下一個if塊。接著,它檢查x是否等于100或y是否等于200或z是否等于300,并進入下一個if塊。最后,它檢查result是否等于1,如果是,則輸出字符串"xor eax,eax"。


條件測試語句通常情況下會使用`cmp`指令配合各種狀態(tài)跳轉(zhuǎn)實現(xiàn),此處我分別提供兩種仿寫方式,來看下編譯器與我們思維方式的異同。

```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int x = 100, y = 200, z = 300;

? int var1 = 20,var2 = 10,var3 = 50;

? int result = 1;


? if (var1 >= var2 && var2 <= var3)

? {

? ? if (x == 100 || y == 200 || z == 300)

? ? {

? ? ? if (result == 1)

? ? ? ? printf("xor eax,eax");

? ? }

? }

? return 0;

}

```

對于編譯器來說,生成的代碼要盡可能高效率,上方的C代碼如果是編譯器生成,則首先編譯器會比較外層循環(huán)中的AND語句,由于是AND語句此處無法優(yōu)化直接做兩次比較,接著進入內(nèi)層比較,依次流水線式執(zhí)行下來。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? x DWORD 100

? y DWORD 200

? z DWORD 300

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

? result DWORD 1

.code

? main PROC

? ? mov eax,dword ptr ds:[var1]

? ? cmp eax,dword ptr ds:[var2]? ? ? ; var1 >= var2

? ? jl lop_end

? ??

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,dword ptr ds:[var3]? ? ? ; var2 <= var3

? ? jg lop_end

? ??

? ? mov eax,dword ptr ds:[x]

? ? cmp eax,100? ? ? ? ? ? ? ? ?; x == 100

? ? jne lop_end

? ??

? ? mov eax,dword ptr ds:[y]

? ? cmp eax,200? ? ? ? ? ? ? ? ?; y == 200

? ? jne lop_end

? ??

? ? mov eax,dword ptr ds:[z]

? ? cmp eax,300? ? ? ? ? ? ? ? ?; z = 300

? ? jne lop_end

? ??

? ? mov eax,dword ptr ds:[result]

? ? test eax,eax? ? ? ? ? ? ? ? ?; eax = 0 ?

? ? jz lop_end

? ? xor eax,eax

? ? jmp lop_end

? ??

? lop_end:

? ? int 3


? ? invoke ExitProcess,0

? main ENDP

END main

```

以下是人的邏輯方式,這段代碼是本人以匯編小白視角編寫的一段代碼,代碼中首先比較外層IF語句由于是AND所以需要比較兩次,接著比較內(nèi)層判斷,內(nèi)層是OR語句,比較時可采用流水線式比較,最終如果比較通過則直接JE跳轉(zhuǎn)到語句內(nèi),否則直接跳轉(zhuǎn)到結(jié)尾。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? x DWORD 100

? y DWORD 200

? z DWORD 300

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

? result DWORD 1

.code

? main PROC

? ? mov eax,dword ptr ds:[var1]

? ? cmp eax,dword ptr ds:[var2]? ? ? ; var1 >= var2

? ? jge L1

? ? jmp lop_end

? L1:

? ? mov eax,dword ptr ds:[var2]? ? ? ; var2 <= var3

? ? cmp eax,dword ptr ds:[var3]? ? ??

? ? jle L2

? ? jmp lop_end

? L2:

? ? mov eax,dword ptr ds:[x]

? ? cmp eax,100? ? ? ? ? ? ? ? ? ? ? ?; x == 100 ?

? ? je L3

? ? mov eax,dword ptr ds:[y]? ? ? ? ? ; y == 200 ???

? ? cmp eax,200

? ? je L3

? ? mov eax,dword ptr ds:[y]

? ? cmp eax,300? ? ? ? ? ? ? ? ? ? ? ?; z == 300 ?

? ? je L3

? ? jmp lop_end

? L3:

? ? mov eax,dword ptr ds:[result]? ? ?; result == 1 ?

? ? test eax,eax? ? ? ? ? ? ? ? ? ? ? ; eax && eax != 0

? ? jz lop_end

? ? xor eax,eax

? ? jmp lop_end

? lop_end:

? ? int 3


? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.5 IF語句雙重嵌套


這段C++代碼定義了6個整型變量并檢查它們的值是否滿足多重條件。首先,它檢查var1是否大于等于var2,如果滿足,則進入下一個if塊。在下一個if塊中,它進一步檢查x<y且z>y是否成立,如果是,則輸出字符串"xor eax, eax",否則輸出字符串"xor ebx, ebx"。如果var1不大于等于var2,則它將檢查var2是否大于var3,如果是,則輸出字符串"xor ecx, ecx"。這段代碼實現(xiàn)了簡單的條件分支邏輯。


雙重IF嵌套語句其本質(zhì)就是連續(xù)作比較,在仿寫匯編指令時應(yīng)該由外到內(nèi)逐層解析,這樣才能寫出條例清晰的匯編指令。

```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int x = 100, y = 200, z = 300;

? int var1 = 20,var2 = 10,var3 = 50;


? if (var1 >= var2)

? {

? ? if ((x<y) && (z>y))

? ? {

? ? ? printf("xor eax,eax");

? ? }

? ? else

? ? {

? ? ? printf("xor ebx,ebx");

? ? }

? }

? else if (var2 > var3)

? {

? ? printf("xor ecx,ecx");

? }

? return 0;

}

```

如下匯編代碼,首先比較外層判斷`var1>=var2`如果不成立則`jl L1`跳轉(zhuǎn)到外層判斷的第二個分支判斷`var2 > var3`,如果成立則jl指令不生效,繼續(xù)判斷內(nèi)層IF語句,由于使用的是AND與運算,則需要順序判斷,判斷不通過直接`jle l2`,如果判斷通過則跳轉(zhuǎn)到`jle lop_end`不執(zhí)行,此時直接執(zhí)行`xor ecx,ecx`完成分支。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? x DWORD 100

? y DWORD 200

? z DWORD 300

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ? mov eax,dword ptr ds:[var1]

? ? cmp eax,dword ptr ds:[var2]? ? ? ? ; if(var1 >= var2) ?

? ? jl L1

? ??

? ? mov eax,dword ptr ds:[x]

? ? cmp eax,dword ptr ds:[y]? ? ? ? ? ?; if((x<y)) ?

? ? jge L2

? ??

? ? mov eax,dword ptr ds:[z]? ? ? ? ? ?; if((z>y)) ?

? ? cmp eax,dword ptr ds:[y]

? ? jle L2

? ??

? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ? ? ; printf("xor eax,eax")

? ? jmp lop_end


? L1:

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,dword ptr ds:[var3]? ? ? ; if(var2 > var3) ?

? ? jle lop_end

? ? xor ecx,ecx? ? ? ? ? ? ? ? ? ? ? ; printf("xor ecx,ecx")

? ? jmp lop_end

? L2:

? ? xor ebx,ebx? ? ? ? ? ? ? ? ? ? ? ; printf("xor ebx,ebx")

? ? jmp lop_end

? ??

? lop_end:

? ? int 3


? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.6 IF語句三層嵌套


這段C++代碼定義了6個整型變量并檢查它們的值是否滿足多個條件。首先,它檢查var1是否大于等于var2并且var2小于等于var3或者var3大于var1,如果滿足,則進入下一個if塊。在下一個if塊中,它檢查x是否為偶數(shù)或y是否為奇數(shù),如果滿足,則進一步檢查result是否等于1,如果是,則輸出字符串"xor eax, eax"。這段代碼實現(xiàn)了多個條件的邏輯判斷,并且包含了算術(shù)和邏輯運算。


三層嵌套IF語句,轉(zhuǎn)換為匯編語句稍微復(fù)雜一些,但大方向不變,還是要由外部到內(nèi)部,依次構(gòu)建每一個分支按照此順序構(gòu)建,其實并不難。

```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int x = 100, y = 200, z = 300;

? int var1 = 20,var2 = 10,var3 = 50;

? int result = 1;


? if ((var1 >= var2) && (var2 <= var3) || (var3 > var1))

? {

? ? if ((x % 2 == 0) || (y % 2 != 0))

? ? {

? ? ? if (result == 1)

? ? ? ? printf("xor eax,eax");

? ? }

? }

? return 0;

}

```

將以上代碼轉(zhuǎn)為匯編語句,首先判斷`(var1 >= var2) && (var2 <= var3)`此語句由于使用了AND所以需要判斷等式兩邊的結(jié)果,只要兩邊有一處不為真,就需要比較`(var3 > var1)`或運算結(jié)果,如果或運算為真則跳轉(zhuǎn)到`L1`標簽處,繼續(xù)執(zhí)行內(nèi)層IF比較語句。

```ASM

? ? .386p

? ? .model flat,stdcall

? ? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? ? x DWORD 100

? ? y DWORD 200

? ? var1 DWORD 20

? ? var2 DWORD 10

? ? var3 DWORD 50

? ? result DWORD 1

.code

? ? main PROC

? ??

? ? ? ? mov eax,dword ptr ds:[var1]

? ? ? ? cmp eax,dword ptr ds:[var2]? ? ? ?; and var1 >= var2

? ? ? ? jl L4

? ? ? ??

? ? ? ? mov eax,dword ptr ds:[var2]

? ? ? ? cmp eax,dword ptr ds:[var3]? ? ? ?; and var2 <= var3

? ? ? ? jle L1

? ? ? ??

? ? L4:

? ? ? ? mov eax,dword ptr ds:[var3]

? ? ? ? cmp eax,dword ptr ds:[var1]? ? ? ?; or var3 > var1

? ? ? ? jle lop_end

? ? L1:

? ? ? ? mov eax,dword ptr ds:[x]

? ? ? ? and eax,080000001h? ? ? ? ? ? ? ? ; eax = eax % 2 = 0

? ? ? ? jns L2? ? ? ? ? ? ? ? ? ? ? ? ? ? ; eax = 0 則跳轉(zhuǎn)

? ? ? ??

? ? ? ? dec eax

? ? ? ? or eax,0fffffffeh? ? ? ? ? ? ? ? ?; eax = eax % 2 != 0

? ? ? ? inc eax

? ? L2:

? ? ? ? mov eax,dword ptr ds:[result]

? ? ? ? test eax,eax? ? ? ? ? ? ? ? ? ? ? ; if(result == 1)

? ? ? ? jne L3

? ? ? ? jmp lop_end

? ? L3:

? ? ? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ? ?; printf("xor eax,eax")

? ? ? ? jmp lop_end

? ? lop_end:

? ? ? ? int 3


? ? ? ? invoke ExitProcess,0

? ? main ENDP

END main

```


### 11.7 IF語句多選擇分支


這段C++代碼定義了3個整型變量并根據(jù)它們的值進行條件判斷。它檢查var1是否大于20,如果是,則輸出字符串"xor eax, eax"。如果var1不大于20,則它將檢查var2是否大于10,如果是,則輸出字符串"xor ebx, ebx"。如果var2不大于10,則它將檢查var2是否小于var3,如果是,則輸出字符串"xor ecx, ecx"。如果以上條件都不滿足,則輸出字符串"xor edx, edx"。這段代碼實現(xiàn)了簡單的條件分支和邏輯判斷。


多重選擇分支結(jié)構(gòu),其本質(zhì)就是對某些條件一直判斷下去,直到遇到符合條件的表達式則執(zhí)行表達式內(nèi)的語句塊。

```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int var1 = 20,var2 = 10,var3 = 50;


? if (var1 > 20)

? ? printf("xor eax,eax");

? else if (var2 > 10)

? ? printf("xor ebx,ebx");

? else if (var2 < var3)

? ? printf("xor ecx,ecx");

? else

? ? printf("xor edx,edx");


? return 0;

}

```

多重判斷語句編譯器生成匯編指令與我們?nèi)说乃季S習(xí)慣稍有些不同,對于我們自己的思維方式,總喜歡將判斷語句放置到匯編函數(shù)開頭部分,通過線性比較的方式分別比較不同的分支條件,每個分支條件將被鏈接到底部的特定語句塊上。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

??

? ? mov eax,dword ptr ds:[var1]

? ? cmp eax,20? ? ? ? ? ? ? ? ? ? ? ?; var1 > 20

? ? jg L1

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,10? ? ? ? ? ? ? ? ? ? ? ?; var2 > 10

? ? jg L2

? ? cmp eax,dword ptr ds:[var3]

? ? jl L3? ? ? ? ? ? ? ? ? ? ? ? ? ? ; var2 < var3

? ? xor edx,edx? ? ? ? ? ? ? ? ? ? ? ; printf("xor edx,edx")

? ? jmp lop_end


? L1:

? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ? ; printf("xor eax,eax")

? ? jmp lop_end

? L2:

? ? xor ebx,ebx? ? ? ? ? ? ? ? ? ? ? ; printf("xor ebx,ebx")

? ? jmp lop_end

? L3:

? ? xor ecx,ecx? ? ? ? ? ? ? ? ? ? ? ; printf("xor ecx,ecx")

? ? jmp lop_end

? lop_end:

? ? int 3


? ? invoke ExitProcess,0

? main ENDP

END main

```

而編譯器為了盡可能優(yōu)化,寫出的代碼可能是以下這樣子的,編譯器并不會采取方便我們理解的方式來生成匯編指令集,而是對分支進行排序,通過順序依次向下執(zhí)行,如果條件跳轉(zhuǎn)不成立,則直接執(zhí)行緊隨跳轉(zhuǎn)其后的語句塊,當執(zhí)行結(jié)束后通過`jmp lop_end`統(tǒng)一跳轉(zhuǎn)到結(jié)束。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ? mov eax,dword ptr ds:[var1]

? ? cmp eax,20

? ? jle L1

? ? xor eax,eax? ? ? ? ? ? ? ? ; printf("xor eax,eax")

? ? jmp lop_end

? L1:

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,10

? ? jle L2

? ? xor ebx,ebx? ? ? ? ? ? ? ? ?; printf("xor ebx,ebx")

? ? jmp lop_end

? L2:

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,dword ptr ds:[var3]

? ? jge L3

? ? xor ecx,ecx? ? ? ? ? ? ? ? ? ; printf("xor ecx,ecx")??

? ? jmp lop_end

? L3:

? ? xor edx,edx? ? ? ? ? ? ? ? ? ; printf("xor edx,edx")

? ? jmp lop_end

? lop_end:

? ? int 3


? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.8 IF語句自增自減


執(zhí)行自增自減運算需要找一個臨時區(qū)域來存放自增后的數(shù)據(jù),所以首先要開辟局部空間,多數(shù)情況下開辟空間可在棧上,例如使用`sub esp,12`來分配??臻g,并初始化后即可使用,最后需要將該空間恢復(fù)。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.code

? main PROC

? ? push ebp

? ? mov ebp,esp

? ? sub esp,12? ? ? ? ? ? ? ? ? ? ; 開辟 3*4 =12 的空間

? ??

? ? lea edi,dword ptr ss:[ebp-12] ; 指向棧中基址

? ? mov ecx,3? ? ? ? ? ? ? ? ? ? ?; 填充次數(shù) 12/4 = 3?

? ? mov eax,0cccccccch? ? ? ? ? ? ; 填充物

? ? rep stosd? ? ? ? ? ? ? ? ? ? ?; 初始化開始


? ? mov dword ptr ss:[ebp-12],1

? ? mov dword ptr ss:[ebp-8],2? ? ; 給每個地址賦值

? ? mov dword ptr ss:[ebp-4],3

? ??

? ? mov eax,dword ptr ss:[ebp-12] ; 取第一個數(shù)據(jù)1

? ? mov ebx,dword ptr ss:[ebp-4]? ; 取第二個數(shù)據(jù)3

? ? add eax,ebx? ? ? ? ? ? ? ? ? ?; 執(zhí)行遞增

? ? mov dword ptr ss:[ebp-8],eax? ; 寫回棧

? ??

? ? add esp,12? ? ? ? ? ? ? ? ? ? ?; 平棧

? ? mov esp,ebp

? ? pop ebp

??

? ? invoke ExitProcess,0

? main ENDP

END main

```

首先我們先來編寫一段簡單的C代碼片段,如下代碼中我們使用了兩種自增符號,一種是`var1++`另一種是`++var2`兩種方式的匯編版本并不一致,仿寫是需要格外注意。

```C

#include <stdio.h>

#include <windows.h>


int main(int argc,char * argv[])

{

? int var1 = 20,var2 = 10,var3 = 50;


? if (var1++ >= 20 && ++var2 > 10)

? {

? ? printf("xor eax,eax");

? }

? return 0;

}

```

以下匯編代碼中需要注意,當我們使用`var1++`時程序是將`++后`的結(jié)果賦值到了棧中存放,并讓`var1`變量遞增,而判斷則使用的是棧中的原值,相反`++var1`則是在原值上直接進行操作,將操作結(jié)果賦值給原值后在進行判斷。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ? push ebp

? ? mov ebp,esp

? ? sub esp,8? ? ? ? ? ? ? ? ? ? ?; 開辟 2*4 =8 的空間

? ??

? ? lea edi,dword ptr ss:[ebp-8]? ; 指向棧中基址

? ? mov ecx,2? ? ? ? ? ? ? ? ? ? ?; 填充次數(shù) 8/4 = 2

? ? mov eax,0cccccccch? ? ? ? ? ? ; 填充物

? ? rep stosd? ? ? ? ? ? ? ? ? ? ?; 初始化開始


? ? mov eax,dword ptr ds:[var1]

? ? mov dword ptr ss:[ebp-8],eax? ?; 將var1存入臨時變量中

? ? add eax,1

? ? mov dword ptr ds:[var1],eax? ? ; 將相加后的結(jié)果寫回到var1

? ??

? ? cmp dword ptr ss:[ebp-8],20? ? ; 用原值與20對比

? ? jl L1

? ? mov dword ptr ss:[ebp-4],1? ? ?; 局部變量存放標志=1

? ? jmp L2

??

? L1: mov dword ptr ss:[ebp-4],0

? L2: cmp dword ptr ss:[ebp-4],0

? ? je lop_end


? ? mov eax,dword ptr ds:[var2]? ? ; 繼續(xù)執(zhí)行 ++var2

? ? add eax,1

? ? mov dword ptr ds:[var2],eax

? ? cmp dword ptr ds:[var2],10? ? ?; var2 > 10

? ? jle lop_end

? ??

? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ; printf("xor eax,eax")


? lop_end:

? ? add esp,8? ? ? ? ? ? ? ? ? ? ?; 平棧

? ? mov esp,ebp

? ? pop ebp

??

? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.9 IF語句三目運算符


C語言中提供了快捷判斷語句,唯一的三目運算符,該運算符其實就是壓縮版的`IF-ELSE`結(jié)構(gòu),其表達式與IF基本一致,但在AND運算符的影響下會與`IF-ELSE`結(jié)構(gòu)有些許的不同。

```C

#include <stdio.h>

#include <Windows.h>


int main(int argc,char *argv[])

{

? int var1 = 20, var2 = 10, var3 = 50;


? if ((var1 > var2 ? 1 : 0) && (var2 <= var3 ? 1 : 0))

? {

? ? printf("xor eax,eax");

? }

? return 0;

}

```

在仿寫這段C代碼的匯編版時,我們首先要注意他是一個AND比較操作,兩側(cè)必須同時為1才可,因為這個特性的存在,在編寫匯編代碼時,可以增加一個`flag`標志位,通過對該標志位的流水線判斷實現(xiàn)三目運算比較。

```ASM

? ? .386p

? ? .model flat,stdcall

? ? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? ? var1 DWORD 20

? ? var2 DWORD 10

? ? var3 DWORD 50

? ? flag DWORD ?

.code

? ? main PROC

? ? ? ? mov eax,dword ptr ds:[var1]

? ? ? ? cmp eax,dword ptr ds:[var2]? ?; var1 > var2 ?

? ? ? ? jle L1

? ? ? ? mov dword ptr ds:[flag],1? ? ?; 表達式1成立

? ? ? ? jmp L2


? ? L1: mov dword ptr ds:[flag],0

? ? L2: cmp dword ptr ds:[flag],0

? ? ? ? je lop_end

? ? ? ??

? ? ? ? mov eax,dword ptr ds:[var2]

? ? ? ? cmp eax,dword ptr ds:[var3]? ?; var2 <= var3

? ? ? ? jg L3

? ? ? ? mov dword ptr ds:[flag],1? ? ?; 表達式2成立

? ? ? ? jmp L4

? ? ? ??

? ? L3: mov dword ptr ds:[flag],0

? ? L4: cmp dword ptr ds:[flag],0

? ? ? ? je lop_end

? ? ? ??

? ? ? ? xor eax,eax? ? ? ? ? ? ? ? ? ?; printf("xor eax,eax")

? ? ? ? jmp lop_end

? ? ? ??

? ? lop_end:

? ? ? ? int 3

? ? ? ??

? ? ? ? invoke ExitProcess,0

? ? main ENDP

END main

```


### 11.10 IF語句嵌套移位


這段C++代碼定義了兩個函數(shù)func_a和func_b,它們分別包含了條件判斷和邏輯運算。在函數(shù)func_a中,它首先對三個整型變量進行了位運算,然后通過邏輯或連接這些運算結(jié)果,進入下一個if塊。在這個if塊中,它再次進行多個邏輯判斷和比較,判斷條件包括被位運算處理過的變量值和固定的數(shù)值50。如果所有條件都滿足,則輸出字符串"xor eax, eax"。在函數(shù)func_b中,它通過取模和位運算對三個整型變量進行處理,并進入下一個if塊。在if塊內(nèi),它進行了大于比較,并輸出字符串"xor ebx, ebx"。這段代碼實現(xiàn)了對多個變量的復(fù)雜運算和邏輯判斷。


```C

#include <stdio.h>

#include <windows.h>


int func_a()

{

? ? int var1 = 20,var2 = 10,var3 = 50;


? ? if (((var1 << 2) ^ (var2 << 3)) || ((var2 << 1) ^ (var3 << 3)))

? ? {

? ? ? ? if ((var1 >= var2) || (var2 <= var3) && (var3 == 50))

? ? ? ? {

? ? ? ? ? ? printf("xor eax,eax");

? ? ? ? }

? ? }

? ? return 0;

}


int func_b()

{

? ? int var1 = 20,var2 = 10,var3 = 50;


? ? if (((var1 << 2) % 2) || (var3 >> 1) % 3)

? ? {

? ? ? ? if (((var1 << 2) + 10) > 50)

? ? ? ? {

? ? ? ? ? ? printf("xor ebx,ebx");

? ? ? ? }

? ? }

? ? return 0;

}

```

先來看第一個`func_a()`函數(shù)如何進行仿寫,首先`(((var1 << 2) ^ (var2 << 3)) || ((var2 << 1) ^ (var3 << 3)))`外部嵌套是一個OR運算,按照順序先拆分。


?- 執(zhí)行`((var1 << 2) ^ (var2 << 3))`先將數(shù)據(jù)`shl`左移,移動后將兩邊數(shù)據(jù)進行`xor`異或,如果為0則比較等式2。

?- 執(zhí)行`((var2 << 1) ^ (var3 << 3)))`比較等式2,如果為真,則繼續(xù)執(zhí)行內(nèi)層的移位與相加運算,為假跳轉(zhuǎn)到結(jié)束。


```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ? ; ((var1 << 2) ^ (var2 << 3))

? ? mov eax,dword ptr ds:[var1]

? ? shl eax,2

? ? mov ecx,dword ptr ds:[var2]

? ? shl ecx,3

? ? xor eax,ecx

? ? je L1

? ??

? ? ; ((var2 << 1) ^ (var3 << 3))

? ? mov eax,dword ptr ds:[var2]

? ? shl eax,1

? ? mov eax,dword ptr ds:[var3]

? ? shl ecx,3

? ? xor eax,ecx

? ? je lop_end

? ??

? ? ; (var1 >= var2)

? L1: mov eax,dword ptr ds:[var1]

? ? cmp eax,dword ptr ds:[var2]

? ? jge L2

? ??

? ? ; (var2 <= var3)

? ? mov eax,dword ptr ds:[var2]

? ? cmp eax,dword ptr ds:[var3]

? ? jg lop_end

? L2:?

? ? ; (var3 == 50)

? ? cmp dword ptr ds:[var3],50

? ? jnz lop_end

??

? ? xor eax,eax? ? ? ? ? ? ? ?; printf("xor eax,eax")

? ? jmp lop_end

??

? lop_end:

? ? int 3

? ? invoke ExitProcess,0

? main ENDP

END main

```

第二個函數(shù)`func_b()`與第一個基本一致,我們只需要將等式進行拆分,拆分后按照括號優(yōu)先級依次進行仿寫并增加跳轉(zhuǎn)指令即可。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


.data

? var1 DWORD 20

? var2 DWORD 10

? var3 DWORD 50

.code

? main PROC

? ? ; ((var1 << 2) % 2)

? ? mov eax,dword ptr ds:[var1]

? ? shl eax,2

? ? and eax,080000001h? ? ? ? ? ; var1 % 2

? ? jns L2? ? ? ? ? ? ? ? ? ? ? ; 非負數(shù)則跳轉(zhuǎn)

??

? ? ; (var3 >> 1) % 3? ? ? ? ? ?; 為負數(shù)執(zhí)行第二個表達式

? L1: mov eax,dword ptr ds:[var3]

? ? sar eax,1? ? ? ? ? ? ? ? ? ?; var3 >> 1

? ? cdq? ? ? ? ? ? ? ? ? ? ? ? ?; 擴展為8字節(jié)

? ? mov ecx,3? ? ? ? ? ? ? ? ? ?; 除以3

? ? idiv ecx

? ? test edx,edx? ? ? ? ? ? ? ? ; 比較余數(shù)是否為0

? ? je lop_end


? ? ; ((var1 << 2) + 10) > 50

? L2: mov eax,dword ptr ds:[var1]

? ? shl eax,2

? ? add eax,10

? ? cmp eax,50

? ? jle lop_end

? ??

? ? xor eax,eax? ? ? ? ? ? ? ? ? ; printf("xor ebx,ebx")

? ? jmp lop_end


? lop_end:

? ? int 3

? ? invoke ExitProcess,0

? main ENDP

END main

```


### 11.11 IF語句運算符混合


如果將多種運算符混合在一起,那么我們在仿寫匯編代碼是可能會麻煩一些,尤其是涉及到多種比較與運算時,我們以計算平年閏年為例,看看該如何實現(xiàn)復(fù)雜運算符的仿寫。


?- 首先閏年時年份對400取余等于0的數(shù),或者對4取余等于0并且對100取余不等于0的數(shù)。


```C

#include <windows.h>

#include <stdio.h>


int main(int argc,char * argv[])

{

? int year = 2017;

? if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))

? {

? ? printf("%d 閏年 \n", year);

? }

? {

? ? printf("%d 平年 \n", year);

? }

? return 0;

}

```

老樣子,按照以前的步驟,先對等式拆分,拆分后依次實現(xiàn)每一個等式,最后將這些等式通過判斷語句串聯(lián)起來即可,這段代碼除使用了`idiv`除法指令外,其他地方與如上內(nèi)容保持一致。

```ASM

? .386p

? .model flat,stdcall

? option casemap:none


include windows.inc

include kernel32.inc

includelib kernel32.lib


include msvcrt.inc

includelib msvcrt.lib


.data

? Year DWORD 2017

? szFmtR BYTE '%d 是閏年',0dh,0ah,0

? szFmtP BYTE '%d 是平年',0dh,0ah,0

.code

? main PROC

? ??

? ? mov eax,dword ptr ds:[Year]? ? ?; year = 2017;

? ? cdq

? ? mov ecx,400

? ? idiv ecx? ? ? ? ? ? ? ? ? ? ? ? ; year % 400 == 0

? ? test edx,edx

? ? je L1

? ??

? ? mov eax,dword ptr ds:[Year]

? ? and eax,080000003h? ? ? ? ? ? ? ; year % 4

? ? test eax,eax

? ? jne L2

? ??

? ? mov eax,dword ptr ds:[Year]

? ? cdq

? ? mov ecx,100

? ? idiv ecx? ? ? ? ? ? ? ? ? ? ? ? ?; year % 100 != 0

? ? test edx,edx? ? ? ? ? ? ? ? ? ? ?; 比較余數(shù)

? ? je L2? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 跳轉(zhuǎn)則是平年

? ??

? L1: mov eax,dword ptr ds:[Year]

? ? invoke crt_printf,addr szFmtR,eax? ? ?; 是閏年

? ? jmp lop_end


? L2: mov eax,dword ptr ds:[Year]

? ? invoke crt_printf,addr szFmtP,eax? ? ?; 是平年

? ? jmp lop_end?


? lop_end:

? ? int 3?


? main ENDP

END main

```


本文作者: 王瑞

本文鏈接: https://www.lyshark.com/post/3cc3d473.html

版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請注明出處!


5.11 匯編語言:仿寫IF條件語句的評論 (共 條)

分享到微博請遵守國家法律
宁都县| 武功县| 临武县| 长白| 股票| 美姑县| 碌曲县| 文成县| 丹寨县| 彭泽县| 夏邑县| 盘山县| 彰化市| 河池市| 辽源市| 福贡县| 内江市| 黄浦区| 延安市| 芦溪县| 泾川县| 乐陵市| 贺兰县| 南乐县| 黄龙县| 永安市| 会东县| 崇明县| 独山县| 宁河县| 乳山市| 江达县| 改则县| 琼结县| 名山县| 台南县| 清丰县| 瓮安县| 南漳县| 河源市| 贡嘎县|