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 闰年 \n", year);
	}
	{
		printf("%d 平年 \n", 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 \n", 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 \n", 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 \n", 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 \n", 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 \n", sum);
			else
				printf("基数: %d \n", 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("\n");
	}
	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", 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 \n", 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 \n", 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 \n", 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

posted @ 2020-08-30 12:45  lyshark  阅读(977)  评论(0编辑  收藏  举报

loading... | loading...
博客园 - 开发者的网上家园