_cdecl和__stdcall修飾對比
由_cdecl和__stdcall修飾的函數在被調用的時候的差別。
兩個都是函數參數從右至左入棧,但是有細微的差別。
_cdecl修飾的函數,它的參數所佔用的堆棧是由調用函數去清空的。
__stdcall修飾的函數,它的參數所佔用的堆棧是由被調用的函數自己返回的時候清空的。
寫一個簡單的程式,查看彙編代碼進行對比。
#include "stdafx.h"</p><p>int_cdecladd1(int a, int b)<br />{<br />return a+b;<br />}<br />///////////////////////////////////////////////////////////////////////////////<br />int__stdcalladd2(int a, int b)<br />{<br />return a+b;<br />}<br />///////////////////////////////////////////////////////////////////////////////<br />int main(int argc, char* argv[])<br />{<br />int a, b, c;<br />a = 12;<br />b = 18;<br />c = add1(a, b);<br />c = add2(a, b);<br />return 0;<br />}
TITLEF:/SourceCode/VC/Test/Test.cpp<br />.386P<br />include listing.inc<br />if @Version gt 510<br />.model FLAT<br />else<br />_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'<br />_TEXTENDS<br />_DATASEGMENT DWORD USE32 PUBLIC 'DATA'<br />_DATAENDS<br />CONSTSEGMENT DWORD USE32 PUBLIC 'CONST'<br />CONSTENDS<br />_BSSSEGMENT DWORD USE32 PUBLIC 'BSS'<br />_BSSENDS<br />$$SYMBOLSSEGMENT BYTE USE32 'DEBSYM'<br />$$SYMBOLSENDS<br />$$TYPESSEGMENT BYTE USE32 'DEBTYP'<br />$$TYPESENDS<br />_TLSSEGMENT DWORD USE32 PUBLIC 'TLS'<br />_TLSENDS<br />;COMDAT ?add1@@YAHHH@Z<br />_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'<br />_TEXTENDS<br />;COMDAT ?add2@@YGHHH@Z<br />_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'<br />_TEXTENDS<br />;COMDAT _main<br />_TEXTSEGMENT PARA USE32 PUBLIC 'CODE'<br />_TEXTENDS<br />FLATGROUP _DATA, CONST, _BSS<br />ASSUMECS: FLAT, DS: FLAT, SS: FLAT<br />endif<br />PUBLIC?add1@@YAHHH@Z; add1<br />;COMDAT ?add1@@YAHHH@Z<br />_TEXTSEGMENT<br />_a$ = 8<br />_b$ = 12<br />?add1@@YAHHH@Z PROC NEAR; add1, COMDAT</p><p>; 7 : {</p><p>pushebp<br />movebp, esp<br />subesp, 64; 00000040H<br />pushebx<br />pushesi<br />pushedi<br />leaedi, DWORD PTR [ebp-64]<br />movecx, 16; 00000010H<br />moveax, -858993460; ccccccccH<br />rep stosd</p><p>; 8 : return a+b;</p><p>moveax, DWORD PTR _a$[ebp]<br />addeax, DWORD PTR _b$[ebp]</p><p>; 9 : }</p><p>popedi<br />popesi<br />popebx<br />movesp, ebp<br />popebp<br />ret0;這裡是_cdecl修飾的函數。函數執行完直接退出,並沒有釋放參數所點的堆棧<br />?add1@@YAHHH@Z ENDP; add1<br />_TEXTENDS<br />PUBLIC?add2@@YGHHH@Z; add2<br />;COMDAT ?add2@@YGHHH@Z<br />_TEXTSEGMENT<br />_a$ = 8<br />_b$ = 12<br />?add2@@YGHHH@Z PROC NEAR; add2, COMDAT</p><p>; 12 : {</p><p>pushebp<br />movebp, esp<br />subesp, 64; 00000040H<br />pushebx<br />pushesi<br />pushedi<br />leaedi, DWORD PTR [ebp-64]<br />movecx, 16; 00000010H<br />moveax, -858993460; ccccccccH<br />rep stosd</p><p>; 13 : return a+b;</p><p>moveax, DWORD PTR _a$[ebp]<br />addeax, DWORD PTR _b$[ebp]</p><p>; 14 : }</p><p>popedi<br />popesi<br />popebx<br />movesp, ebp<br />popebp<br /><span style="color: #ff0000;" mce_style="color: #ff0000;">ret8;ret 8=ret && add esp,8。這裡是__stdcall所修飾的函數,返回時清空參數所佔的堆棧空間</style><br />?add2@@YGHHH@Z ENDP; add2<br />_TEXTENDS<br />PUBLIC_main<br />EXTRN__chkesp:NEAR<br />;COMDAT _main<br />_TEXTSEGMENT<br />_a$ = -4<br />_b$ = -8<br />_c$ = -12<br />_mainPROC NEAR; COMDAT</p><p>; 17 : {</p><p>pushebp<br />movebp, esp<br />subesp, 76; 0000004cH<br />pushebx<br />pushesi<br />pushedi<br />leaedi, DWORD PTR [ebp-76]<br />movecx, 19; 00000013H<br />moveax, -858993460; ccccccccH<br />rep stosd</p><p>; 18 : int a, b, c;<br />; 19 : a = 12;</p><p>movDWORD PTR _a$[ebp], 12; 0000000cH</p><p>; 20 : b = 18;</p><p>movDWORD PTR _b$[ebp], 18; 00000012H</p><p>; 21 : c = add1(a, b);</p><p>;調用函數參數入棧<br />moveax, DWORD PTR _b$[ebp]<br />pusheax<br />movecx, DWORD PTR _a$[ebp]<br />pushecx<br />call?add1@@YAHHH@Z; add1<br />addesp, 8;_cdecl修飾的需要在調用函數結束之後,對參數所佔的堆棧空間進行清空。<br />movDWORD PTR _c$[ebp], eax</p><p>; 22 : c = add2(a, b);</p><p>movedx, DWORD PTR _b$[ebp]<br />pushedx<br />moveax, DWORD PTR _a$[ebp]<br />pusheax<br />call?add2@@YGHHH@Z; add2<br />;__stdcall修飾函數在返回的時候,參數所佔的堆棧空間已經由被調用函數返回時清空。<br />movDWORD PTR _c$[ebp], eax</p><p>; 23 : return 0;</p><p>xoreax, eax</p><p>; 24 : }</p><p>popedi<br />popesi<br />popebx<br />addesp, 76; 0000004cH<br />cmpebp, esp<br />call__chkesp<br />movesp, ebp<br />popebp<br />ret0<br />_mainENDP<br />_TEXTENDS<br />END<br />