逆向之堆排序
版本:Release
优化选项:O2
调试工具:OD
源码:
- //堆排序
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #define MAX_SIZE 10
- #define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
- void adjust(int a[],int rootn,int n)//调整堆
- {
- int temp,parent,child;
- temp=a[rootn];
- parent=rootn;
- child=2*parent;
- while(child<=n)
- {
- if(child<n&&a[child]<a[child+1])
- child++;
- if(temp>a[child])
- break;
- a[parent]=a[child];
- parent=child;
- child*=2;
- }
- a[parent]=temp;
- }
- void heapsort(int a[],int n)
- {
- int i,temp;
- for(i=n/2;i>0;i--)
- adjust(a,i,n);//自下而上逐层建堆
- for(i=n-1;i>0;i--)
- {
- SWAP(a[1],a[i+1],temp);//取堆顶点最大元素
- adjust(a,1,i);//调整堆
- }
- }
- int main()
- {
- int i;
- int a[MAX_SIZE+1];//={0,5,8,4,6,2,15,12,58,12,10};
- srand((unsigned)time(0));
- for(i=1;i<=MAX_SIZE;i++)
- a[i]=rand()%100;
- for(i=1;i<=MAX_SIZE;i++)
- printf("%4d",a[i]);
- putchar('\n');
- heapsort(a,MAX_SIZE);
- for(i=1;i<=MAX_SIZE;i++)
- printf("%4d",a[i]);
- system("pause");
- return 0;
- }
- 首先把主函数架子给反出来,比较简单
- 012610A0 >/$ 83EC 2C sub esp, 2C
- 012610A3 |. 56 push esi
- 012610A4 |. 57 push edi
- 012610A5 |. 6A 00 push 0
- 012610A7 |. FF15 A0202601 call dword ptr [<&MSVCR90._time64>] ; MSVCR90._time64
- 012610AD |. 50 push eax ; /seed
- 012610AE |. FF15 A8202601 call dword ptr [<&MSVCR90.srand>] ; \srand
- 012610B4 |. 8B3D AC202601 mov edi, dword ptr [<&MSVCR90.rand>] ; MSVCR90.rand
- 012610BA |. 83C4 08 add esp, 8
- 012610BD |. BE 01000000 mov esi, 1
- 012610C2 |> FFD7 /call edi
- 012610C4 |. 99 |cdq
- 012610C5 |. B9 64000000 |mov ecx, 64 ; 100取余
- 012610CA |. F7F9 |idiv ecx
- 012610CC |. 46 |inc esi
- 012610CD |. 83FE 0A |cmp esi, 0A ; 分配10个元素
- 012610D0 |. 8954B4 04 |mov dword ptr [esp+esi*4+4], edx ; 第一次到这里其实esi==2,也就是说随机数存储在分配数组中下标1开始
- 012610D4 |.^ 7E EC \jle short 012610C2
- 012610D6 |. 8B3D B0202601 mov edi, dword ptr [<&MSVCR90.printf>; MSVCR90.printf
- 012610DC |. BE 01000000 mov esi, 1
- 012610E1 |> 8B54B4 08 /mov edx, dword ptr [esp+esi*4+8] ; 这个循环是输出随机取得的数
- 012610E5 |. 52 |push edx
- 012610E6 |. 68 04212601 |push 01262104 ; ASCII "%4d"
- 012610EB |. FFD7 |call edi
- 012610ED |. 46 |inc esi
- 012610EE |. 83C4 08 |add esp, 8
- 012610F1 |. 83FE 0A |cmp esi, 0A ; 依旧是循环10次
- 012610F4 |.^ 7E EB \jle short 012610E1
- 012610F6 |. 6A 0A push 0A ; /c = 0A (Line Feed)
- 012610F8 |. FF15 A4202601 call dword ptr [<&MSVCR90.putchar>] ; \putchar
- 012610FE |. 83C4 04 add esp, 4
- 01261101 |. 8D4424 08 lea eax, dword ptr [esp+8] ; 取分配数组的地址
- 01261105 |. E8 F6FEFFFF call heapsort ; 排序函数是我们要主要分析的
- 0126110A |. BE 01000000 mov esi, 1
- 0126110F |. 90 nop
- 01261110 |> 8B44B4 08 /mov eax, dword ptr [esp+esi*4+8] ; 看过前面几个循环应该不会陌生了吧,一个模式,输出排序后的数
- 01261114 |. 50 |push eax
- 01261115 |. 68 04212601 |push 01262104 ; ASCII "%4d"
- 0126111A |. FFD7 |call edi
- 0126111C |. 46 |inc esi
- 0126111D |. 83C4 08 |add esp, 8
- 01261120 |. 83FE 0A |cmp esi, 0A
- 01261123 |.^ 7E EB \jle short 01261110
- 01261125 |. 68 08212601 push 01262108 ; /command = "pause"
- 0126112A |. FF15 B4202601 call dword ptr [<&MSVCR90.system>] ; \system
- 01261130 |. 83C4 04 add esp, 4
- 01261133 |. 5F pop edi
- 01261134 |. 33C0 xor eax, eax
- 01261136 |. 5E pop esi
- 01261137 |. 83C4 2C add esp, 2C
- 0126113A \. C3 retn
- 嗯。下面分析我们的排序函数,这才是重头戏嘛
- 先大概浏览了下主要的跳转,发现函数调用直接插进来优化掉了没有了函数调用,本来还想从子函数入手的,既然如此就直接上吧,虽然会有点复杂
- 01261000 >/$ 53 push ebx
- 01261001 |. 55 push ebp
- 01261002 |. 56 push esi
- 01261003 |. 57 push edi
- 01261004 |. BF 05000000 mov edi, 5 ; 姑且认为edi是数组下标吧,令edi=n
- 01261009 |. 8DA424 000000>lea esp, dword ptr [esp]
- 01261010 |> 83FF 05 /cmp edi, 5
- 01261013 |. 8B1CB8 |mov ebx, dword ptr [eax+edi*4]
- 01261016 |. 8BF7 |mov esi, edi
- 01261018 |. 8D0C3F |lea ecx, dword ptr [edi+edi] ; ecx=2n
- 0126101B |. 7F 22 |jg short 0126103F ; 粗略来看下面这些跳转是为了找出a[n],a[2n],a[2n+1]中较大的数
- 0126101D |. 83F9 0A |cmp ecx, 0A ; if (2n<10)
- 01261020 |> 7D 0A |/jge short 0126102C
- 01261022 |. 8B1488 ||mov edx, dword ptr [eax+ecx*4]
- 01261025 |. 3B5488 04 ||cmp edx, dword ptr [eax+ecx*4+4] ; if(a[2n]<a[2n+1])
- 01261029 |. 7D 01 ||jge short 0126102C
- 0126102B |. 41 ||inc ecx
- 0126102C |> 8B1488 ||mov edx, dword ptr [eax+ecx*4]
- 0126102F |. 3BDA ||cmp ebx, edx ; if (a[n]<=a[2n+1])
- 01261031 |. 7F 0C ||jg short 0126103F
- 01261033 |. 8914B0 ||mov dword ptr [eax+esi*4], edx ; a[n]=a[较大那个]
- 01261036 |. 8BF1 ||mov esi, ecx ; esi=ecx,这里ecx是最大数的下标
- 01261038 |. 03C9 ||add ecx, ecx ; ecx=2*ecx,继续向下搜索调整
- 0126103A |. 83F9 0A ||cmp ecx, 0A
- 0126103D |.^ 7E E1 |\jle short 01261020
- 0126103F |> 4F |dec edi ; n--
- 01261040 |. 891CB0 |mov dword ptr [eax+esi*4], ebx ; 到这里,在看下上面涉及到了ebx的代码,观察下就可以发现a[n]==ebx,而这些代码的目的应该是找到最大数的位置,然后将a[n]替换进去
- 01261043 |. 85FF |test edi, edi ; n>0则继续循环
- 01261045 |.^ 7F C9 \jg short 01261010
- 01261047 |. BA 09000000 mov edx, 9
- 0126104C |. 8D68 28 lea ebp, dword ptr [eax+28] ; a[10]
- 0126104F |. 90 nop
- 01261050 |> 8B75 00 /mov esi, dword ptr [ebp]
- 01261053 |. 8B48 04 |mov ecx, dword ptr [eax+4] ; SWAP a[1],a[10]
- 01261056 |. 8970 04 |mov dword ptr [eax+4], esi ; a[10]
- 01261059 |. 894D 00 |mov dword ptr [ebp], ecx
- 0126105C |. 8B58 04 |mov ebx, dword ptr [eax+4]
- 0126105F |. B9 02000000 |mov ecx, 2
- 01261064 |. 3BCA |cmp ecx, edx ; 我们假设edx就是n吧,这样的话if(2<n)
- 01261066 |. BE 01000000 |mov esi, 1
- 0126106B |. 7F 1E |jg short 0126108B
- 0126106D |> 7D 0A |/jge short 01261079 ; 下面这段循环和上面一个套路,只是优化后略有不同(明明是一个函数,妹的)
- 0126106F |. 8B3C88 ||mov edi, dword ptr [eax+ecx*4]
- 01261072 |. 3B7C88 04 ||cmp edi, dword ptr [eax+ecx*4+4]
- 01261076 |. 7D 01 ||jge short 01261079
- 01261078 |. 41 ||inc ecx
- 01261079 |> 8B3C88 ||mov edi, dword ptr [eax+ecx*4]
- 0126107C |. 3BDF ||cmp ebx, edi
- 0126107E |. 7F 0B ||jg short 0126108B
- 01261080 |. 893CB0 ||mov dword ptr [eax+esi*4], edi
- 01261083 |. 8BF1 ||mov esi, ecx
- 01261085 |. 03C9 ||add ecx, ecx
- 01261087 |. 3BCA ||cmp ecx, edx
- 01261089 |.^ 7E E2 |\jle short 0126106D
- 0126108B |> 4A |dec edx ; n--
- 0126108C |. 83ED 04 |sub ebp, 4
- 0126108F |. 891CB0 |mov dword ptr [eax+esi*4], ebx
- 01261092 |. 85D2 |test edx, edx
- 01261094 |.^ 7F BA \jg short 01261050
- 01261096 |. 5F pop edi
- 01261097 |. 5E pop esi
- 01261098 |. 5D pop ebp
- 01261099 |. 5B pop ebx
- 0126109A \. C3 retn
//堆排序
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX_SIZE 10
#define SWAP(x,y,t) ((t)=(x),(x)=(y),(y)=(t))
void adjust(int a[],int rootn,int n)//调整堆
{
int temp,parent,child;
temp=a[rootn];
parent=rootn;
child=2*parent;
while(child<=n)
{
if(child<n&&a[child]<a[child+1])
child++;
if(temp>a[child])
break;
a[parent]=a[child];
parent=child;
child*=2;
}
a[parent]=temp;
}
void heapsort(int a[],int n)
{
int i,temp;
for(i=n/2;i>0;i--)
adjust(a,i,n);//自下而上逐层建堆
for(i=n-1;i>0;i--)
{
SWAP(a[1],a[i+1],temp);//取堆顶点最大元素
adjust(a,1,i);//调整堆
}
}
int main()
{
int i;
int a[MAX_SIZE+1];//={0,5,8,4,6,2,15,12,58,12,10};
srand((unsigned)time(0));
for(i=1;i<=MAX_SIZE;i++)
a[i]=rand()%100;
for(i=1;i<=MAX_SIZE;i++)
printf("%4d",a[i]);
putchar('\n');
heapsort(a,MAX_SIZE);
for(i=1;i<=MAX_SIZE;i++)
printf("%4d",a[i]);
system("pause");
return 0;
}
首先把主函数架子给反出来,比较简单
012610A0 >/$ 83EC 2C sub esp, 2C
012610A3 |. 56 push esi
012610A4 |. 57 push edi
012610A5 |. 6A 00 push 0
012610A7 |. FF15 A0202601 call dword ptr [<&MSVCR90._time64>] ; MSVCR90._time64
012610AD |. 50 push eax ; /seed
012610AE |. FF15 A8202601 call dword ptr [<&MSVCR90.srand>] ; \srand
012610B4 |. 8B3D AC202601 mov edi, dword ptr [<&MSVCR90.rand>] ; MSVCR90.rand
012610BA |. 83C4 08 add esp, 8
012610BD |. BE 01000000 mov esi, 1
012610C2 |> FFD7 /call edi
012610C4 |. 99 |cdq
012610C5 |. B9 64000000 |mov ecx, 64 ; 100取余
012610CA |. F7F9 |idiv ecx
012610CC |. 46 |inc esi
012610CD |. 83FE 0A |cmp esi, 0A ; 分配10个元素
012610D0 |. 8954B4 04 |mov dword ptr [esp+esi*4+4], edx ; 第一次到这里其实esi==2,也就是说随机数存储在分配数组中下标1开始
012610D4 |.^ 7E EC \jle short 012610C2
012610D6 |. 8B3D B0202601 mov edi, dword ptr [<&MSVCR90.printf>; MSVCR90.printf
012610DC |. BE 01000000 mov esi, 1
012610E1 |> 8B54B4 08 /mov edx, dword ptr [esp+esi*4+8] ; 这个循环是输出随机取得的数
012610E5 |. 52 |push edx
012610E6 |. 68 04212601 |push 01262104 ; ASCII "%4d"
012610EB |. FFD7 |call edi
012610ED |. 46 |inc esi
012610EE |. 83C4 08 |add esp, 8
012610F1 |. 83FE 0A |cmp esi, 0A ; 依旧是循环10次
012610F4 |.^ 7E EB \jle short 012610E1
012610F6 |. 6A 0A push 0A ; /c = 0A (Line Feed)
012610F8 |. FF15 A4202601 call dword ptr [<&MSVCR90.putchar>] ; \putchar
012610FE |. 83C4 04 add esp, 4
01261101 |. 8D4424 08 lea eax, dword ptr [esp+8] ; 取分配数组的地址
01261105 |. E8 F6FEFFFF call heapsort ; 排序函数是我们要主要分析的
0126110A |. BE 01000000 mov esi, 1
0126110F |. 90 nop
01261110 |> 8B44B4 08 /mov eax, dword ptr [esp+esi*4+8] ; 看过前面几个循环应该不会陌生了吧,一个模式,输出排序后的数
01261114 |. 50 |push eax
01261115 |. 68 04212601 |push 01262104 ; ASCII "%4d"
0126111A |. FFD7 |call edi
0126111C |. 46 |inc esi
0126111D |. 83C4 08 |add esp, 8
01261120 |. 83FE 0A |cmp esi, 0A
01261123 |.^ 7E EB \jle short 01261110
01261125 |. 68 08212601 push 01262108 ; /command = "pause"
0126112A |. FF15 B4202601 call dword ptr [<&MSVCR90.system>] ; \system
01261130 |. 83C4 04 add esp, 4
01261133 |. 5F pop edi
01261134 |. 33C0 xor eax, eax
01261136 |. 5E pop esi
01261137 |. 83C4 2C add esp, 2C
0126113A \. C3 retn
嗯。下面分析我们的排序函数,这才是重头戏嘛
先大概浏览了下主要的跳转,发现函数调用直接插进来优化掉了没有了函数调用,本来还想从子函数入手的,既然如此就直接上吧,虽然会有点复杂
01261000 >/$ 53 push ebx
01261001 |. 55 push ebp
01261002 |. 56 push esi
01261003 |. 57 push edi
01261004 |. BF 05000000 mov edi, 5 ; 姑且认为edi是数组下标吧,令edi=n
01261009 |. 8DA424 000000>lea esp, dword ptr [esp]
01261010 |> 83FF 05 /cmp edi, 5
01261013 |. 8B1CB8 |mov ebx, dword ptr [eax+edi*4]
01261016 |. 8BF7 |mov esi, edi
01261018 |. 8D0C3F |lea ecx, dword ptr [edi+edi] ; ecx=2n
0126101B |. 7F 22 |jg short 0126103F ; 粗略来看下面这些跳转是为了找出a[n],a[2n],a[2n+1]中较大的数
0126101D |. 83F9 0A |cmp ecx, 0A ; if (2n<10)
01261020 |> 7D 0A |/jge short 0126102C
01261022 |. 8B1488 ||mov edx, dword ptr [eax+ecx*4]
01261025 |. 3B5488 04 ||cmp edx, dword ptr [eax+ecx*4+4] ; if(a[2n]<a[2n+1])
01261029 |. 7D 01 ||jge short 0126102C
0126102B |. 41 ||inc ecx
0126102C |> 8B1488 ||mov edx, dword ptr [eax+ecx*4]
0126102F |. 3BDA ||cmp ebx, edx ; if (a[n]<=a[2n+1])
01261031 |. 7F 0C ||jg short 0126103F
01261033 |. 8914B0 ||mov dword ptr [eax+esi*4], edx ; a[n]=a[较大那个]
01261036 |. 8BF1 ||mov esi, ecx ; esi=ecx,这里ecx是最大数的下标
01261038 |. 03C9 ||add ecx, ecx ; ecx=2*ecx,继续向下搜索调整
0126103A |. 83F9 0A ||cmp ecx, 0A
0126103D |.^ 7E E1 |\jle short 01261020
0126103F |> 4F |dec edi ; n--
01261040 |. 891CB0 |mov dword ptr [eax+esi*4], ebx ; 到这里,在看下上面涉及到了ebx的代码,观察下就可以发现a[n]==ebx,而这些代码的目的应该是找到最大数的位置,然后将a[n]替换进去
01261043 |. 85FF |test edi, edi ; n>0则继续循环
01261045 |.^ 7F C9 \jg short 01261010
01261047 |. BA 09000000 mov edx, 9
0126104C |. 8D68 28 lea ebp, dword ptr [eax+28] ; a[10]
0126104F |. 90 nop
01261050 |> 8B75 00 /mov esi, dword ptr [ebp]
01261053 |. 8B48 04 |mov ecx, dword ptr [eax+4] ; SWAP a[1],a[10]
01261056 |. 8970 04 |mov dword ptr [eax+4], esi ; a[10]
01261059 |. 894D 00 |mov dword ptr [ebp], ecx
0126105C |. 8B58 04 |mov ebx, dword ptr [eax+4]
0126105F |. B9 02000000 |mov ecx, 2
01261064 |. 3BCA |cmp ecx, edx ; 我们假设edx就是n吧,这样的话if(2<n)
01261066 |. BE 01000000 |mov esi, 1
0126106B |. 7F 1E |jg short 0126108B
0126106D |> 7D 0A |/jge short 01261079 ; 下面这段循环和上面一个套路,只是优化后略有不同(明明是一个函数,妹的)
0126106F |. 8B3C88 ||mov edi, dword ptr [eax+ecx*4]
01261072 |. 3B7C88 04 ||cmp edi, dword ptr [eax+ecx*4+4]
01261076 |. 7D 01 ||jge short 01261079
01261078 |. 41 ||inc ecx
01261079 |> 8B3C88 ||mov edi, dword ptr [eax+ecx*4]
0126107C |. 3BDF ||cmp ebx, edi
0126107E |. 7F 0B ||jg short 0126108B
01261080 |. 893CB0 ||mov dword ptr [eax+esi*4], edi
01261083 |. 8BF1 ||mov esi, ecx
01261085 |. 03C9 ||add ecx, ecx
01261087 |. 3BCA ||cmp ecx, edx
01261089 |.^ 7E E2 |\jle short 0126106D
0126108B |> 4A |dec edx ; n--
0126108C |. 83ED 04 |sub ebp, 4
0126108F |. 891CB0 |mov dword ptr [eax+esi*4], ebx
01261092 |. 85D2 |test edx, edx
01261094 |.^ 7F BA \jg short 01261050
01261096 |. 5F pop edi
01261097 |. 5E pop esi
01261098 |. 5D pop ebp
01261099 |. 5B pop ebx
0126109A \. C3 retn
总结:
逆向的时候在进入一个很多跳转的指令中时,最好大概看下循环中一些常用到的寄存器,然后可以将寄存器记在纸上,而不是向无头苍蝇一样直接冲进指令堆中,结果常常是找不着北,这样应该会有助于分析流程控制条件和实现的功能等
虽然一条条指令分析并记在纸上简单又准确我也常这样做,不过我想如果在遇到一些大,复杂的跳转循环之类的指令应该会很麻烦吧,我是这么认为。。总之有一定目的性的分析应该会更好些
-------------------------------------------------------------
- 版本:Release
- 优化选项:O2
- 调试工具:OD
- 源码:
版本: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