前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Win32汇编:各种语句的构造方式

Win32汇编:各种语句的构造方式

作者头像
微软技术分享
发布2022-12-28 14:59:12
8750
发布2022-12-28 14:59:12

整理复习汇编语言的知识点,以前在学习《Intel汇编语言程序设计 - 第五版》时没有很认真的整理笔记,主要因为当时是以学习理解为目的没有整理的很详细,这次是我第三次阅读此书,每一次阅读都会有新的收获,这次复习,我想把书中的重点,再一次做一个归纳与总结(注:16位汇编部分跳过),并且继续尝试写一些有趣的案例,这些案例中所涉及的指令都是逆向中的重点,一些不重要的我就直接省略了,一来提高自己,二来分享知识,转载请加出处,敲代码备注挺难受的。

这次复习的重点就是高级语言,各种语句的底层实现逻辑,我们手工的来实现一些常用的表达式,逐级递增难度,本文中所仿写的汇编流程,风格,参考自VS2013编译器的Debug实现,由于不是研究编译特性的文章,故此处不考虑编译器对代码实施的各种优化措施,只注重C语言代码的汇编化。

IF/AND/OR 语句

IF中的AND语句的构造: and语句为等式两边只要一边返回假,则整个等式就不需要继续下去了,只有等式1成立的情况下才会继续判断等式2是否成立。

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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                          ; 不大于则跳转
		
		cmp dword ptr ds:[var2],100    ; 判断是否小于100
		jg L1                          ; 不小于则跳转
		
		cmp dword ptr ds:[var3],50     ; 判断是否等于50
		jne L1                         ; 不等于则跳转

		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则跳转,不为0则继续执行
		
		xor eax,eax                    ; 此处是执行if语句内部
		xor ebx,ebx
		xor ecx,ecx
		jmp lop_end

	lop_end:
		nop                            ; 直接结束
	
		invoke ExitProcess,0
	main ENDP
END main

IF中OR语句的构造: OR语句的判断则是只要等式两边一边的结果返回为真,则整个表达式的后半部分直接跳过。

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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 则跳转
	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

IF中AND/OR混合构造:

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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

IF语句嵌套调用: 在编写这样子的嵌套语句时,应该由外到内逐层解析,这样能更容易写出优美的表达式。

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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]
		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

IF 判断平年闰年: 闰年时年份对400取余等于0的数,或者对4取余等于0并且对100取余不等于0的数.

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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                     ; 比较余数
		je L2                            ; 跳转则是平年
		
	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

IF语句三层嵌套:

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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 lop_end
		
		mov eax,dword ptr ds:[var2]
		cmp eax,dword ptr ds:[var3]      ; and var2 <= var3
		jle L1
		
		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 则跳转
		
		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

IF语句中的TEST: 这里有多种写法,第一种是比较好的写法,不需要增加太多编号,第二种是正常人的思维方式.

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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

以下是人的逻辑方式.

代码语言:javascript
复制
	.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
	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

IF-ELSEIF-ELSE: 多层循环从何治,看我的,给我写。

代码语言:javascript
复制
#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;
}

正常写法

代码语言:javascript
复制
	.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

编译器是这样干的,我把他的思路写一下。

代码语言:javascript
复制
	.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

编译器对于if-elseif-else是这样处理的.

代码语言:javascript
复制
	int var1 = 20;
	int var2 = 10;
	int var3 = 50;

	if (var1 > 20)
		printf("xor eax,eax");
	else if (var2 >= 20)
		printf("xor ebx,ebx");
	else if (var3 <= 20)
		printf("xor ecx,ecx");
	else
		printf("xor edx,edx");



	.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 ?
		jle L1                         ; 不大于则跳到L1继续判断
		xor eax,eax
		jmp lop_end                    ; 最后都要跳向结束
		
	L1:	mov eax,dword ptr ds:[var2]
		cmp eax,20                     ; var1 >= 20 ?
		jl L2                          ; 不大于则继续判断L2
		xor ebx,ebx
		jmp lop_end
		
	L2:	mov eax,dword ptr ds:[var3]
		cmp eax,20                      ; var3 <= 20 ?
		jg L3                           ; 大于则跳到L3
		xor ecx,ecx
		jmp lop_end

	L3:	xor edx,edx
		jmp lop_end
		
	lop_end:
		xor esi,esi
		
		invoke ExitProcess,0
	main ENDP
END main

IF的前期脑残写法: 写的烂,没编译器生成的代码有趣,垃圾保存。 脑残1

代码语言:javascript
复制
if(var1 > var2) and (var2 < var3)
{
	xor eax,eax
}else if(var1 > var3)
{
	xor ebx,ebx
}

	.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,dword ptr ds:[var2]      ; if(var1 > var2)
		jg L1
		
		mov eax,dword ptr ds:[var1]
		cmp eax,dword ptr ds:[var3]      ; else if(var1 > var3)
		jg L3
	L1:
		mov eax,dword ptr ds:[var2]      ; if(var2 < var3)
		cmp eax,dword ptr ds:[var3]
		jl L2
	L2:
		xor eax,eax
		jmp lop
	L3:
		xor ebx,ebx
		jmp lop
	lop:
		nop
	
		invoke ExitProcess,0
	main ENDP
END main

脑残2

代码语言:javascript
复制
if var1 == var2
{
	if x > y
	{
		xchg x,y
	}
	else
	{
		x=10
		y=20
	}
}else
{
	var1 = 0
	var2 = 0
}

	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

.data
	x BYTE 6
	y BYTE 5
	var1 DWORD 10
	var2 DWORD 10

.code
	main PROC
		mov eax,dword ptr ds:[var1]
		cmp eax,dword ptr ds:[var2]     ; var1 == var2 ?
		jne L1                          ; 不等于跳转到L1
		
		mov al,byte ptr ds:[x]
		cmp al,byte ptr ds:[y]          ; x > y ?
		jg L2                           ; 大于跳到L2
		
		mov byte ptr ds:[x],0           ; 不大于则执行x=10 y=20
		mov byte ptr ds:[y],0
		jmp lop
	L1:
		mov dword ptr ds:[var1],0       ; var1 != var2 则执行
		mov dword ptr ds:[var2],0
	L2:
		mov al,byte ptr ds:[x]
		mov bl,byte ptr ds:[y]
		xchg al,bl                      ; x y 数值交换
		mov byte ptr ds:[x],al
		mov byte ptr ds:[y],bl
		jmp lop
	lop:
		nop
		invoke ExitProcess,0
	main ENDP
END main

if 双层嵌套结构: 包含有and,or运算符的连用处理.

代码语言:javascript
复制
	int var1 = 20;
	int var2 = 10;
	int var3 = 50;

	if (var1++ > 5 && var2++ >= 10)
	{
		var3 = var3 + 10;
		var3 << 2;
		if (var3 <= 100 or var3 <= 1000)
			xor eax,eax
		else
			xor ebx,ebx
	}

	.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
		inc dword ptr ds:[var1]           ; var1++
		mov eax,dword ptr ds:[var1]
		cmp eax,5                         ; var1 > 5 ?
		jg L1
		jmp lop_end
	L1:
		inc dword ptr ds:[var2]           ; var2++
		mov eax,dword ptr ds:[var2]       ; var2 >=10 ?
		cmp eax,10
		jge L2
		jmp lop_end
	L2:
		mov eax,dword ptr ds:[var3]       ; 获取 var3
		add eax,10                        ; var3 = var3 + 10
		shl eax,2                         ; var3 << 2
		
		cmp eax,100
		jle L3                            ; var3 <= 100 ?
		cmp eax,1000                      ; eax or
		jle L3                            ; var3 <= 1000 ?
		jmp L4                            ; else
	L3:
		xor eax,eax
		jmp lop_end
	L4:
		xor ebx,ebx
		jmp lop_end
		
	lop_end:
		nop
		invoke ExitProcess,0
	main ENDP
END main

编译器对于此类嵌套出处理结果是这样的,由于and指令左面如果成立则继续执行右面的判断,如果不成立右面的直接掠过,这样的话就比较有趣了,如下是我根据汇编代码推测的一段片段,。

代码语言:javascript
复制
	.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
	tmp DWORD ?
	flag DWORD ?

.code
	main PROC
		mov eax,dword ptr ds:[var1]
		mov dword ptr ds:[tmp],eax       ; 将var1原值备份到tmp
		
		mov ecx,dword ptr ds:[var1]
		add ecx,1                        ; 递增var1并会写到变量中
		mov dword ptr ds:[var1],ecx
		
		cmp dword ptr ds:[tmp],5         ; 用原值与5做比较
		jle L1                           ; 如果 var1 < var2
		
		mov dword ptr ds:[flag],1
		jmp L2
		
	L1:	mov dword ptr ds:[flag],0         ; 判断的是and的第一个等式
	L2:	cmp dword ptr ds:[flag],0
		je lop_end
		
		mov eax,dword ptr ds:[var2]
		mov dword ptr ds:[tmp],eax        ; 备份var2
		
		mov ecx,dword ptr ds:[var2]
		add ecx,1                         ; 递增运算++
		mov dword ptr ds:[var2],ecx
		
		cmp dword ptr ds:[tmp],10         ; 判断 var2>=10 ?
		jl L3                             ; 不大于则跳到L3
		mov dword dword ptr ds:[flag],1   ; 大于则标志flag=1
		jmp L4

	L3:	mov dword ptr ds:[flag],0
	L4:	cmp dword ptr ds:[flag],0
		je lop_end                         ; 不跳转则执行内部if
		
		mov eax,dword ptr ds:[var3]
		add eax,10
		mov dword ptr ds:[var3],eax         ; 递增var3
		
		mov eax,dword ptr ds:[var3]
		shl eax,2
		mov dword ptr ds:[var3],eax         ; var3 = var3 << 2
		
		cmp dword ptr ds:[var3],100         ; var3 <= 100
		jle L5
		cmp dword ptr ds:[var3],1000        ; var3<=1000
		jg L6                               ; 跳转到内层else
	L5:
		xor eax,eax
		nop
		jmp lop_end
	L6:
		xor ebx,ebx
		nop
		jmp lop_end
		
	lop_end:
		xor eax,eax
		invoke ExitProcess,0
	main ENDP
END main

IF中的自增自减处理: 执行自增自减运算需要找一个临时区域来存放自增后的数据,所以首先要开辟局部空间,多数情况下开辟空间可在栈上,例如使用sub esp,12来分配栈空间,并初始化后即可使用,最后需要将该空间恢复.

代码语言:javascript
复制
	.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                     ; 填充次数 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] ; 取第一个数据1
		mov ebx,dword ptr ss:[ebp-4]  ; 取第二个数据3
		add eax,ebx                   ; 执行递增
		mov dword ptr ss:[ebp-8],eax  ; 写回栈
		
		add esp,12                     ; 平栈
		mov esp,ebp
		pop ebp
	
		invoke ExitProcess,0
	main ENDP
END main
代码语言:javascript
复制
#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++时程序是将++后的结果赋值到了栈中存放,并让var1变量递增,而判断则使用的是栈中的原值,相反++var1则是在原值上直接进行操作,将操作结果赋值给原值后在进行判断.

代码语言:javascript
复制
	.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                     ; 填充次数 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    ; 将相加后的结果写回到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]    ; 继续执行 ++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

IF嵌套中的移位1:

代码语言:javascript
复制
#include <stdio.h>
#include <windows.h>

int main(int argc,char * argv[])
{
	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;
}
代码语言:javascript
复制
	.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

第二种如果判断

代码语言:javascript
复制
#include <stdio.h>
#include <windows.h>

int main(int argc,char * argv[])
{
	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;
}
代码语言:javascript
复制
	.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                      ; 非负数则跳转
	
		; (var3 >> 1) % 3           ; 为负数执行第二个表达式
	L1:	mov eax,dword ptr ds:[var3]
		sar eax,1                   ; var3 >> 1
		cdq                         ; 扩展为8字节
		mov ecx,3                   ; 除以3
		idiv ecx
		test edx,edx                ; 比较余数是否为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

IF中的三目运算符:

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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

While /For 语句构建

While/FOr 循环框架: while循环,for循环的简单框架,后期会逐步提高难度,最终实现一个循环链表结构。

代码语言:javascript
复制
	.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            ; 设置while初始化
	S1:	cmp dword ptr ds:[count],10           ; 设置最大循环数
		jge loop_end                          ; 判断是否循环结束
		
		xor eax,eax                           ; 执行循环体
		
		mov eax,dword ptr ds:[count]           ; 取出循环条件
		add eax,1                              ; 递增
		mov dword ptr ds:[count],eax           ; 写回
		jmp S1
	loop_end:
		int 3

		invoke ExitProcess,0
	main ENDP
END main

再看一下他的好基友,do-while是如何构造的,相比于while,该语句是先执行在判断,从效率上来说这个效率要高于while.

代码语言:javascript
复制
	.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     ; 初始化循环次数
	S1:	xor eax,eax                    ; 执行循环体
		
		mov eax,dword ptr ds:[count]   ; 取出计数器
		add eax,1                      ; 递增
		mov dword ptr ds:[count],eax   ; 回写
		
		cmp dword ptr ds:[count],10    ; 与10做对比
		jl S1                          ; 小于则继续循环

		int 3

		invoke ExitProcess,0
	main ENDP
END main

最后看一个for语句的实现流程,该语句的构建方式相对于While来说略显复杂些,效率远不及While,反汇编后发现,编译器是这样构建的.

代码语言:javascript
复制
	.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          ; 设置 int x = 0;
		jmp L2

	L1:	mov eax,dword ptr ds:[count]        ; x = x++
		add eax,1
		mov dword ptr ds:[count],eax

	L2:	cmp dword ptr ds:[count],10         ; 比较 x < 10
		jge lop_end
		
		xor eax,eax                         ; 执行循环体
		jmp L1
		
	lop_end:
		int 3
		invoke ExitProcess,0
	main ENDP
END main

在Python中for循环是for x in range(2,10)可以指定一个范围,我们接着尝试构建一下.

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

.data
	start_count DWORD ?
	end_count DWORD ?
.code
	main PROC
		mov dword ptr ds:[start_count],2     ; 指定开始循环编号
		mov dword ptr ds:[end_count],5       ; 指定结束循环编号
		
		mov ecx,dword ptr ds:[start_count]
	L1:	cmp dword ptr ds:[end_count],ecx
		jle lop_end
		
		xor eax,eax                          ; 循环体内部
		
		add ecx,1                            ; 每次递增
		mov dword ptr ds:[start_count],ecx
		jmp L1
		
	lop_end:
		int 3
		invoke ExitProcess,0
	main ENDP
END main

While遍历数组: 以下案例主要通过仿写While循环结构并通过比例因子寻址,实现对一个DWORD数组的遍历.

代码语言:javascript
复制
#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;
}
代码语言:javascript
复制
	.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        ; 初始化循环
		mov ecx,0                         ; 设置循环计数(比例因子)

	S1:	cmp dword ptr ds:[count],lengthof MyArray  ; 与数组总长度对比
		jge lop_end                                ; 是否结束
		
		lea esi,dword ptr ds:[MyArray]             ; 获取数组基地址
		mov ebx,dword ptr ds:[esi + ecx * 4]       ; 比例因子寻址
		invoke crt_printf,addr szFmt,ebx           ; 调用系统crt
		
		mov ecx,dword ptr ds:[count]
		add ecx,1                                   ; 计次循环递增
		mov dword ptr ds:[count],ecx
		jmp S1
	lop_end:
		int 3
	
		invoke ExitProcess,0
	main ENDP
END main

For循环尝试判断: 这次使用For循环,首先仿写For循环语句,然后在内部判断指定数值是否合格,合格输出.

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>

int main(int argc,char *argv[])
{
	int Array[10] = { 56,78,33,45,78,90,32,44,56,67 };

	for (int x = 0; x < 10; x++)
	{
		if (Array[x] >= 50)
		{
			printf("out -> %d \n", Array[x]);
		}
	}
	return 0;
}
代码语言:javascript
复制
	.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,44,56,67
	count DWORD ?
	szFmt BYTE 'out -> %d ',0dh,0ah,0
.code
	main PROC
		
		mov dword ptr ds:[count],0      ; int x = 0
		jmp L1
	L2:	mov eax,dword ptr ds:[count]
		add eax,1                       ; x ++
		mov dword ptr ds:[count],eax
	L1:
		cmp dword ptr ds:[count],10     ; x < 10
		jge lop_end
		
		mov eax,dword ptr ds:[count]          ; 获取循环次数,当作因子
		lea esi,dword ptr ds:[MyArray]        ; 取数组基地址
		mov ebx,dword ptr ds:[esi + eax * 4]  ; 因子寻址
		cmp ebx,50
		jl L2                                 ; 如果小于50则跳转到下一次循环
		
		invoke crt_printf,addr szFmt,ebx      ; 调用系统crt
		jmp L2

	lop_end:
		int 3
	
		invoke ExitProcess,0
	main ENDP
END main

继续增加难度,求最大最小平均值的代码,尝试用汇编实现.

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
	int Array[10] = { 56,78,33,45,78,90,32,44,56,67 };
	int max_result = 0,min_result = 100,sum_result = 0,avg_result = 0;

	for (int x = 0; x < 10; x++)
	{
		if (Array[x] >= max_result)
		{
			max_result = Array[x];
		}
		if (Array[x] <= min_result)
		{
			min_result = Array[x];
		}
		sum_result = sum_result + Array[x];
		avg_result = sum_result / 10;
	}
	printf("max = %d min = %d sum = %d avg = %d \n", max_result,min_result,sum_result,avg_result);
	system("pause");
	return 0;
}

以下这段代码,写的有点小问题,但大体完善,先思考一下哪里的问题,后期我在发答案!

代码语言:javascript
复制
	.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,44,56,67
	count DWORD ?
	max_result DWORD 0
	min_result DWORD 100
	sum_result DWORD 0
	avg_result DWORD 0
	
	szFmt BYTE 'max = %d min = %d sum = %d avg = %d ',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[count],0      ; int x = 0
		jmp L1
	L2:	mov eax,dword ptr ds:[count]
		add eax,1                       ; x ++
		mov dword ptr ds:[count],eax
	L1:
		cmp dword ptr ds:[count],10     ; x < 10
		jge lop_end

		mov eax,dword ptr ds:[count]
		lea esi,dword ptr ds:[MyArray]
		
		mov ebx,dword ptr ds:[esi + eax * 4]
		cmp ebx,dword ptr ds:[max_result]      ; Array[x] >= max_result
		jl L3
		mov dword ptr ds:[max_result],ebx      ; max_result = Array[x];
	L3:
		mov ebx,dword ptr ds:[esi + eax * 4]
		cmp ebx,dword ptr ds:[min_result]      ; Array[x] <= min_result
		jg L4
	L4:
		mov ebx,dword ptr ds:[esi + eax * 4]
		mov edx,dword ptr ds:[sum_result]      ; sum_result + Array[x];
		add ebx,edx
		mov dword ptr ds:[sum_result],ebx      ; sum_result
		
		mov eax,dword ptr ds:[sum_result]
		cdq
		mov ecx,10
		idiv ecx                               ; sum_result / 10;
		mov dword ptr ds:[sum_result],eax      ; avg_result

		jmp L2
		
	lop_end:
		mov eax,dword ptr ds:[max_result]
		mov ebx,dword ptr ds:[min_result]
		mov ecx,dword ptr ds:[sum_result]
		mov edx,dword ptr ds:[avg_result]
		invoke crt_printf,addr szFmt,eax,ebx,ecx,edx
		int 3
		invoke ExitProcess,0
	main ENDP
END main

问题显而易见,相信大家都看出来了,我就直接公布正确代码了

代码语言:javascript
复制
	.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,44,56,67
	count DWORD ?
	max_result DWORD 0
	min_result DWORD 100
	sum_result DWORD 0
	avg_result DWORD 0
	
	szFmt BYTE 'max = %d min= %d sum= %d avg = %d ',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[count],0      ; int x = 0
		jmp L1
	L2:	mov eax,dword ptr ds:[count]
		add eax,1                       ; x ++
		mov dword ptr ds:[count],eax
	L1:
		cmp dword ptr ds:[count],10     ; x < 10
		jge lop_end

		mov eax,dword ptr ds:[count]
		lea esi,dword ptr ds:[MyArray]
		
		mov ebx,dword ptr ds:[esi + eax * 4]
		cmp ebx,dword ptr ds:[max_result]      ; Array[x] >= max_result
		jl L3
		mov dword ptr ds:[max_result],ebx      ; max_result = Array[x];
	L3:
		mov ebx,dword ptr ds:[esi + eax * 4]
		cmp ebx,dword ptr ds:[min_result]      ; Array[x] <= min_result
		jg L4
		mov dword ptr ds:[min_result],ebx
	L4:
	
		mov ebx,dword ptr ds:[esi + eax * 4]   ; Array[x]
		add dword ptr ds:[sum_result],ebx      ; sum_result = sum_result + Array[x];
		
		mov eax,dword ptr ds:[sum_result]
		cdq                                    ; 符号扩展
		mov ecx,10                             ; / 10
		idiv ecx                               ; sum_result / 10;
		mov dword ptr ds:[avg_result],eax      ; avg_result
		jmp L2
		
	lop_end:
		mov eax,dword ptr ds:[max_result]
		mov ebx,dword ptr ds:[min_result]
		mov ecx,dword ptr ds:[sum_result]
		mov edx,dword ptr ds:[avg_result]
		invoke crt_printf,addr szFmt,eax,ebx,ecx,edx
		int 3
	main ENDP
END main

Do-While 与跳出循环: 要说continue与break语句的唯一区别,就在于一个是跳转到了本次循环的结束位置,另一个则是条向了总循环结束位置.

代码语言:javascript
复制
#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);

	return 0;
}
代码语言:javascript
复制
	.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

For循环多重IF判断: 在循环中我们首先判断两个数组中元素是否大于0,大于则执行加法运算,然后输出基数或偶数.

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
	int SrcArray[10] = { 56,78,33,45,78,90,32,15,56,67 };
	int DstArray[10] = { 59,77,89,23,11,45,67,88,93,27 };
	int index = 0;

	for (index = 0; index < 10; index++)
	{
		if (SrcArray[index] != 0 && DstArray[index] != 0)
		{
			int sum = SrcArray[index] + DstArray[index];
			if (sum % 2 == 0)
				printf("偶数: %d \n", sum);
			else
				printf("基数: %d \n", sum);
		}
	}
	system("pause");
	return 0;
}

思考了一会,花费了一些时间,但还是使用汇编完成了.

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	SrcArray DWORD 56,78,33,45,78,90,32,15,56,67
	DstArray DWORD 59,77,89,23,11,45,67,88,93,27
	index DWORD 0
	sum DWORD 0
	
	szFmt1 BYTE '基数: %d ',0dh,0ah,0
	szFmt2 BYTE '偶数: %d ',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[index],0        ; index = 0
		
		jmp L1
	L2:	mov eax,dword ptr ds:[index]
		add eax,1                         ; index++
		mov dword ptr ds:[index],eax
	L1:
		cmp dword ptr ds:[index],10       ; index < 10
		jge lop_end
		
		mov eax,dword ptr ds:[index];
		cmp dword ptr ds:[SrcArray + eax * 4],0
		je L2                                     ; SrcArray[index] != 0
		
		mov eax,dword ptr ds:[index]
		cmp dword ptr ds:[DstArray + eax * 4],0   ; DstArray[index] != 0
		je L2
		
		; ------------------------------------------
		; 另类加法,通过一个SrcArray定位DstArray完成加法
		
		mov eax,dword ptr ds:[index]                 ; 获取因子
		lea esi,dword ptr ds:[SrcArray]              ; 取数组首地址
		
		mov ebx,dword ptr ds:[esi + eax * 4]         ; 获取 SrcArray[index]
		mov ecx,dword ptr ds:[esi + eax * 4 + 40]    ; 获取 DstArray[index]
		add ebx,ecx                                  ; SrcArray[index] + DstArray[index]
		mov dword ptr ds:[sum],ebx                   ; sum = SrcArray[index] + DstArray[index]
		
		mov eax,dword ptr ds:[sum]
		and eax,080000001h                           ; sum % 2 == 0
		test eax,eax
		jne L3
		
		invoke crt_printf,addr szFmt2,dword ptr ds:[sum]  ; 偶数输出
		jmp L2
	L3:
		invoke crt_printf,addr szFmt1,dword ptr ds:[sum]  ; 基数输出
		jmp L2
	lop_end:
		int 3

	main ENDP
END main

For语句嵌套(乘法口诀表): 首先我们来接触一下For循环的嵌套实现方法,以打印99表为例,尝试使用汇编实现.

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
	for (int x = 1; x < 10; x++)
	{
		for (int y = 1; y <= x; y++)
		{
			int result = x*y;
			printf("%d*%d=%-3d", y, x, result);
		}
		printf("\n");
	}
	system("pause");
	return 0;
}

执行双层循环需要嵌套For语句,先来写一个简单的双层For循环的汇编版.

代码语言:javascript
复制
	.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 '内层循环: %d 外层循环: %d ',0dh,0ah,0
	szPr  BYTE '----->',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[x],1        ; int x = 1
		jmp L1
	L2:	mov eax,dword ptr ds:[x]
		add eax,1                     ; x++
		mov dword ptr ds:[x],eax
	L1:	
		cmp dword ptr ds:[x],10       ; x < 10
		jge lop_end

		mov dword ptr ds:[y],1        ; y = 1
		jmp L3
	L5:	mov eax,dword ptr ds:[y]
		add eax,1                     ; y++
		mov dword ptr ds:[y],eax
	L3:
		mov eax,dword ptr ds:[y]
		cmp eax,dword ptr ds:[x]      ; y <= x
		jg L4
		
		; 执行的是循环体内部
		mov eax,dword ptr ds:[x]
		mov ebx,dword ptr ds:[y]
		invoke crt_printf,addr szFmt,eax,ebx
		
		jmp L5
	L4:
		; 执行外层循环
		invoke crt_printf,addr szPr

		jmp L2
	lop_end:
		int 3

	main ENDP
END main

最终实现只是相应的做一个替换即可.

代码语言:javascript
复制
	.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 '%d * %d = %d ',0
	szPr  BYTE ' ',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[x],1        ; int x = 1
		jmp L1
	L2:	mov eax,dword ptr ds:[x]
		add eax,1                     ; x++
		mov dword ptr ds:[x],eax
	L1:	
		cmp dword ptr ds:[x],10       ; x < 10
		jge lop_end

		mov dword ptr ds:[y],1        ; y = 1
		jmp L3
	L5:	mov eax,dword ptr ds:[y]
		add eax,1                     ; y++
		mov dword ptr ds:[y],eax
	L3:
		mov eax,dword ptr ds:[y]
		cmp eax,dword ptr ds:[x]      ; y <= x
		jg L4
		
		; 执行的是循环体内部
		mov eax,dword ptr ds:[x]
		imul eax,dword ptr ds:[y]
		invoke crt_printf,addr szFmt,dword ptr ds:[y],dword ptr ds:[x],eax
		
		jmp L5
	L4:
		; 执行外层循环
		invoke crt_printf,addr szPr

		jmp L2
	lop_end:
		int 3

	main ENDP
END main

For简单循环(水仙花数): 所谓水仙花数是指一个三位数,其各位数字立方和等于该数本身.

例如: 153是一个水仙花数,因为153=1的三次方+5的三次方+3的三次方. 分析: 利用for循环控制100-999个数,每个数分解出个位,十位,百位.

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
	int x, y, z, n;
	for (n = 100; n < 1000; n++)
	{
		x = n / 100;
		y = n / 10 % 10;
		z = n % 10;
		if (x * 100 + y * 10 + z == x*x*x + y*y*y + z*z*z)
		{
			printf("水仙花: %-5d \n", n);
		}
	}

	system("pause");
	return 0;
}

尝试使用汇编实现计算逻辑.

代码语言:javascript
复制
	.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 ?
	n DWORD ?
	szFmt BYTE '水仙花: %-5d ',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[n],100     ; n = 100
		jmp L1
	L2:	mov eax,dword ptr ds:[n]
		add eax,1                    ; n++
		mov dword ptr ds:[n],eax
	L1:	mov eax,dword ptr ds:[n]
		cmp eax,1000                 ; n < 1000
		jge lop_end
		
		mov eax,dword ptr ds:[n]
		cdq
		mov ecx,100                  ; x = n / 100;
		idiv ecx
		mov dword ptr ds:[x],eax
		
		mov eax,dword ptr ds:[n]
		cdq
		mov ecx,10
		idiv ecx                     ; y = n / 10;
		cdq
		mov ecx,10
		idiv ecx                     ; y = y % 10;
		mov dword ptr ds:[y],edx
		
		mov eax,dword ptr ds:[n]
		cdq
		mov ecx,10
		idiv ecx                     ; z = n % 10;
		mov dword ptr ds:[z],edx
		
		; 开始执行if()比较语句
		imul eax,dword ptr ds:[x],100  ; x * 100
		imul ecx,dword ptr ds:[y],10   ; y * 10
		add eax,dword ptr ds:[z]       ; + z
		add ecx,eax
		
		mov edx,dword ptr ds:[x]
		imul edx,dword ptr ds:[x]      ; x*x*x
		imul edx,dword ptr ds:[x]
		
		mov eax,dword ptr ds:[y]
		imul eax,dword ptr ds:[y]      ; y*y*y
		imul eax,dword ptr ds:[y]
		add edx,eax
		
		mov eax,dword ptr ds:[z]
		imul eax,dword ptr ds:[z]      ; z*z*z
		imul eax,dword ptr ds:[z]
		add edx,eax
		
		cmp ecx,edx   ; (x * 100 + y * 10 + z) == (x*x*x + y*y*y + z*z*z)
		jne L2
		
		mov eax,dword ptr ds:[n]
		invoke crt_printf,addr szFmt,eax
		jmp L2
		
	lop_end:
		int 3	

	main ENDP
END main

For语句嵌套(冒泡排序): 冒泡排序实现思路从后向前,大的数下沉小的数上移,C代码如下,尝试使用汇编实现.

代码语言:javascript
复制
#include <stdio.h>
#include <Windows.h>

int main(int argc, char *argv[])
{
	int Array[10] = { 34,78,65,77,89,43,23,55,67,8 };
	int x, y, temporary, ArraySize=10;

	for (x = 0; x < ArraySize - 1; x++)
	{
		for (y = ArraySize - 1; y > x; y--)
		{
			if (Array[y - 1] > Array[y])
			{
				temporary = Array[y - 1];
				Array[y - 1] = Array[y];
				Array[y] = temporary;
			}
		}
	}

	for (int x = 0; x < 10; x++)
	{
		printf("%d \n", Array[x]);
	
	system("pause");
	return 0;
}

未完待续

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	Array DWORD 34,78,65,77,89,43,23,55,67,8
	x DWORD ?
	y DWORD ?
	Temporary DWORD ?
	ArraySize DWORD ?
.code
	main PROC
		
		mov dword ptr ds:[x],0            ; x=0
		mov dword ptr ds:[ArraySize],10   ; ArraySize=10
		
		jmp L1
	L2:	mov eax,dword ptr ds:[x]
		add eax,1                          ; x++
		mov dword ptr ds:[x],eax
		
	L1:	mov eax,dword ptr ds:[ArraySize]
		sub eax,1                          ; x < ArraySize - 1
		cmp dword ptr ds:[x],eax
		jge lop_end
		
		; 内层循环体内容
	L4:	mov eax,dword ptr ds:[ArraySize]
		sub eax,1                          ; y = ArraySize - 1
		mov dword ptr ds:[y],eax
		jmp L3
		
		mov eax,dword ptr ds:[y]
		sub eax,1                          ; y--
		mov dword ptr ds:[y],eax
	L3:
		mov eax,dword ptr ds:[y]
		cmp eax,dword ptr ds:[x]            ; y > x
		jle L2
		

		mov ecx,dword ptr ds:[y]
		mov eax,dword ptr ds:[Array + ecx * 4]  ; y
		sub ecx,1
		mov ebx,dword ptr ds:[Array + ecx * 4]  ; x
		
		xchg eax,ebx
		
		mov dword ptr ds:[Array + ecx * 4],eax
		add ecx,1
		mov dword ptr ds:[Array + ecx * 4],ebx


		jmp L4
		jmp L2
	lop_end:
		int 3

	main ENDP
END main
代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	Array DWORD 34,78,65,77,89,43,23,55,67,8
	x DWORD ?
	y DWORD ?
	Temporary DWORD ?
	ArraySize DWORD ?
	szFmt BYTE '%d --> %d ',0dh,0ah,0
.code
	main PROC
		; 初始化的部分
		mov dword ptr ds:[x],0            ; x=0
		mov dword ptr ds:[ArraySize],10   ; ArraySize=10
		
		; 外层循环体
		jmp L1
	L2:	mov eax,dword ptr ds:[x]
		add eax,1                          ; x++
		mov dword ptr ds:[x],eax
		
	L1:	mov eax,dword ptr ds:[ArraySize]
		sub eax,1                          ; ArraySize - 1
		cmp dword ptr ds:[x],eax           ; x < ArraySize
		jge lop_end
		
		; 内层循环体内容
		mov eax,dword ptr ds:[ArraySize]
		sub eax,1
		mov dword ptr ds:[y],eax
		
		jmp L3
	L4:	mov eax,dword ptr ds:[y]
		sub eax,1                           ; y--
		mov dword ptr ds:[y],eax
	
	L3:	mov eax,dword ptr ds:[y]
		cmp eax,dword ptr ds:[x]
		jle L2
		
		mov esi,dword ptr ds:[y]

		mov ebx,dword ptr ds:[Array + esi * 4]         ; Array[y]
		mov edx,dword ptr ds:[Array + esi * 4 - 4]     ; Array[y - 1]
		cmp edx,ebx
		jle L4
		
		mov dword ptr ds:[Array + esi * 4],edx
		mov dword ptr ds:[Array + esi * 4 - 4],ebx
	
		; invoke crt_printf,addr szFmt,ebx,edx
		
		jmp L4
		jmp L2

	lop_end:
		int 3
	main ENDP
END main

排序完成

完整代码已经写出来了,如下所示.

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	Array DWORD 34,78,65,77,89,43,23,55,67,8
	x DWORD ?
	y DWORD ?
	Temporary DWORD ?
	ArraySize DWORD ?
	szFmt BYTE '%d --> %d ',0dh,0ah,0
.code
	main PROC
		; 初始化的部分
		mov dword ptr ds:[x],0            ; x=0
		mov dword ptr ds:[ArraySize],10   ; ArraySize=10
		
		; 外层循环体
		jmp L1
	L2:	mov eax,dword ptr ds:[x]
		add eax,1                          ; x++
		mov dword ptr ds:[x],eax
		
	L1:	mov eax,dword ptr ds:[ArraySize]
		sub eax,1                          ; ArraySize - 1
		cmp dword ptr ds:[x],eax           ; x < ArraySize
		jge lop_end
		
		; 内层循环体内容
		mov eax,dword ptr ds:[ArraySize]
		sub eax,1
		mov dword ptr ds:[y],eax
		
		jmp L3
	L4:	mov eax,dword ptr ds:[y]
		sub eax,1                           ; y--
		mov dword ptr ds:[y],eax
	
	L3:	mov eax,dword ptr ds:[y]
		cmp eax,dword ptr ds:[x]            ; Array[y - 1] > Array[y]
		jle L2
		
		mov esi,dword ptr ds:[y]

		mov ebx,dword ptr ds:[Array + esi * 4]         ; Array[y]
		mov edx,dword ptr ds:[Array + esi * 4 - 4]     ; Array[y - 1]
		cmp edx,ebx
		jle L4
		
		mov dword ptr ds:[Array + esi * 4],edx         ; Array[y] = Array[y - 1]
		mov dword ptr ds:[Array + esi * 4 - 4],ebx     ; Array[y - 1] = Array[y]
		; invoke crt_printf,addr szFmt,ebx,edx
		
		jmp L4
		jmp L2

	lop_end:
		nop

		; 执行打印函数
		mov dword ptr ds:[Temporary],0

		jmp L5
	L7:	mov eax,dword ptr ds:[Temporary]
		add eax,1
		mov dword ptr ds:[Temporary],eax
	L5:
		mov eax,dword ptr ds:[Temporary]
		cmp eax,10
		jge L6
		
		lea esi,dword ptr ds:[Array]                ; 取数组基地址
		mov esi,dword ptr ds:[Array + eax * 4]      ; 比例因子寻址
		invoke crt_printf,addr szFmt,esi,esi
		jmp L7
	L6:
		int 3

	main ENDP
END main

先看排序部分

接着是输出部分

While 三层嵌套: 在写三层嵌套时,你需要注意了,在内层循环时需要清空变量,不然会导致循环一次整个程序结束掉了,就像下面的这种写法,乍一看没啥问题,可是一旦运行就会发现,程序每次都只运行外层一次循环就意外终止了,经过反汇编调试发现,是粗心导致没有让内层循环及时的置空。

代码语言:javascript
复制
#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)
			{
				z = z + 1;
			}
			y = y + 1;
		}
		x = x + 1;
	}
	return 0;
}

来一个案例看看,使用三层嵌套完成案例,有1,2,3,4个数字,能组成多少个互补相同且不重复的三位数,尝试使用汇编实现以下这个逻辑。

代码语言:javascript
复制
#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;
}

首先我们先来构建一个双层循环,然后再构建三层的.

代码语言:javascript
复制
	.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 '外层循环: %d ---> 内层循环:%d ',0dh,0ah,0
.code
	main PROC
		mov dword ptr ds:[x],1           ; x = 1
	
		; 外层循环
	L1:	mov ecx,dword ptr ds:[x]
		cmp ecx,5                        ; x < 5
		jge lop_end
		
		; 内层循环
		mov dword ptr ds:[y],1           ; y = 1
	L2:	mov ecx,dword ptr ds:[y]         ; ecx = y
		cmp ecx,5                        ; y < 5
		jge L3
		
		; 循环过程执行
		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

接着是构建一个三层循环体,三层循环体就像汉堡一样,前面初始化部分时面包,中间时肉,后面也是面包,放在一起,很有食欲。

代码语言:javascript
复制
	.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
	
		; 外层循环
	L1:	mov ecx,dword ptr ds:[x]
		cmp ecx,5                        ; x < 5
		jge lop_end
		
		; 中间循环
		mov dword ptr ds:[y],1           ; y = 1
	L2:	mov ecx,dword ptr ds:[y]         ; ecx = y
		cmp ecx,5                        ; y < 5
		jge L3                           ; 大于跳到最外层

		; 内层循环
		mov dword ptr ds:[z],1           ; z = 1
		
	L5:	mov ecx,dword ptr ds:[z]
		cmp ecx,5                        ; z < 5
		jge L4                           ; 大于跳到中间层
		
		; 三层循环框架
		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

中间的IF语句,就是汉堡包的佐料部分,肉质丝滑,入口即化,实在是美妙至极,如下时肉质部分。

代码语言:javascript
复制
	.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
	
		; 外层循环
	L1:	mov ecx,dword ptr ds:[x]
		cmp ecx,5                        ; x < 5
		jge lop_end
		
		; 中间循环
		mov dword ptr ds:[y],1           ; y = 1
	L2:	mov ecx,dword ptr ds:[y]         ; ecx = y
		cmp ecx,5                        ; y < 5
		jge L3                           ; 大于跳到最外层

		; 内层循环
		mov dword ptr ds:[z],1           ; z = 1
		
	L5:	mov ecx,dword ptr ds:[z]
		cmp ecx,5                        ; z < 5
		jge L4                           ; 大于跳到中间层
		
		; 三层循环框架
		;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

Switch与循环: Switch语句与IF语句类似,不同之处就在于Switch是将跳转地址保存在数组中,需要时去数组中通过比例因子寻找到指定的内存然后,使用一条Jmp指令跳转过去,实在美妙!

先给大家看一下,我是怎吗保存这些地址的吧,汇编代码如下所示,直接取出标号,放入数组中,也可以使用堆栈存储,随意。

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none
include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	MemArray DWORD ?

	szFmt BYTE '%d,%d,%d ',0dh,0ah,0
.code
	main PROC
	mov dword ptr ds:[MemArray],offset lop_end  
	mov dword ptr ds:[MemArray+4],offset L2
	
	lop_end:
		int 3	
	L2:
		xor eax,eax
		xor ebx,ebx
	main ENDP
END main

尝试构建Switch语句。

代码语言:javascript
复制
#include <windows.h>
#include <stdio.h>

int main(int argc, char * argv[])
{
	int x = 0;
	while (x < 6)
	{
		switch (x)
		{
		case 0:
			printf("1"); break;
		case 1:
			printf("2"); break;
		case 2:
			printf("3"); break;
		case 3:
			printf("4"); break;
		case 4:
			printf("5"); break;
		default:
			printf("0"); break;
		}
		x = x + 1;
	}
	return 0;
}

理解了Switch的查表法,然后再配合汇编中的语法规范就可以巧妙地构造出Switch结构.

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	MemArray DWORD 0,0,0,0,0,0,0,0,0,0
	Count DWORD ?
	szFmt BYTE '%d ',0dh,0ah,0
.code
	main PROC
		
		; 将指定标号的地址取出,并复制到数组
		mov dword ptr ds:[MemArray],offset S0
		mov dword ptr ds:[MemArray + 4],offset S1
		mov dword ptr ds:[MemArray + 8],offset S2
		mov dword ptr ds:[MemArray + 12],offset S3
		mov dword ptr ds:[MemArray + 16],offset S4
		mov dword ptr ds:[MemArray + 20],offset S_END
	
		mov dword ptr ds:[Count],0
		
	L1:	mov ecx,dword ptr ds:[Count]
		cmp ecx,6
		jg lop_end
		
		; 通过循环次数寻找指令地址并跳转
		mov ecx,dword ptr ds:[Count]
		cmp ecx,6
		jg S_END
		jmp dword ptr ds:[MemArray + ecx * 4]
		
	S0:	mov eax,1
		invoke crt_printf,addr szFmt,eax
		jmp L2

	S1:	mov eax,2
		invoke crt_printf,addr szFmt,eax
		jmp L2
	
	S2:	mov eax,3
		invoke crt_printf,addr szFmt,eax
		jmp L2
		
	S3:	mov eax,4
		invoke crt_printf,addr szFmt,eax
		jmp L2
		
	S4:	mov eax,5
		invoke crt_printf,addr szFmt,eax
		jmp L2
	
	S_END:	mov eax,0
		invoke crt_printf,addr szFmt,eax
		jmp L2

	L2:	mov ecx,dword ptr ds:[Count]
		add ecx,1                        ; ecx ++
		mov dword ptr ds:[Count],ecx
		jmp L1
		
	lop_end:
		int 3	
	main ENDP
END main

Loop实现排序: 如果不自己构建排序循环,使用loop实现,则冒泡排序将变得香。

先来看一个汇编案例,我想说,观察下面的代码,你说 这是不是一个死循环呢?思考一下。

代码语言:javascript
复制
	.386p
	.model flat,stdcall
	option casemap:none

include windows.inc
include kernel32.inc
includelib kernel32.lib

include msvcrt.inc
includelib msvcrt.lib

.data
	Count DWORD 10
.code
	main PROC
		mov ecx,dword ptr ds:[Count]
		dec ecx
	L1:	push ecx

		invoke crt_printf,addr szFmt,ecx
		pop ecx	
		loop L1

	main ENDP
END main

不是,loop人家执行的时候,会自动的将ecx中的值减去1,所以他不是死循环,来实现一下这个需求。

代码语言:javascript
复制
#include <windows.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
	int Array[10] = { 56,88,34,67,98,25,67,10,87,43 };
	int x=10, y, temporary;

	while (x - 1 > 0)
	{
		y = x;
		while (y > 0)
		{
			if (Array[y] > Array[y - 1])
			{
				temporary = Array[y - 1];
				Array[y - 1] = Array[y];
				Array[y] = temporary;
			}
			y--;
		}
		x--;
	}

	for (int x = 0; x < 10; x++)
		printf("%d ", Array[x]);
	return 0;
}

然后使用loop实现双层夹心汉堡,口感同样一级棒.

代码语言:javascript
复制
	.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
	main PROC
		; 数组排序
		mov ecx,dword ptr ds:[Count]      ; 获取到数组元素数
		dec ecx                           ; 数组减1
	L1:	push ecx                          ; 入栈保存
		
		lea esi,dword ptr ds:[MyArray]    ; 得到数组基地址
		
	L2:	mov eax,dword ptr ds:[esi]
		cmp eax,dword ptr ds:[esi + 4]    ; 比较第一个数组与第二个
		jg L3
		
		xchg eax,[esi + 4]                ; 交换数据
		mov [esi],eax

	L3:	add esi,4
		loop L2
		
		pop ecx                           ; 弹出数据
		loop L1
		
		; for循环输出元素
		mov dword ptr ds:[PrCount],0
		
		jmp LL1
		mov ecx,dword ptr ds:[PrCount]
		add ecx,1
		mov dword ptr ds:[PrCount],ecx
	LL1:
		mov ecx,dword ptr ds:[PrCount]
		cmp ecx,10
		jg lop_end
		
		lea eax,dword ptr ds:[MyArray]
		mov ebx,dword ptr ds:[eax + ecx * 4]
		invoke crt_printf,addr szFmt,ebx
		
		mov ecx,dword ptr ds:[PrCount]
		add ecx,1
		mov dword ptr ds:[PrCount],ecx
		jmp LL1
		
	lop_end:
		int 3

	main ENDP
END main

While 实现(二分法): 二分查找法也是常用查找结构,主要思想是对半分,如果中位数大于则说明元素在前半部分,如果小于则说明在后半部分,该排序唯一需要注意的是,数组必须是一个有序集合.

代码语言:javascript
复制
#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;      // 取中位数
		if (value[mid] < searchVal)        // 中位数小于searchVal
		{                                  // 说明元素在后面
			first = mid + 1;
		}
		else if (value[mid] > searchVal)
		{                                  // 否则说明元素在前
			last = mid - 1;
		}
		else
		{ // 找到后返回中位数
			return mid;
		}
	}
	return -1;
}

int main(int argc, char *argv[])
{
	// 二分查找法,必须针对的是有序数组
	int Array[10] = { 1,2,3,4,5,6,7,8,9,10 };

	// 查找数组Array中索引7所在的下标
	int ret = BinSearch(Array, 7, 10);
	printf("数组下标: %d \n", ret);

	system("pause");
	return 0;
}

接着是尝试使用汇编实现这个查找逻辑,完整版代码已经写好了

代码语言:javascript
复制
	.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]   ; 得到要查找的数
		lea ebx,dword ptr ds:[MyArray]     ; 得到数组基地址

		; 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
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-08-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • IF/AND/OR 语句
  • While /For 语句构建
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档