• Win32汇编


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

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

    IF/AND/OR 语句

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

    #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;
    }
    
    	.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语句的判断则是只要等式两边一边的结果返回为真,则整个表达式的后半部分直接跳过。

    #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;
    }
    
    	.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混合构造:

    #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;
    }
    
    	.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语句嵌套调用: 在编写这样子的嵌套语句时,应该由外到内逐层解析,这样能更容易写出优美的表达式。

    #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;
    }
    
    	.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的数.

    #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 闰年 
    ", year);
    	}
    	{
    		printf("%d 平年 
    ", year);
    	}
    	return 0;
    }
    
    	.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语句三层嵌套:

    #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;
    }
    
    	.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: 这里有多种写法,第一种是比较好的写法,不需要增加太多编号,第二种是正常人的思维方式.

    #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;
    }
    
    	.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
    

    以下是人的逻辑方式.

    	.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: 多层循环从何治,看我的,给我写。

    #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;
    }
    

    正常写法

    	.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
    

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

    	.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是这样处理的.

    	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

    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

    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运算符的连用处理.

    	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指令左面如果成立则继续执行右面的判断,如果不成立右面的直接掠过,这样的话就比较有趣了,如下是我根据汇编代码推测的一段片段,。

    	.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来分配栈空间,并初始化后即可使用,最后需要将该空间恢复.

    	.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
    
    #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则是在原值上直接进行操作,将操作结果赋值给原值后在进行判断.

    	.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:

    #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;
    }
    
    	.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
    

    第二种如果判断

    #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;
    }
    
    	.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中的三目运算符:

    #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;
    }
    
    	.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循环的简单框架,后期会逐步提高难度,最终实现一个循环链表结构。

    	.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.

    	.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,反汇编后发现,编译器是这样构建的.

    	.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)可以指定一个范围,我们接着尝试构建一下.

    	.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数组的遍历.

    #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 
    ", Array[count]);
    		count = count + 1;
    	}
    	return 0;
    }
    
    	.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循环语句,然后在内部判断指定数值是否合格,合格输出.

    #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 
    ", Array[x]);
    		}
    	}
    	return 0;
    }
    
    	.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
    

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

    #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 
    ", max_result,min_result,sum_result,avg_result);
    	system("pause");
    	return 0;
    }
    

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

    	.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
    

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

    	.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语句的唯一区别,就在于一个是跳转到了本次循环的结束位置,另一个则是条向了总循环结束位置.

    #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 
    ", Array[index], Array[index + 1]);
    			break;
    		}
    
    		index = index + 1;
    	} while (index < 10);
    
    	return 0;
    }
    
    	.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,大于则执行加法运算,然后输出基数或偶数.

    #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 
    ", sum);
    			else
    				printf("基数: %d 
    ", sum);
    		}
    	}
    	system("pause");
    	return 0;
    }
    

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

    	.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表为例,尝试使用汇编实现.

    #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("
    ");
    	}
    	system("pause");
    	return 0;
    }
    

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

    	.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
    

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

    	.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个数,每个数分解出个位,十位,百位.

    #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);
    		}
    	}
    
    	system("pause");
    	return 0;
    }
    

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

    	.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代码如下,尝试使用汇编实现.

    #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 
    ", Array[x]);
    	
    	system("pause");
    	return 0;
    }
    

    未完待续

    	.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
    

    	.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
    

    排序完成

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

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

    #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个数字,能组成多少个互补相同且不重复的三位数,尝试使用汇编实现以下这个逻辑。

    #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 
    ", x, y, z);
    				}
    				z = z + 1;
    			}
    			z = 1;
    			y = y + 1;
    		}
    		y = 1;
    		x = x + 1;
    	}
    	return 0;
    }
    

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

    	.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
    

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

    	.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语句,就是汉堡包的佐料部分,肉质丝滑,入口即化,实在是美妙至极,如下时肉质部分。

    	.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指令跳转过去,实在美妙!

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

    	.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语句。

    #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结构.

    	.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实现,则冒泡排序将变得香。

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

    	.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,所以他不是死循环,来实现一下这个需求。

    #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实现双层夹心汉堡,口感同样一级棒.

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

    #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 
    ", ret);
    
    	system("pause");
    	return 0;
    }
    

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

    	.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
    


    版权声明: 本博客,文章与代码均为学习时整理的笔记,博客中除去明确标注有参考文献的文章,其他文章【均为原创】作品,转载请务必【添加出处】,您添加出处是我创作的动力!

    警告:如果您恶意转载本人文章,则您的整站文章,将会变为我的原创作品,请相互尊重!
  • 相关阅读:
    淀粉质模板 Tree
    洛谷 P2197 【模板】nim游戏 解题报告
    洛谷 P3168 [CQOI2015]任务查询系统 解题报告
    洛谷 P2485 [SDOI2011]计算器 解题报告
    洛谷 P4883 mzf的考验 解题报告
    洛谷 P4882 lty loves 96! 解题报告
    牛客 NOIp模拟1 T1 中位数 解题报告
    牛客 NOIp模拟1 T3 保护 解题报告
    洛谷 P3349 [ZJOI2016]小星星 解题报告
    洛谷 P4139 上帝与集合的正确用法 解题报告
  • 原文地址:https://www.cnblogs.com/LyShark/p/13584304.html
Copyright © 2020-2023  润新知