第五篇:逆向之二路归并排序
2012-05-06 17:07
447 查看
版本: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
相关文章推荐
- 经典排序之二 快速排序 + 二路归并
- C++ 二路归并排序
- 二路归并排序
- 二路归并排序简介及其并行化
- 数据结构经典排序---二路归并排序
- 二路归并排序简介及其并行化
- 二路归并排序及其改进方法
- 排序算法大集锦_二路归并排序_2&3(分治思想)
- 二路归并排序
- 二路归并排序
- 二路归并排序
- 数据结构-数组排序-二路归并-循环实现-C语言
- 两种归并排序算法的实现:二路归并排序和基本归并排序(虚拟消除递归的二路归并排序)
- 二路归并排序Python实现
- 微软笔试题 大型文件外部排序(二路归并和k路归并的实现和比较)
- 二路归并排序
- 二路归并排序_2011_10_11
- 微软笔试题 大型文件外部排序(二路归并和k路归并的实现和比较)
- 二路归并排序
- 二路归并排序及数组中逆序对的计算