2010-05-28 154 views
4

是否可以將虛擬地址作爲成員函數指針的整數來獲取?成員函數指針爲整數?

我試過了。

 
void (AClass::*Test)(); 
Test = &AClass::TestFunc; 
int num = *(int*)&Test; 

但所有這一切都讓我的jmp的虛擬地址的函數。我需要實際的功能虛擬地址。

回答

0

儘管我無法確定是否有一種可移植的方式來執行此操作,但我通常建議使用靜態包裝函數爲類方法提供此類外部訪問。否則,即使成功了,您也會創建應用程序與該類實現的緊密耦合。

3

不,成員函數指針可能有a variety of sizes(從4-16字節或更多,具體取決於平臺,請參閱文章中的表格),並且不能可靠地適應整數空間。這是因爲虛擬函數和繼承可能會導致編譯器存儲多條信息以調用正確的函數,因此在某些情況下不存在簡單的地址。

0

如果這是我懷疑它,只是關閉增量鏈接。同時,你正在得到正確的答案。

我的另一個懷疑是TestFunc可能是virtual。對於獲取地址的虛擬函數,VC++虛構了一個執行vtable查找的thunk,並給出了該thunk作爲地址的指針。 (這確保了當實際的對象是派生類型更多的時候可以找到正確的派生函數,還有其他方法可以做到這一點,但是這允許這樣的指針是單個指針並且簡化了調用代碼,代價是雙倍當它們被調用時跳轉)。打開程序的彙編語言輸出,並查看結果;應該清楚發生了什麼事情。

這裏也是,你得到的是正確的答案,並且沒有辦法找到「實際」函數的地址。事實上,一個虛擬函數並沒有命名一個實際函數,它命名了哪個派生函數適合於所討論的對象。 (如果您不喜歡這種行爲,請使該功能不是虛擬的。)

如果您確實需要實際功能的真實地址,則有兩種選擇。令人討厭的是編寫一些代碼來掃描thunk以找出函數的vtable索引。然後查看相關對象的vtable以獲取該函數。 (但請注意,取一個非虛函數的地址會給你實際調用的函數的地址,而不是一個thunk--所以你也不得不迎合這種可能性。指向虛擬函數的指針和指向非虛函數的指針是相同的。)

更簡單的方法是創建一個包含每個虛函數代碼的非虛函數,然後讓每個虛函數調用非虛函數,虛擬功能。這給你和以前一樣的行爲。如果你想知道代碼在哪裏,可以使用非虛函數的地址。 (在任何一種情況下,這樣做都很難很好地工作,這會很煩人,而且會是VC++特有的 - 但如果你願意付出努力,你可能會發生這種情況)

+0

它不是虛擬的。儘管如此,它仍然是一項重要工作 – user230821 2010-05-28 13:56:35

+0

嘗試關閉增量鏈接。在這種情況下,每個外部函數都會通過一些代碼來調用它的實際地址。 (據推測,這樣可以更好地重用以前鏈接中的數據,因爲沒有更改的模塊只需要每次調用功能最多一次修復,而不是每次調用一次。) – 2010-05-29 18:14:27

4

我知道這是舊的,但因爲沒有有意義的主題答案,所以我去了。

有些事情需要首先考慮。 C++中的成員函數調用約定稱爲__thiscall。這個約定與__stdcall幾乎相同,唯一明顯的區別是,在進行有效調用之前,ECX被設置爲調用其方法的對象的指針this

爲了說明這一點,並在同一時間回答你的問題,讓我們說,該類AClass宣佈這樣一個成員函數:int AClass::myFunction(int a, int b)而且我們有一個叫做aClassObjectAClass一個實例。 這裏是做什麼您最初問及「模擬」的aClassObject一個AClass::myFunction電話,一旦你獲得原始指針相當hackish的方式:

// declare a delegate, __stdcall convention, as stated above 
typedef int (__stdcall *myFunctionDelegate)(int a, int b); 
// here's the 'hackish' solution to your question 
char myFunctionPtrString[10]; 
sprintf(myFunctionPtrString, "%d", &AClass::myFunction); 
int myFunctionPtr = atoi(myFunctionPtrString); 
// now let's call the method using our pointer and the aClassObject instance 
myFunctionDelegate myFunction = (myFunctionDelegate)myFunctionPtr; 
// before we make the call, we must put a pointer to aClassObject 
// in ECX, to finally meet the __thiscall calling convention 
int aClassObjectPtr = (int)&aClassObject; 
__asm{ 
    mov ecx, aClassObjectPtr 
} 
// make the call! 
myFunction(2, 3); 

當然並且,例如可以AClass類型的任何實例。

乾杯,

Zozel