版本:Release
优化选项:O2
调试工具:OD
源码:
//二路归并排序(递归实现)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_SIZE 10
void merge(int init[],int mergesort[],int left,int mid,int right)
{
int i=left,j=mid+1;
int k=left;
while(i<=mid&&j<=right)
{
if(init[i]<=init[j])
mergesort[k++]=init[i++];
else
mergesort[k++]=init[j++];
}
while(i<=mid)
mergesort[k++]=init[i++];
while(j<=right)
mergesort[k++]=init[j++];
for(k=left;k<=right;k++)
init[k]=mergesort[k];//must copy to orginal array
}
void sort(int init[],int mergesort[],int left,int right)//递归版本
{
int mid;
if(left<right)
{
mid=(left+right)/2;
sort(init,mergesort,left,mid);
sort(init,mergesort,mid+1,right);
merge(init,mergesort,left,mid,right);
}
}
int main()
{
int i,left=0,right=MAX_SIZE-1;
int init[MAX_SIZE],mergesort[MAX_SIZE];
srand((unsigned)time(0));
for(i=0;i<MAX_SIZE;i++)
init[i]=rand()%50;
for(i=0;i<MAX_SIZE;i++)
printf("%4d",init[i]);
sort(init,mergesort,left,right);
for(i=0;i<MAX_SIZE;i++)
printf("%4d",init[i]);
system("pause");
return 0;
}
首先是主函数的反汇编,主函数没什么需要注意的,就直接上代码了
013C1100 >/$ 83EC 50 sub esp, 50
013C1103 |. 56 push esi
013C1104 |. 57 push edi
013C1105 |. 6A 00 push 0
013C1107 |. FF15 A0203C01 call dword ptr [<&MSVCR90._time64>] ; MSVCR90._time64
013C110D |. 50 push eax ; /seed
013C110E |. FF15 A4203C01 call dword ptr [<&MSVCR90.srand>] ; \srand
013C1114 |. 8B3D A8203C01 mov edi, dword ptr [<&MSVCR90.rand>] ; MSVCR90.rand
013C111A |. 83C4 08 add esp, 8
013C111D |. 33F6 xor esi, esi
013C111F |. 90 nop
013C1120 |> FFD7 /call edi ; 这个循环作用就是取得10个随机数存入数组,不多说
013C1122 |. 99 |cdq
013C1123 |. B9 32000000 |mov ecx, 32
013C1128 |. F7F9 |idiv ecx
013C112A |. 46 |inc esi
013C112B |. 83FE 0A |cmp esi, 0A
013C112E |. 8954B4 04 |mov dword ptr [esp+esi*4+4], edx
013C1132 |.^ 7C EC \jl short 013C1120
013C1134 |. 8B3D AC203C01 mov edi, dword ptr [<&MSVCR90.printf>; MSVCR90.printf
013C113A |. 33F6 xor esi, esi
013C113C |. 8D6424 00 lea esp, dword ptr [esp]
013C1140 |> 8B54B4 08 /mov edx, dword ptr [esp+esi*4+8] ; 输出10个随机数
013C1144 |. 52 |push edx
013C1145 |. 68 04213C01 |push 013C2104 ; ASCII "%4d"
013C114A |. FFD7 |call edi
013C114C |. 46 |inc esi
013C114D |. 83C4 08 |add esp, 8
013C1150 |. 83FE 0A |cmp esi, 0A
013C1153 |.^ 7C EB \jl short 013C1140
013C1155 |. 6A 04 push 4 ; 下面连着几个sort调用应该是编译器优化出来的,被分成几次调用并移到主函数中
013C1157 |. 6A 00 push 0
013C1159 |. 8D4424 38 lea eax, dword ptr [esp+38] ; 临时数组地址(紧接着待排序数组)
013C115D |. 50 push eax
013C115E |. 8D4C24 14 lea ecx, dword ptr [esp+14]
013C1162 |. 51 push ecx ; 待排序数组地址
013C1163 |. E8 48FFFFFF call sort
013C1168 |. 6A 09 push 9
013C116A |. 6A 05 push 5
013C116C |. 8D5424 48 lea edx, dword ptr [esp+48]
013C1170 |. 52 push edx
013C1171 |. 8D4424 24 lea eax, dword ptr [esp+24]
013C1175 |. 50 push eax
013C1176 |. E8 35FFFFFF call sort
013C117B |. 6A 09 push 9
013C117D |. 6A 04 push 4
013C117F |. 8D4C24 58 lea ecx, dword ptr [esp+58]
013C1183 |. 6A 00 push 0
013C1185 |. 51 push ecx
013C1186 |. 8D7424 38 lea esi, dword ptr [esp+38]
013C118A |. E8 71FEFFFF call merge
013C118F |. 83C4 30 add esp, 30
013C1192 |. 33F6 xor esi, esi
013C1194 |> 8B54B4 08 /mov edx, dword ptr [esp+esi*4+8] ; 输出排序后数组
013C1198 |. 52 |push edx
013C1199 |. 68 04213C01 |push 013C2104 ; ASCII "%4d"
013C119E |. FFD7 |call edi
013C11A0 |. 46 |inc esi
013C11A1 |. 83C4 08 |add esp, 8
013C11A4 |. 83FE 0A |cmp esi, 0A
013C11A7 |.^ 7C EB \jl short 013C1194
013C11A9 |. 68 08213C01 push 013C2108 ; /command = "pause"
013C11AE |. FF15 B0203C01 call dword ptr [<&MSVCR90.system>] ; \system
013C11B4 |. 83C4 04 add esp, 4
013C11B7 |. 5F pop edi
013C11B8 |. 33C0 xor eax, eax
013C11BA |. 5E pop esi
013C11BB |. 83C4 50 add esp, 50
013C11BE \. C3 retn
接下来是sort函数的反汇编,也没啥难度,就是些调用,直接贴代码
013C10B0 >/$ 53 push ebx
013C10B1 |. 8B5C24 10 mov ebx, dword ptr [esp+10] ; 第3个参数
013C10B5 |. 55 push ebp
013C10B6 |. 8B6C24 18 mov ebp, dword ptr [esp+18] ; 第4个参数
013C10BA |. 3BDD cmp ebx, ebp
013C10BC |. 7D 3F jge short 013C10FD
013C10BE |. 56 push esi
013C10BF |. 8B7424 14 mov esi, dword ptr [esp+14] ; 第2个参数
013C10C3 |. 8D042B lea eax, dword ptr [ebx+ebp] ; left+right?
013C10C6 |. 99 cdq
013C10C7 |. 57 push edi
013C10C8 |. 2BC2 sub eax, edx
013C10CA |. 8BF8 mov edi, eax
013C10CC |. 8B4424 14 mov eax, dword ptr [esp+14] ; 第一个参数
013C10D0 |. D1FF sar edi, 1 ; (left+right)/2
013C10D2 |. 57 push edi
013C10D3 |. 53 push ebx ; left
013C10D4 |. 56 push esi ; 就是传进来的第二个参数
013C10D5 |. 50 push eax ; 第一个参数
013C10D6 |. E8 D5FFFFFF call sort
013C10DB |. 8B5424 24 mov edx, dword ptr [esp+24]
013C10DF |. 55 push ebp ; right
013C10E0 |. 8D4F 01 lea ecx, dword ptr [edi+1] ; left+1
013C10E3 |. 51 push ecx
013C10E4 |. 56 push esi
013C10E5 |. 52 push edx
013C10E6 |. E8 C5FFFFFF call sort
013C10EB |. 55 push ebp ; right
013C10EC |. 57 push edi ; (left+right)/2
013C10ED |. 53 push ebx ; left
013C10EE |. 56 push esi ; 第二个参数
013C10EF |. 8B7424 44 mov esi, dword ptr [esp+44] ; 第一个参数
013C10F3 |. E8 08FFFFFF call merge
013C10F8 |. 83C4 30 add esp, 30
013C10FB |. 5F pop edi
013C10FC |. 5E pop esi
013C10FD |> 5D pop ebp
013C10FE |. 5B pop ebx
013C10FF \. C3 retn
接下来就是主要的排序实现函数merge的代码了,C版的是有5个参数,而汇编版只有4个参数是明显的,还有一个参数是直接用寄存器存储这个要注意下
013C1000 >/$ 53 push ebx
013C1001 |. 8B5C24 10 mov ebx, dword ptr [esp+10] ; 第4个参数(以C源码来说)
013C1005 |. 55 push ebp
013C1006 |. 8B6C24 18 mov ebp, dword ptr [esp+18] ; 第5个参数
013C100A |. 57 push edi
013C100B |. 8B7C24 14 mov edi, dword ptr [esp+14] ; 第3个参数
013C100F |. 3BFB cmp edi, ebx ; cmp left,mid
013C1011 |. 8BCF mov ecx, edi ; 这个ecx用于后面循环的下标增长
013C1013 |. 8D53 01 lea edx, dword ptr [ebx+1] ; edx=mid+1
013C1016 |. 8BC7 mov eax, edi ; 这个eax就是排序后数组中的下标
013C1018 |. 7F 50 jg short 013C106A
013C101A |. 8D9B 00000000 lea ebx, dword ptr [ebx]
013C1020 |> 3BD5 /cmp edx, ebp
013C1022 |. 7F 2A |jg short 013C104E
013C1024 |. 8B3C8E |mov edi, dword ptr [esi+ecx*4] ; a[left]
013C1027 |. 8B1C96 |mov ebx, dword ptr [esi+edx*4] ; a[mid+1]
013C102A |. 3BFB |cmp edi, ebx
013C102C |. 7F 0B |jg short 013C1039
013C102E |. 8B5C24 10 |mov ebx, dword ptr [esp+10] ; 第二个参数(目标数组)
013C1032 |. 893C83 |mov dword ptr [ebx+eax*4], edi
013C1035 |. 40 |inc eax
013C1036 |. 41 |inc ecx
013C1037 |. EB 09 |jmp short 013C1042
013C1039 |> 8B7C24 10 |mov edi, dword ptr [esp+10]
013C103D |. 891C87 |mov dword ptr [edi+eax*4], ebx
013C1040 |. 40 |inc eax ; eax==left
013C1041 |. 42 |inc edx ; edx==mid+1
013C1042 |> 3B4C24 18 |cmp ecx, dword ptr [esp+18] ; cmp ecx,mid
013C1046 |. 8B7C24 14 |mov edi, dword ptr [esp+14]
013C104A |.^ 7E D4 \jle short 013C1020
上面这个隔开了的循环是主要循环,而且感觉应该是和源码有点出入
我的反汇编还原结果: 源码:
while(j<=right) while(i<=mid&&j<=right)
{ {
if(init[i]<=init[j]) if(init[i]<=init[j])
mergesort[k++]=init[i++]; mergesort[k++]=init[i++];
else else
mergesort[k++]=init[j++]; mergesort[k++]=init[j++];
if(i>mid) break; }
}
发现了吗?在第一次进入循环的时候判断为真缺了个i<=mid,后面的是一样的,只有在第一次进入会发生这种情况
反正我是不知道为什么。。也许在某些情况下就会发生错误呢?于是抱着编译器不可能这么不严禁的态度继续研究研究,于是发现
这样是没有问题的,其实传入的3个参数有这样一种关系:mid=(left+right)/2;经过一些计算就可以发现当(mid+2)<=right{j<=right}时,left<=right{i<=mid}必定成立(自己可以算算),当然仅限于第一次进入循环的时候,也就是说编译器编译的时候提前发现了这种数学关系然后做了些小优化吧。感叹下写编译器的人真牛!
013C104C |. EB 1C jmp short 013C106A
013C104E |> 3B4C24 18 cmp ecx, dword ptr [esp+18] ; 这和上面那个循环判断条件一样,再之下一个循环也是一个类似的判断,2个循环大体表达一个意思只是参数有所不同,仔细看看应该能发现
013C1052 |. 7F 16 jg short 013C106A
013C1054 |> 8B3C8E /mov edi, dword ptr [esi+ecx*4]
013C1057 |. 8B5C24 10 |mov ebx, dword ptr [esp+10] ; 目标数组的地址
013C105B |. 893C83 |mov dword ptr [ebx+eax*4], edi ; 将比较结果后其中一个数存入结果数组
013C105E |. 41 |inc ecx
013C105F |. 40 |inc eax
013C1060 |. 3B4C24 18 |cmp ecx, dword ptr [esp+18]
013C1064 |.^ 7E EE \jle short 013C1054 ; 这个循环大体上是 while(i<=j) b[x++]=a[j];这个样子
013C1066 |. 8B7C24 14 mov edi, dword ptr [esp+14]
013C106A |> 3BD5 cmp edx, ebp
013C106C |. 7F 14 jg short 013C1082
013C106E |. 8B4C24 10 mov ecx, dword ptr [esp+10] ; 这个循环指令有所不同,但意思是一个意思仅参数有所区别,就不多说了
013C1072 |. 8D0481 lea eax, dword ptr [ecx+eax*4]
013C1075 |> 8B0C96 /mov ecx, dword ptr [esi+edx*4]
013C1078 |. 8908 |mov dword ptr [eax], ecx
013C107A |. 42 |inc edx
013C107B |. 83C0 04 |add eax, 4
013C107E |. 3BD5 |cmp edx, ebp
013C1080 |.^ 7E F3 \jle short 013C1075
013C1082 |> 3BFD cmp edi, ebp
013C1084 |. 7F 19 jg short 013C109F
013C1086 |. 8B4C24 10 mov ecx, dword ptr [esp+10] ; 目标数组地址
013C108A |. 2BEF sub ebp, edi ; right-left
013C108C |. 2BCE sub ecx, esi ; ecx==待排序数组大小
013C108E |. 8D04BE lea eax, dword ptr [esi+edi*4] ; a[left]
013C1091 |. 45 inc ebp
013C1092 |> 8B1401 /mov edx, dword ptr [ecx+eax]
013C1095 |. 8910 |mov dword ptr [eax], edx
013C1097 |. 83C0 04 |add eax, 4
013C109A |. 83ED 01 |sub ebp, 1
013C109D |.^ 75 F3 \jnz short 013C1092 ; 这个循环模式大体上是while(right--) a[i++]=b[i++];
013C109F |> 5F pop edi
013C10A0 |. 5D pop ebp
013C10A1 |. 5B pop ebx
013C10A2 \. C3 retn