注:此博客不再更新,所有最新文章将发表在个人独立博客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