5.12 匯編語言:仿寫While循環(huán)語句
循環(huán)語句(While)一種基本控制結(jié)構(gòu),它允許程序在條件為真的情況下重復(fù)執(zhí)行一段代碼塊,直到條件為假為止。循環(huán)語句在處理需要重復(fù)執(zhí)行的任務(wù)時非常有用,它可以讓程序更加高效地處理大量數(shù)據(jù)或者重復(fù)性操作。
一般來說,While循環(huán)由一個條件表達式、一個代碼塊組成。在每次循環(huán)迭代開始時,程序會首先檢查條件表達式的值,如果為真,則執(zhí)行代碼塊,然后再次檢查條件表達式的值。只要條件表達式為真,循環(huán)就會一直繼續(xù)執(zhí)行;一旦條件表達式為假,循環(huán)將停止,程序繼續(xù)執(zhí)行循環(huán)之后的代碼。
### 12.12 Do-While 循環(huán)結(jié)構(gòu)優(yōu)化
DO語句先執(zhí)行循環(huán)體,后進行判斷,如果通過則跳轉(zhuǎn)到循環(huán)體首部繼續(xù)執(zhí)行,未通過則直接順序向下走。DO循環(huán)效率最高,該循環(huán)在結(jié)構(gòu)上非常精簡,利用了程序執(zhí)行時由低到高的特性,由于結(jié)構(gòu)內(nèi)只在結(jié)尾處做了判斷,只使用了一條判斷語句即實現(xiàn)了循環(huán),因此已經(jīng)無需在結(jié)構(gòu)上進行任何優(yōu)化了。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
.data
? count DWORD ?
.code
? main PROC
? ? mov dword ptr ds:[count],0? ? ?; 初始化循環(huán)次數(shù)
? S1:
? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ; 執(zhí)行循環(huán)體
? ? mov eax,dword ptr ds:[count]? ?; 取出計數(shù)器
? ? add eax,1? ? ? ? ? ? ? ? ? ? ? ; 遞增
? ? mov dword ptr ds:[count],eax? ?; 回寫
? ??
? ? cmp dword ptr ds:[count],10? ? ; 與10做對比
? ? jl S1? ? ? ? ? ? ? ? ? ? ? ? ? ; 小于則繼續(xù)循環(huán)
? ? int 3
? ? invoke ExitProcess,0
? main ENDP
END main
```
### 12.13 While 循環(huán)結(jié)構(gòu)優(yōu)化
While語句先判斷循環(huán)條件,后執(zhí)行循環(huán)體,由于需要判斷,該循環(huán)的構(gòu)建需要使用兩個跳轉(zhuǎn)語句方可實現(xiàn)。While循環(huán)結(jié)構(gòu)的效率要比Do循環(huán)結(jié)構(gòu)低,While循環(huán)結(jié)構(gòu)先比較再循環(huán),因此無法利用程序執(zhí)行順序來完成循環(huán),又因為While循環(huán)結(jié)構(gòu)使用了2個跳轉(zhuǎn)指令,在程序流程上就弱于Do循環(huán)。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
.data
? count DWORD ?
.code
? main PROC
? ? mov dword ptr ds:[count],0? ? ? ? ? ? ; 設(shè)置while初始化
? S1:
? ? cmp dword ptr ds:[count],10? ? ? ? ? ?; 設(shè)置最大循環(huán)數(shù)
? ? jge loop_end? ? ? ? ? ? ? ? ? ? ? ? ? ; 判斷是否循環(huán)結(jié)束
? ??
? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ? ? ? ?; 執(zhí)行循環(huán)體
? ??
? ? mov eax,dword ptr ds:[count]? ? ? ? ? ?; 取出循環(huán)條件
? ? add eax,1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 遞增
? ? mov dword ptr ds:[count],eax? ? ? ? ? ?; 寫回
? ? jmp S1
??
? loop_end:
? ? int 3
? ? invoke ExitProcess,0
? main ENDP
END main
```
為了提升While循環(huán)執(zhí)行效率,編譯器通常會將其轉(zhuǎn)換為對等的Do循環(huán),如果循環(huán)無法轉(zhuǎn)成對等的Do循環(huán),則可使用單層IF結(jié)構(gòu)內(nèi)部嵌套Do循環(huán)的方式來實現(xiàn),外層IF則用來判斷Do循環(huán)是否執(zhí)行,例如如下案例中,首先外層使用IF語句判斷循環(huán)條件,該語句內(nèi)部則嵌套一個Do循環(huán),以此來將While轉(zhuǎn)為Do。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
.data
? count DWORD ?
.code
? main PROC
? ? mov dword ptr ds:[count],0? ? ? ? ? ? ; 設(shè)置初始條件
? ??
? ? ; 初次判斷條件是否滿足
? ? cmp dword ptr ds:[count],10
? ? jge loop_end
? S1:
? ? ; 循環(huán)體內(nèi)部語句
? ? xor eax,eax
? ??
? ? ; 遞增
? ? add dword ptr ds:[count],1
? ??
? ? ; 比較條件是否滿足
? ? cmp dword ptr ds:[count],10
? ? jl S1
? ??
? loop_end:
? ? int 3
? ? invoke ExitProcess,0
? main ENDP
END main
```
### 12.15 Loop 循環(huán)結(jié)構(gòu)優(yōu)化
上方提到過的三種循環(huán)模式都是通過跳轉(zhuǎn)指令與計數(shù)器構(gòu)建的,與這三者不同匯編中默認提供了loop指令,專門用來實現(xiàn)循環(huán)計數(shù)功能,由于是匯編指令,所以此loop語句必須讀入ECX寄存器內(nèi)的次數(shù)作為循環(huán)終止條件,每次讀入會自動遞減,具體匯編代碼如下。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
.data
? count DWORD ?
? result DWORD ?
? ArrayDW DWORD 8,7,9,4,3,7,5,8,9,3,0h
.code
? main PROC
? ? ; 通過loop實現(xiàn)的單層循環(huán)體
? ? xor eax,eax? ? ? ? ? ? ? ? ? ? ? ?; 用于累加數(shù)據(jù)
? ? mov ecx,10? ? ? ? ? ? ? ? ? ? ? ? ; 設(shè)置循環(huán)次數(shù)
? s1:
? ? mov dword ptr ds:[count],ecx? ? ? ; 將循環(huán)次數(shù)備份
? ? xor ecx,ecx? ? ? ? ? ? ? ? ? ? ? ?; 清空寄存器
? ? mov ecx,10
? ? add eax,ecx? ? ? ? ? ? ? ? ? ? ? ?; 結(jié)果想加到eax
? ? mov ecx,dword ptr ds:[count]? ? ? ; 恢復(fù)循環(huán)次數(shù)
? ? loop s1
? ??
? ? mov dword ptr ds:[result],eax? ? ?; 獲取相加后的結(jié)果
? ??
? ? invoke ExitProcess,0
? main ENDP
END main
```
如果是雙層循環(huán)體,則在使用loop語句構(gòu)建時,必須考慮外層ECX中的循環(huán)計數(shù)該如何處理,通常會把外層循環(huán)計數(shù)保存在棧中,這是非常的理想的,保存在一個變量內(nèi)也勉強湊活,只是效率上沒有直接壓入棧中高。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
.data
? count DWORD ?
? result DWORD ?
? ArrayDW DWORD 8,7,9,4,3,7,5,8,9,3,0h
.code
? main PROC
? ? ; 通過loop實現(xiàn)嵌套循環(huán)體
? ? mov ecx,9? ? ? ? ? ? ? ? ? ?; 控制外層循環(huán)數(shù)
? s2:
? ? push ecx? ? ? ? ? ? ? ? ? ? ; 保存外層循環(huán)數(shù)
? ? mov ecx,9? ? ? ? ? ? ? ? ? ?; 設(shè)置內(nèi)層循環(huán)數(shù)
? s3:
? ? mov eax,dword ptr ds:[ArrayDW + ecx * 4]
? ? cmp eax,3? ? ? ? ? ? ? ? ? ? ; 與3作比較大于則跳
? ? ja jump
? ? loop s3
? jump:
? ? xor eax,eax
? ? pop ecx
? ? loop s2
? ??
? ? invoke ExitProcess,0
? main ENDP
END main
```
運用Loop指令實現(xiàn)對數(shù)組`MyArray`的由大到小排序,其中`ArraySort`子過程用于由大到小排序,子過程`PrintArray`用于循環(huán)輸出排序后的結(jié)果。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? MyArray DWORD 25,74,89,33,24,67,93,15,78,92
? Count DWORD 10
? PrCount DWORD ?
? szFmt BYTE '%d ',0dh,0ah,0
.code
? ; 數(shù)組排序函數(shù)
? ArraySort PROC
? ? ? mov ecx,dword ptr ds:[Count]? ? ? ; 獲取到數(shù)組元素數(shù)
? ? ? dec ecx? ? ? ? ? ? ? ? ? ? ? ? ? ?; 數(shù)組減1
? ? L1:
? ? ? push ecx? ? ? ? ? ? ? ? ? ? ? ? ? ; 入棧保存
? ? ? lea esi,dword ptr ds:[MyArray]? ? ; 得到數(shù)組基地址
? ? ??
? ? L2:
? ? ? mov eax,dword ptr ds:[esi]
? ? ? cmp eax,dword ptr ds:[esi + 4]? ? ; 比較第一個數(shù)組與第二個
? ? ? jg L3
? ? ??
? ? ? xchg eax,[esi + 4]? ? ? ? ? ? ? ? ; 交換數(shù)據(jù)
? ? ? mov [esi],eax
? ? L3:
? ? ? add esi,4
? ? ? loop L2
? ? ??
? ? ? pop ecx? ? ? ? ? ? ? ? ? ? ? ? ? ?; 彈出數(shù)據(jù)
? ? ? loop L1
? ? ? ret
? ArraySort ENDP
??
? ; 循環(huán)輸出元素
? PrintArray PROC
? ? ? mov dword ptr ds:[PrCount],0? ? ? ? ? ? ; 初始化元素
? ? ??
? ? L1:
? ? ? mov ecx,dword ptr ds:[PrCount]? ? ? ? ? ; 獲取循環(huán)次數(shù)
? ? ? cmp ecx,10? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 對比十次
? ? ? jge lop_end? ? ? ? ? ? ? ? ? ? ? ? ? ? ?; 判斷是否可結(jié)束循環(huán)
? ? ??
? ? ? lea eax,dword ptr ds:[MyArray]? ? ? ? ? ; 獲取數(shù)組基地址
? ? ? mov ebx,dword ptr ds:[eax + ecx * 4]? ? ; 比例因子尋址
? ? ? invoke crt_printf,addr szFmt,ebx
? ? ??
? ? ? mov ecx,dword ptr ds:[PrCount]? ? ? ? ? ; 取循環(huán)計數(shù)
? ? ? add ecx,1
? ? ? mov dword ptr ds:[PrCount],ecx? ? ? ? ? ; 遞增后回寫
? ? ? jmp L1
? ? ??
? ? lop_end:
? ? ? int 3
? ? ? ret
? PrintArray ENDP
? main PROC
? ? invoke ArraySort
? ? invoke PrintArray
? main ENDP
END main
```
### 12.16 仿寫Do-While循環(huán)體
這段C++代碼定義了一個包含10個元素的整型數(shù)組,然后在do-while循環(huán)中對數(shù)組進行遍歷,并檢查每一個數(shù)組元素是否滿足下面的條件:它的值大于10并且下一個數(shù)組元素的值小于等于20。如果找到了滿足條件的數(shù)組元素,則輸出它和下一個數(shù)組元素的值,并跳出循環(huán)。如果循環(huán)結(jié)束都沒有找到符合條件的數(shù)組元素,則直接退出程序。這段代碼展示了如何使用循環(huán)和條件判斷對數(shù)組進行遍歷和篩選。
```C
#include <stdio.h>
#include <Windows.h>
int main(int argc, char *argv[])
{
? int Array[10] = { 56,78,33,45,78,90,32,15,56,67 };
? int index = 0;
? do
? {
? ? if (Array[index] > 10 && Array[index + 1] <= 20)
? ? {
? ? ? printf("array[1] => %d array[2] => %d \n", Array[index], Array[index + 1]);
? ? ? break;
? ? }
? ? index = index + 1;
? } while (index < 10);
? system("pause");
? return 0;
}
```
由于是自己仿寫,所以此處我使用了For形式的循環(huán)模式,首先初始化`count=0`進入L1循環(huán)后先來判斷數(shù)組中第一個元素是否小于10,接著通過`add eax,1`將比例因子向后移動4字節(jié),繼續(xù)比較第二個數(shù)值是否小于等于20,如果都存在則直接輸出該結(jié)果,并通過`jmp lop_end`跳轉(zhuǎn)到程序結(jié)尾,否則遞增`count`元素,并跳轉(zhuǎn)到循環(huán)開頭繼續(xù)查找。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? MyArray DWORD 56,78,33,45,78,90,32,15,56,67
? count DWORD ?
? szFmt BYTE 'array[1] => %d array[2] => %d ',0dh,0ah,0
.code
? main PROC
? ? mov dword ptr ds:[count],0? ? ? ? ? ? ? ? ? ? ?; int index = 0;
? L1:
? ? mov eax,dword ptr ds:[count]
? ? cmp dword ptr ds:[MyArray + eax * 4],10? ? ? ? ; Array[index] > 10
? ? jle L2
? ??
? ? mov eax,dword ptr ds:[count]
? ? add eax,1
? ? cmp dword ptr ds:[MyArray + eax * 4],20? ? ? ? ; Array[index + 1] <= 20
? ? jg L2
? ??
? ? mov esi,dword ptr ds:[MyArray + eax * 4 - 4]? ?; esi = Array[index]
? ? mov edi,dword ptr ds:[MyArray + eax * 4]? ? ? ?; edi = Array[index+1]
? ? invoke crt_printf,addr szFmt,esi,edi
? ? jmp lop_end? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; break
? L2:
? ? mov eax,dword ptr ds:[count]
? ? add eax,1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; index = index + 1;
? ? mov dword ptr ds:[count],eax
? ? cmp dword ptr ds:[count],10? ? ? ? ? ? ? ? ? ? ; index < 10
? ? jl L1
? lop_end:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?; break
? ? int 3
? main ENDP
END main
```
### 12.17 仿寫While循環(huán)體
這段C++代碼定義了一個包含10個元素的整型數(shù)組,然后在while循環(huán)中對數(shù)組進行遍歷,輸出每一個數(shù)組元素的值。循環(huán)使用一個count變量作為計數(shù)器,從0開始逐步增加,直到count的值等于數(shù)組元素的總數(shù)。在循環(huán)內(nèi)部,它通過count變量訪問數(shù)組元素,并將它們的值作為參數(shù)傳遞給printf函數(shù)進行輸出。這段代碼展示了如何使用循環(huán)結(jié)構(gòu)遍歷數(shù)組元素。
```C
#include <stdio.h>
#include <Windows.h>
int main(int argc,char *argv[])
{
? int Array[10] = { 1,2,3,4,5,6,7,8,9,10 };
? int count = 0;
? while (count < sizeof(Array) / sizeof(int))
? {
? ? printf("value = %d \n", Array[count]);
? ? count = count + 1;
? }
? return 0;
}
```
首先初始化部分,設(shè)置`ecx寄存器`為比例因子,進入循環(huán)體后,通過尋址公式`ds:[esi + ecx * 4]`實現(xiàn)對數(shù)組地址的遞增輸出,此代碼中的`ds:[count]`只用于控制循環(huán)體循環(huán)次數(shù),`ecx寄存器`則只用做尋址因子使用。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? MyArray DWORD 1,2,3,4,5,6,7,8,9,10
? count DWORD ?
? szFmt BYTE 'value = %d ',0dh,0ah,0
.code
? main PROC
? ? mov dword ptr ds:[count],0? ? ? ? ? ? ? ? ?; 初始化循環(huán)
? ? mov ecx,0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 設(shè)置循環(huán)計數(shù)(比例因子)
? S1:
? ? cmp dword ptr ds:[count],lengthof MyArray? ; 與數(shù)組總長度對比
? ? jge lop_end? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ; 是否結(jié)束
? ??
? ? lea esi,dword ptr ds:[MyArray]? ? ? ? ? ? ?; 獲取數(shù)組基地址
? ? mov ebx,dword ptr ds:[esi + ecx * 4]? ? ? ?; 比例因子尋址
? ? invoke crt_printf,addr szFmt,ebx? ? ? ? ? ?; 調(diào)用系統(tǒng)crt
? ??
? ? mov ecx,dword ptr ds:[count]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?; 計次循環(huán)遞增
? ? mov dword ptr ds:[count],ecx
? ? jmp S1
? lop_end:
? ? int 3
? ? invoke ExitProcess,0
? main ENDP
END main
```
### 12.18 仿寫While三層循環(huán)體
這段C++代碼實現(xiàn)了一個三重循環(huán),用于生成所有由1到4中不重復(fù)的三個數(shù)字組成的序列。在外層循環(huán)中,它使用變量x從1開始逐個增加,直到其值大于等于5。在中間循環(huán)中,它使用變量y從1開始逐個增加,直到其值大于等于5。在最內(nèi)層循環(huán)中,它使用變量z從1開始逐個增加,直到其值大于等于5。然后它檢查當(dāng)前的x、y、z變量是否滿足三個數(shù)不重復(fù)的條件,如果滿足,則輸出這三個數(shù)字,并進入第三個循環(huán)。循環(huán)結(jié)構(gòu)使用變量z逐項增加,并在檢查條件后繼續(xù)下一個序列的生成。當(dāng)z逐項增加完成后,中間循環(huán)使用變量y逐項增加。如此循環(huán),直到所有由1到4的三個數(shù)字序列都被產(chǎn)生出來為止。
```C
#include <windows.h>
#include <stdio.h>
int main(int argc,char * argv[])
{
? int x=1, y=1, z=1;
? while (x < 5)
? {
? ? while (y < 5)
? ? {
? ? ? while (z < 5)
? ? ? {
? ? ? ??
? ? ? ? if (x != z && x != y && y != z)
? ? ? ? {
? ? ? ? ? printf("%d,%d,%d \n", x, y, z);
? ? ? ? }
? ? ? ? z = z + 1;
? ? ? }
? ? ? z = 1;
? ? ? y = y + 1;
? ? }
? ? y = 1;
? ? x = x + 1;
? }
? return 0;
}
```
由于這段C代碼使用了`三層While`循環(huán),其構(gòu)建為匯編代碼時稍有些難度,我們首先把外層框架構(gòu)建好,先來構(gòu)建一個`二層While循環(huán)`結(jié)構(gòu),如下匯編代碼中,我們通過變量`x DWORD`控制外層循環(huán)次數(shù),內(nèi)層循環(huán)次數(shù)則使用`y DWORD`變量來控制,當(dāng)每次需要修改或讀取變量時,則通過`mov ecx,dword ptr ds:[x]`指令將計數(shù)次數(shù)讀入到`ecx寄存器`內(nèi),以此來保證循環(huán)次數(shù)不沖突。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? x DWORD ?
? y DWORD ?
? szFmt BYTE '外層循環(huán): %d ---> 內(nèi)層循環(huán):%d ',0dh,0ah,0
.code
? main PROC
? ? mov dword ptr ds:[x],1? ? ? ? ? ?; x = 1
??
? ? ; 外層循環(huán)
? L1:
? ? mov ecx,dword ptr ds:[x]
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; x < 5
? ? jge lop_end
? ??
? ? ; 內(nèi)層循環(huán)
? ? mov dword ptr ds:[y],1? ? ? ? ? ?; y = 1
? ??
? L2:
? ? mov ecx,dword ptr ds:[y]? ? ? ? ?; ecx = y
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; y < 5
? ? jge L3
? ??
? ? ; 循環(huán)過程執(zhí)行(存放循環(huán)過程代碼)
? ? mov esi,dword ptr ds:[x]
? ? mov edi,dword ptr ds:[y]
? ? invoke crt_printf,addr szFmt,esi,edi
? ? mov ecx,dword ptr ds:[y]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ; y = y + 1
? ? mov dword ptr ds:[y],ecx
? ? jmp L2
? L3:
? ? mov ecx,dword ptr ds:[x]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ; x = x + 1
? ? mov dword ptr ds:[x],ecx
? ? jmp L1
??
? lop_end:
? ? int 3?
? main ENDP
END main
```
既然二層結(jié)構(gòu)可以被構(gòu)建出來,那么我們利用這個原理,在二層基礎(chǔ)之上增加一個`z DWORD`變量,用于對最內(nèi)部的`While`語句進行計數(shù),由此我們就可以構(gòu)建出`三層While循環(huán)`結(jié)構(gòu),匯編代碼如下所示,仔細看完全能看懂的。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? x DWORD ?
? y DWORD ?
? z DWORD ?
? szFmt BYTE '外層循環(huán): %d ---> 中間層循環(huán): %d ---> 內(nèi)層循環(huán): %d? ',0dh,0ah,0
.code
? main PROC
? ? mov dword ptr ds:[x],1? ? ? ? ? ?; x = 1
??
? ? ; 外層循環(huán)
? L1: mov ecx,dword ptr ds:[x]
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; x < 5
? ? jge lop_end
? ??
? ? ; 中間循環(huán)
? ? mov dword ptr ds:[y],1? ? ? ? ? ?; y = 1
? L2: mov ecx,dword ptr ds:[y]? ? ? ? ?; ecx = y
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; y < 5
? ? jge L3? ? ? ? ? ? ? ? ? ? ? ? ? ?; 大于跳到最外層
? ? ; 內(nèi)層循環(huán)
? ? mov dword ptr ds:[z],1? ? ? ? ? ?; z = 1
? ??
? L5: mov ecx,dword ptr ds:[z]
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; z < 5
? ? jge L4? ? ? ? ? ? ? ? ? ? ? ? ? ?; 大于跳到中間層
? ??
? ? ; 三層循環(huán)框架
? ? mov eax,dword ptr ds:[x]
? ? mov ebx,dword ptr ds:[y]
? ? mov ecx,dword ptr ds:[z]
? ? invoke crt_printf,addr szFmt,eax,ebx,ecx
? ??
? ? mov ecx,dword ptr ds:[z]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ?; z = z + 1
? ? mov dword ptr ds:[z],ecx
? ??
? ? jmp L5
? ??
? L4: mov ecx,dword ptr ds:[y]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ; y = y + 1
? ? mov dword ptr ds:[y],ecx
? ? jmp L2
? L3: mov ecx,dword ptr ds:[x]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ; x = x + 1
? ? mov dword ptr ds:[x],ecx
? ? jmp L1
??
? lop_end:
? ? int 3?
? main ENDP
END main
```
最后我們用上方三層結(jié)構(gòu)作為框架使用,在其基礎(chǔ)之上增加內(nèi)部的IF判斷功能實現(xiàn),這樣一來我們的三層While嵌套循環(huán)體的仿寫就實現(xiàn)了,多說一句,在仿寫時一定要注意次序跟規(guī)律謹慎些,寫出來并不難。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? x DWORD ?
? y DWORD ?
? z DWORD ?
? szFmt BYTE '%d,%d,%d ',0dh,0ah,0
.code
? main PROC
? ? mov dword ptr ds:[x],1? ? ? ? ? ?; x = 1
??
? ? ; 外層循環(huán)
? L1: mov ecx,dword ptr ds:[x]
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; x < 5
? ? jge lop_end
? ??
? ? ; 中間循環(huán)
? ? mov dword ptr ds:[y],1? ? ? ? ? ?; y = 1
? L2: mov ecx,dword ptr ds:[y]? ? ? ? ?; ecx = y
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; y < 5
? ? jge L3? ? ? ? ? ? ? ? ? ? ? ? ? ?; 大于跳到最外層
? ? ; 內(nèi)層循環(huán)
? ? mov dword ptr ds:[z],1? ? ? ? ? ?; z = 1
? ??
? L5: mov ecx,dword ptr ds:[z]
? ? cmp ecx,5? ? ? ? ? ? ? ? ? ? ? ? ; z < 5
? ? jge L4? ? ? ? ? ? ? ? ? ? ? ? ? ?; 大于跳到中間層
? ??
? ? ; 三層循環(huán)框架
? ? ;mov eax,dword ptr ds:[x]
? ? ;mov ebx,dword ptr ds:[y]
? ? ;mov ecx,dword ptr ds:[z]
? ? ;invoke crt_printf,addr szFmt,eax,ebx,ecx
? ??
? ? ; 開始在框架中搞事情
? ? mov eax,dword ptr ds:[x]
? ? cmp eax,dword ptr ds:[z]
? ? je L6
? ? mov eax,dword ptr ds:[x]
? ? cmp eax,dword ptr ds:[y]
? ? je L6
? ? mov eax,dword ptr ds:[y]
? ? cmp eax,dword ptr ds:[z]
? ? je L6
? ??
? ? invoke crt_printf,addr szFmt,dword ptr ds:[x],dword ptr ds:[y],dword ptr ds:[z]
? ??
? L6: mov ecx,dword ptr ds:[z]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ?; z = z + 1
? ? mov dword ptr ds:[z],ecx
? ??
? ? jmp L5
? ??
? L4: mov ecx,dword ptr ds:[y]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ; y = y + 1
? ? mov dword ptr ds:[y],ecx
? ? jmp L2
? L3: mov ecx,dword ptr ds:[x]
? ? add ecx,1? ? ? ? ? ? ? ? ? ? ? ? ; x = x + 1
? ? mov dword ptr ds:[x],ecx
? ? jmp L1
??
? lop_end:
? ? int 3?
? main ENDP
END main
```
### 12.19 仿寫While實現(xiàn)二分法
該C++代碼實現(xiàn)了一個二分查找算法,用于在已排序的數(shù)組中查找指定值的位置。代碼中定義了一個BinSearch函數(shù),通過對傳入數(shù)組進行二分查找,最終返回要查找的值在數(shù)組中的索引值。main函數(shù)調(diào)用了BinSearch函數(shù),在已知數(shù)組中查找指定值并輸出其在數(shù)組中的索引。
```C
#include <windows.h>
#include <stdio.h>
int BinSearch(int value[], const int SearchVal, int Count)
{
? int first = 0;
? int last = Count - 1;
? while (first <= last)
? {
? ? int mid = (last + first) / 2;? ? ? // 取中位數(shù)
? ? if (value[mid] < SearchVal)? ? ? ? // 中位數(shù)小于searchVal
? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 說明元素在后面
? ? ? first = mid + 1;
? ? }
? ? else if (value[mid] > SearchVal)
? ? {? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? // 否則說明元素在前
? ? ? last = mid - 1;
? ? }
? ? else
? ? { // 找到后返回中位數(shù)
? ? ? return mid;
? ? }
? }
? return -1;
}
int main(int argc, char *argv[])
{
? // 二分查找法,必須針對的是有序數(shù)組
? int Array[10] = { 1,2,3,4,5,6,7,8,9,10 };
? // 查找數(shù)組Array中索引7所在的下標
? int ret = BinSearch(Array, 7, 10);
? printf("數(shù)組下標: %d \n", ret);
? system("pause");
? return 0;
}
```
接著是嘗試使用匯編實現(xiàn)這個查找邏輯,這段代碼你一定可以看懂,細心些就好,我寫的時候也思考了很長時間才寫出來的。
```ASM
? .386p
? .model flat,stdcall
? option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib
include msvcrt.inc
includelib msvcrt.lib
.data
? MyArray DWORD 1,2,3,4,5,6,7,8,9,10
??
? SearchVal DWORD 7
? Count DWORD 10
??
? first DWORD ?
? last DWORD ?
? mid DWORD ?
? szFmt BYTE '%d ',0dh,0ah,0
.code
? main PROC
? ? mov dword ptr ds:[first],0? ? ? ? ?; first = 0;
? ? mov edi,dword ptr ds:[SearchVal]? ?; 得到要查找的數(shù)
? ? lea ebx,dword ptr ds:[MyArray]? ? ?; 得到數(shù)組基地址
? ? ; int last = Count - 1;
? ? mov eax,dword ptr ds:[Count]
? ? sub eax,1
? ? mov dword ptr ds:[last],eax
? ??
? ? ; while(first <=last)
? L1: mov ecx,dword ptr ds:[first]
? ? cmp ecx,dword ptr ds:[last]
? ? jg lop_end
? ??
? ? ; int mid = (last + first) / 2;
? ? mov eax,dword ptr ds:[last]
? ? add eax,dword ptr ds:[first]
? ? shr eax,1
? ? mov dword ptr ds:[mid],eax
? ??
? ? ; edx = value[mid]
? ? mov esi,dword ptr ds:[mid]
? ? shl esi,2
? ? mov edx,[ebx + esi]
? ? ;invoke crt_printf,addr szFmt,edx
? ? ; if(edx < SearchVal(edi))
? ? cmp edx,edi
? ? jge L2
? ? ; first = mid + 1;
? ? mov eax,dword ptr ds:[mid]
? ? add eax,1
? ? mov dword ptr ds:[first],eax
? ? jmp L1
? L2:
? ? ; else if (value[mid] > searchVal)
? ? cmp edx,edi
? ? jle L3
? ? ; last = mid - 1;
? ? mov eax,dword ptr ds:[mid]
? ? sub eax,1
? ? mov dword ptr ds:[last],eax
? ? jmp L1
??
? L3: ; else
? ? mov eax,dword ptr ds:[mid]
? ? invoke crt_printf,addr szFmt,eax
? ? jmp lop_end
? ? jmp L1
? lop_end:
? ? mov eax,-1
? ? int 3
? main ENDP
END main
```
本文作者: 王瑞
本文鏈接: https://www.lyshark.com/post/910678b8.html
版權(quán)聲明: 本博客所有文章除特別聲明外,均采用 BY-NC-SA 許可協(xié)議。轉(zhuǎn)載請注明出處!