汇编Q2: 多重循环

注:此博客不再更新,所有最新文章将发表在个人独立博客limengting.site。分享技术,记录生活,欢迎大家关注

2、C语言编写多重循环程序,查看其反汇编码,分析各条语句功能,并采用汇编语言编写相同功能程序。

(1)冒泡排序

汇编代码:

;冒泡排序实现数组从小到大排序
.386
.model flat,stdcall
option casemap:none

includelib msvcrt.lib
printf	PROTO C:dword,:vararg

.data
array	dword	20,15,70,30,32,89,12	;等待被排序的数组
items	equ		($ - array) / 4		;数组元素的个数
szFmt	byte	'array[%d] = %d', 0ah, 0	;输出结果格式字符串

.code
start:
	mov		ECX, items - 1	;ECX相当于数组最大下标
i10:	;外层循环起始处
	xor		ESI, ESI	;ESI计数
i20:	;内层循环起始处
	mov		EAX, array[ESI * 4]
	mov		EBX, array[ESI * 4 + 4]
	cmp		EAX, EBX
	JL		i30		;JL 两个带符号数的比较,小于则跳转,EAX\EBX不进行交换	
	mov		array[ESI * 4], EBX
	mov		array[ESI * 4 +4], EAX
i30:
	inc		ESI;
	cmp		ESI, ECX
	JB		i20		;JB	两个无符号数的比较,小于表示不越界则跳转进行内层循环
	loop	i10		;外层循环
	xor		EDI, EDI
i40:	;输出
	invoke	printf, offset szFmt, EDI, array[EDI * 4]
	inc		EDI
	cmp		EDI, items
	JB		i40
	ret
end	start

C语言:

#include <stdio.h>

int main()
{
	int array[7] = { 20,15,70,30,32,89,12 };
 
	for (int i = 0; i < 6; i++) 
	{
		for (int j = 0; j < 6; j++)  
			if (array[j] > array[j + 1])
			{
				int temp = array[j];
				array[j] = array[j + 1];
				array[j + 1] = temp;
			}
	}

	for (int i = 0; i < 7; i++)
	{
		printf("array[%d]=%d", i, array[i]);
		printf("\n");
	}
	return 0;
}

(2)插入排序

汇编代码:

;插入排序
.386
.model flat,stdcall
option casemap:none

includelib msvcrt.lib
printf	PROTO C:dword,:vararg

;ESI = i
;EDI = j
;EDX = tmp = array[i] = array[ESI * 4]
;EBX = array[j] = array[EDI * 4]
.data
array	dword	20,15,70,30,32,89,12	;等待被排序的数组
len		equ		($ - array) / 4		;数组元素的个数
szFmt	byte	'array[%d] = %d', 0ah, 0	;输出结果格式字符串

.code
start:
mov		ECX, len - 1	;外层循环的次数放在ECX中
xor		ESI, ESI	
mov		ESI, 1		;ESI表示i,int i = 1; 

OuterLoop:	;外层循环起始处
	mov		EDX, array[ESI * 4]		;int tmp = array[i];

	xor		EDI, EDI	
	mov		EAX, ESI
	dec		EAX
	mov		EDI, EAX		;EDI表示j,int j = i - 1
	
InnerLoop:	;内层循环起始处
	cmp		array[EDI * 4], EDX ;比较array[j]和tmp
	JL		NoMovement		;JL 两个带符号数的比较,若array[j] <= tmp,则跳出内层循环到NoMovement
	mov		EBX, array[EDI * 4]
	mov		array[EDI * 4 + 4], EBX	;若array[j] > tmp,则执行array[j + 1] = array[j];
	dec		EDI				;j --
	cmp		EDI, 0			;比较是否j>=0
	JNB		InnerLoop		;若j>=0,则继续进行内层循环

NoMovement:
	mov		array[EDI * 4 + 4], EDX			;array[j + 1] = tmp;
	inc		ESI		;i++
	loop	OuterLoop			;若循环次数未到6次,则继续进行外层循环
	xor		EDI,EDI			;进入OutPut段

OutPut:	;输出	
	invoke	printf, offset szFmt, EDI, array[EDI * 4]	;为什么把EDI换成EAX就不行??只输出第一个数
	inc		EDI
	cmp		EDI, len
	JB		OutPut
	ret
end	start

C语言:

#include <stdio.h>

int main()
{
	int array[7] = { 20,15,70,30,32,89,12 };

	for (int i = 1; i < 7; i++)
	{
		int tmp = array[i];
		int j;
		for (j = i - 1; j >= 0; j--)
		{
			if (array[j] > tmp)
				array[j + 1] = array[j];
			else break;
		}
		array[j + 1] = tmp;
	}

	for (int i = 0; i < 7; i++)
	{
		printf("array[%d]=%d", i, array[i]);
		printf("\n");
	}
	return 0;
}

反汇编码:

int	3 ;中断(来自CPU内部的中断:内中断,不可屏蔽的),空的地方用int 3填上,一旦EIP跑飞就单步中断
	  ;int 3对应的机器码是CC,要用CC填充空的空间

#include <stdio.h>

int main()
{
00BD17E0  push        ebp       	;ebp压栈         
00BD17E1  mov         ebp,esp  		;ebp,esp都指向栈顶
00BD17E3  sub         esp,114h  	;esp上移114h
00BD17E9  push        ebx  		;ebx入栈
00BD17EA  push        esi  		;esi入栈
00BD17EB  push        edi  		;edi入栈
00BD17EC  lea         edi,[ebp-114h]  	;edi指向ebp-114h
00BD17F2  mov         ecx,45h  		;循环次数为45h
00BD17F7  mov         eax,0CCCCCCCCh  	;填充值都为0CCCCCCCCh,即int 3,出错会立刻中断
00BD17FC  rep stos    dword ptr es:[edi]   ;循环执行直到edi的位置
	int array[7] = { 20,15,70,30,32,89,12 };
00BD17FE  mov         dword ptr [array],14h  	;如何知道array的地址???array[0]=20
00BD1805  mov         dword ptr [ebp-1Ch],0Fh   ;array[1]=15
00BD180C  mov         dword ptr [ebp-18h],46h   ;array[2]=70
00BD1813  mov         dword ptr [ebp-14h],1Eh   ;array[3]=30
00BD181A  mov         dword ptr [ebp-10h],20h   ;array[4]=32
00BD1821  mov         dword ptr [ebp-0Ch],59h   ;array[5]=89
00BD1828  mov         dword ptr [ebp-8],0Ch  	;array[6]=12,从上往下放数,低地址放低坐标,高地址放高坐标

	for (int i = 1; i < 7; i++)             ;外层循环 	
00BD182F  mov         dword ptr [ebp-2Ch],1     ;[ebp-2Ch]中存放着i的值,并把i的初值设为1
00BD1836  jmp         main+61h (0BD1841h)       ;无条件跳转到0BD1841h处
00BD1838  mov         eax,dword ptr [ebp-2Ch]   ;i的值赋给eax
00BD183B  add         eax,1  			;eax + 1
00BD183E  mov         dword ptr [ebp-2Ch],eax   ;eax重新赋给i,即1838~183E三条语句实现i++
00BD1841  cmp         dword ptr [ebp-2Ch],7     ;i和7比较
00BD1845  jge         main+0B7h (0BD1897h)      ;jge两个带符号数的比较,如果i大于等于7则跳转到0BD1897h,结束外层循环
	{
		int tmp = array[i];
00BD1847  mov         eax,dword ptr [ebp-2Ch]   ;若i小于7则把i的值放入eax中
00BD184A  mov         ecx,dword ptr array[eax*4];ecx指向array[i]
00BD184E  mov         dword ptr [ebp-38h],ecx   ;[ebp-38h]中存着tmp的值,把array[i]的值赋给tmp
		int j;
		for (j = i - 1; j >= 0; j--)
00BD1851  mov         eax,dword ptr [ebp-2Ch]   ;把i的值赋给eax 
00BD1854  sub         eax,1  			;eax - 1
00BD1857  mov         dword ptr [ebp-44h],eax   ;eax的值赋给[ebp-44h],即j的值存放在[ebp-44h]中
00BD185A  jmp         main+85h (0BD1865h)       ;无条件跳转到0BD1865h
00BD185C  mov         eax,dword ptr [ebp-44h]   ;j的值赋给eax
00BD185F  sub         eax,1  			;eax - 1
00BD1862  mov         dword ptr [ebp-44h],eax   ;eax重新赋给j,即185C~1862三条语句实现j--
00BD1865  cmp         dword ptr [ebp-44h],0     ;比较j和0的大小
00BD1869  jl          main+0ABh (0BD188Bh)      ;如果j小于0则跳转到0BD188Bh,跳出内层循环
		{
			if (array[j] > tmp)	
00BD186B  mov         eax,dword ptr [ebp-44h]   ;j>=0则继续内层循环,把j的值赋给eax
00BD186E  mov         ecx,dword ptr array[eax*4];ecx指向array[j]  
00BD1872  cmp         ecx,dword ptr [ebp-38h]   ;比较array[j]和tmp的大小
00BD1875  jle         main+0A7h (0BD1887h)  	;如果array[j]<=tmp则跳转到0BD1887h
				array[j + 1] = array[j];
00BD1877  mov         eax,dword ptr [ebp-44h]   ;如果array[j]>tmp,则把j的值赋给eax
00BD187A  mov         ecx,dword ptr [ebp-44h]   ;把j的值赋给ecx
00BD187D  mov         edx,dword ptr array[ecx*4];把array[j]赋给edx  
00BD1881  mov         dword ptr [ebp+eax*4-1Ch],edx;[ebp-1Ch]为array[1],[ebp-1Ch+eax*4]为array[1+j],即把array[j]赋给arrayp[j+1]
			else break;
00BD1885  jmp         main+0A9h (0BD1889h)      ;无条件跳转到0BD1889h
00BD1887  jmp         main+0ABh (0BD188Bh)      ;如果array[j]<=tmp跳转到此处,继续跳转到08D188Bh 
		}
00BD1889  jmp         main+7Ch (0BD185Ch)       ;无条件跳转到0BD185Ch,重复内层循环
		array[j + 1] = tmp;
00BD188B  mov         eax,dword ptr [ebp-44h]  	;j<0跳转到此处/array[j]<=tmp也跳转到此处,把j的值赋给eax
00BD188E  mov         ecx,dword ptr [ebp-38h]   ;把tmp的值赋给ecx
00BD1891  mov         dword ptr [ebp+eax*4-1Ch],ecx  ;分析同00BD1881,把ecx赋给array[j+1],即把tmp赋给array[j+1]
	}
00BD1895  jmp         main+58h (0BD1838h)       ;无条件跳转到0BD1838h

	for (int i = 0; i < 7; i++)
00BD1897  mov         dword ptr [ebp-50h],0  	;外层循环结束跳转到这里,开始打印输出,给临时变量i赋初值为0,内存空间为[ebp-50h]
00BD189E  jmp         main+0C9h (0BD18A9h)      ;无条件跳转到0BD18A9h
00BD18A0  mov         eax,dword ptr [ebp-50h]   ;
00BD18A3  add         eax,1  
00BD18A6  mov         dword ptr [ebp-50h],eax  
00BD18A9  cmp         dword ptr [ebp-50h],7     ;比较i和7的大小
00BD18AD  jge         main+0F7h (0BD18D7h)      ;如果i>=7则跳转到0BD18D7h,结束打印的循环
	{
		printf("array[%d]=%d", i, array[i])
00BD18AF  mov         eax,dword ptr [ebp-50h]   ;把i的值赋给eax
00BD18B2  mov         ecx,dword ptr array[eax*4];把array[i]的值赋给ecx  
00BD18B6  push        ecx                       ;ecx入栈
00BD18B7  mov         edx,dword ptr [ebp-50h]   ;把i的值赋给edx
00BD18BA  push        edx                       ;edx入栈
00BD18BB  push        offset string "array[%d]=%d" (0BD7B30h) ;与0BD7B30h的偏移量入栈???  
00BD18C0  call        _printf (0BD1334h)        ;调用C库的printf
00BD18C5  add         esp,0Ch  			;esp + 12???
		printf("\n");
00BD18C8  push        offset string "\n" (0BD7B40h)  ;与0BD7B40h的偏移量入栈????
00BD18CD  call        _printf (0BD1334h)             ;调用C库中的printf
00BD18D2  add         esp,4                          ;esp + 4
	}
00BD18D5  jmp         main+0C0h (0BD18A0h)           ;无条件跳转到0BD18A0h
	return 0;
00BD18D7  xor         eax,eax              ;把eax清零
}
00BD18D9  push        edx  		   ;edx入栈
00BD18DA  mov         ecx,ebp              ;把ebp的值赋给ecx
00BD18DC  push        eax                  ;eax入栈
00BD18DD  lea         edx,ds:[0BD1900h]    ;?????????
00BD18E3  call        @_RTC_CheckStackVars@8 (0BD1267h)  
00BD18E8  pop         eax  		   ;弹出eax赋给eax
00BD18E9  pop         edx  		   ;弹出edx赋给edx
00BD18EA  pop         edi  		   ;弹出edi赋给edi
00BD18EB  pop         esi                  ;弹出esi赋给esi
00BD18EC  pop         ebx  		   ;弹出ebx赋给ebx
00BD18ED  add         esp,114h  	   ;esp + 114h恢复堆栈
00BD18F3  cmp         ebp,esp  		   ;比较ebp和esp
00BD18F5  call        __RTC_CheckEsp (0BD1122h) ;???? 
00BD18FA  mov         esp,ebp   	   ;把ebp的值赋给esp
00BD18FC  pop         ebp  	           ;弹出的值给ebp		
00BD18FD  ret  
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值