时间: 2021-07-31 作者:daque
咱们领会在举行因变量挪用时,有几种挪用本领,分为c式,pascal式。在c和c++中c式挪用是缺省的,只有特出证明。二者是有辨别的,底下咱们用范例证明一下: 1. __cdecl :c和c++缺省挪用办法 例子: void input( int &m,int &n);/*十分于void __cdecl input(int &m,int &n);*/ 以次是相映的汇编代码: 00401068 lea eax,[ebp-8] ;取[ebp-8]地方(ebp-8),存到eax 0040106b push eax ;而后压栈 0040106c lea ecx,[ebp-4] ;取[ebp-4]地方(ebp-4),存到ecx 0040106f push ecx ;而后压栈 00401070 call @ilt+5(input) (0040100a);而后挪用input因变量 00401075 add esp,8 ;回复栈 从之上挪用input因变量的进程不妨看出:在挪用此因变量之前,开始压栈ebp-8,而后压栈ebp-4,而后挪用因变量input,结果input因变量挪用中断后,运用esp+8回复栈。由此看来,在c谈话挪用中默许的因变量化装_cdecl,由主挪用因变量举行参数压栈而且回复仓库。 底下看一下:地方ebp-8和ebp-4是什么? 在vc的view下选debug windows,而后选registers,表露存放器变量值,而后在选debug windows底下的memory,输出ebp-8的值和ebp-4的值(或径直输出ebp-8和-4),看一下这两个地方本质保存的是什么值,本质上是变量 n 的地方(ebp-8),m的地方(ebp-4),由此不妨看出:在主挪用因变量中举行实参的压栈而且程序是从右到左。其余,因为实参是相映的变量的援用,也表明本质上援用传播的是变量的地方(一致南针)。 归纳:在c或c++谈话挪用中默许的因变量化装_cdecl,由主挪用因变量举行参数压栈而且回复仓库,实参的压栈程序是从右到左,结果由降调因变量举行仓库回复。因为主挪用因变量处置仓库,以是不妨实行变参因变量。其余,定名化装本领是在因变量前加一个下划线(_). 2. winapi (本质上即是pascal,callback,_stdcall) 例子: void winapi input( int &m,int &n); 看一下相映挪用的汇编代码: 00401068 lea eax,[ebp-8] 0040106b push eax 0040106c lea ecx,[ebp-4] 0040106f push ecx 00401070 call @ilt+5(input) (0040100a) 从之上挪用input因变量的进程不妨看出:在挪用此因变量之前,开始压栈ebp-8,而后压栈ebp-4,而后挪用因变量input,在挪用因变量input之后,没有相映的仓库回复处事(为其它的因变量挪用,以是我没有列出) 底下再列出input因变量自己的汇编代码:(本质此因变量不大,但做汇编例子仍旧大了些,大师不妨只看前和后,中央代码与此例子无干)39: void winapi input( int &m,int &n)40: {00401110 push ebp00401111 mov ebp,esp00401113 sub esp,48h00401116 push ebx00401117 push esi00401118 push edi00401119 lea edi,[ebp-48h]0040111c mov ecx,12h00401121 mov eax,0cccccccch00401126 rep stos dword ptr [edi]41: int s,i;42:43: while(1)00401128 mov eax,10040112d test eax,eax0040112f je input+0c1h (004011d1)44: {45: printf("\nplease input the first number m:");00401135 push offset string "\nplease input the first number m"... (004260b8)0040113a call printf (00401530)0040113f add esp,446: scanf("%d",&m);00401142 mov ecx,dword ptr [ebp+8]00401145 push ecx00401146 push offset string "%d" (004260b4)0040114b call scanf (004015f0)00401150 add esp,847:48: if ( m<1 ) continue;00401153 mov edx,dword ptr [ebp+8]00401156 cmp dword ptr [edx],100401159 jge input+4dh (0040115d)0040115b jmp input+18h (00401128)49: printf("\nplease input the first number n:");0040115d push offset string "\nplease input the first number n"... (0042608c)00401162 call printf (00401530)00401167 add esp,450: scanf("%d",&n);0040116a mov eax,dword ptr [ebp+0ch]0040116d push eax0040116e push offset string "%d" (004260b4)00401173 call scanf (004015f0)00401178 add esp,851:52: if ( n<1 ) continue;0040117b mov ecx,dword ptr [ebp+0ch]0040117e cmp dword ptr [ecx],100401181 jge input+75h (00401185)00401183 jmp input+18h (00401128)53:54: for(i=1,s=0;i<=n;i++)00401185 mov dword ptr [ebp-8],10040118c mov dword ptr [ebp-4],000401193 jmp input+8eh (0040119e)00401195 mov edx,dword ptr [ebp-8]00401198 add edx,10040119b mov dword ptr [ebp-8],edx0040119e mov eax,dword ptr [ebp+0ch]004011a1 mov ecx,dword ptr [ebp-8]004011a4 cmp ecx,dword ptr [eax]004011a6 jg input+0a3h (004011b3)55: s=s+i;004011a8 mov edx,dword ptr [ebp-4]004011ab add edx,dword ptr [ebp-8]004011ae mov dword ptr [ebp-4],edx004011b1 jmp input+85h (00401195)56: if ( m >= s )004011b3 mov eax,dword ptr [ebp+8]004011b6 mov ecx,dword ptr [eax]004011b8 cmp ecx,dword ptr [ebp-4]004011bb jl input+0afh (004011bf)57: break;004011bd jmp input+0c1h (004011d1)58: else59: printf(" m < n*(n+1)/2,please input again!\n");004011bf push offset string " m < n*(n+1)/2,please input agai"... (00426060)004011c4 call printf (00401530)004011c9 add esp,460: }004011cc jmp input+18h (00401128)61:62: }004011d1 pop edi004011d2 pop esi004011d3 pop ebx004011d4 add esp,48h004011d7 cmp ebp,esp004011d9 call __chkesp (004015b0)004011de mov esp,ebp004011e0 pop ebp004011e1 ret 8结果,咱们看到在因变量结束局部,有ret 8,鲜明是回复仓库,因为在32位c++中,变量地方为4个字节(int也为4个字节),以是弹栈两个地方即8个字节。 由此不妨看出:在主挪用因变量中控制压栈,在被挪用因变量中控制回复仓库。所以不许实行变参因变量,由于被调因变量不许事前领会弹栈数目,但在降调因变量中是不妨做到的,由于参数数目由降调因变量决定。 底下再看一下,ebp-8和ebp-4这两个地方本质保存的是什么值,ebp-8地方保存的是n 的值,ebp -4保存的是m的值。证明也是从右到左压栈,举行参数传播。 归纳:在主挪用因变量中控制压栈,在被挪用因变量中控制弹出仓库中的参数,而且控制回复仓库。所以不许实行变参因变量,参数传播是从右到左。其余,定名化装本领是在因变量前加一个下划线(_),在因变量名后有标记(@),在@反面跟不上参数列表中的参数所占字节数(10进制),如:void input(int &m,int &n),被化装成:_input@8 对于大普遍api因变量以及窗口动静处置因变量皆用 callback ,以是挪用前,降调因变量会先压栈,而后api因变量本人回复仓库。 如: push edx push edi push eax push ebx call getdlgitemtexta 你不妨想一下,这几个存放器中存的都是什么?参考:msdn例子为在vc6.0下debug形式下的win32 console反汇编代码。