在這文章裡面,我主要解釋class裡面的函數調用原理,首先給出測試代碼如下:
classCBase{public:voidHello(){}};int main(){CBasebase;base.Hello();}
同樣地,按照前面文章講解的方法,彙編得到以下main.asm,如下:
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01 TITLEE:\bossjue\main.cpp.686P.XMMinclude listing.inc.modelflatINCLUDELIB LIBCMTINCLUDELIB OLDNAMESPUBLIC?Hello@CBase@@QAEXXZ; CBase::HelloPUBLIC_main; Function compile flags: /Odtp_TEXTSEGMENT_base$ = -1; size = 1_mainPROC; File e:\bossjue\main.cpp; Line 7pushebpmovebp, esppushecx; Line 9leaecx, DWORD PTR _base$[ebp]call?Hello@CBase@@QAEXXZ; CBase::Hello; Line 10xoreax, eaxmovesp, ebppopebpret0_mainENDP; Function compile flags: /Odtp_TEXTENDS;COMDAT ?Hello@CBase@@QAEXXZ_TEXTSEGMENT_this$ = -4; size = 4?Hello@CBase@@QAEXXZ PROC; CBase::Hello, COMDAT; _this$ = ecx; Line 3pushebpmovebp, esppushecxmovDWORD PTR _this$[ebp], ecx; Line 4movesp, ebppopebpret0?Hello@CBase@@QAEXXZ ENDP; CBase::Hello_TEXTENDSEND
對比上面我彙編彙編的非類的函數調用,你可以看到,無非是多了一個mov ecx, this的操作(等價的代碼),其意思是把this複製給ecx,再調用函數,因此我們可以猜測,VS上的C++類函數調用是用ecx傳遞this指標(對stack沒影響哦),我們寫出如下測試代碼,可以看到成功運行:
#include <iostream>using namespace std;classCBase{public:CBase(int iValue):m_iValue(iValue){}public:voidHello(){cout<<m_iValue<<endl;}private:intm_iValue;};int main(){CBasebase(100);typedef void(CBase::*FunPtr)();FunPtrFunAddr=&CBase::Hello;__asm{leaecx, basecallFunAddr}}
但是,如果我們去掉lea ecx, base的話,會看到運行錯誤哦,說明了vs是用ecx傳遞this指標的。那麼,我們可以想,既然VS是用ecx傳遞this指標,我們就可以把類的成員函數做為Thread函數了,只是在一個適當的時候讓ecx等於this,對吧,問題是這個適當的時候是什麼時候,還有,怎麼樣讓ecx傳遞this呢?這是下一節中講的內容。