Reputation: 1133
Is it possible to get the virtual address as an integer of a member function pointer?
I have tried.
void (AClass::*Test)(); Test = &AClass::TestFunc; int num = *(int*)&Test;
But all that does is get me the virtual address of a jmp to the function. I need the actual functions virtual address.
Upvotes: 6
Views: 1829
Reputation: 1713
I know this is old, but since there's no meaningful on-the-subject answer, here I go.
Some things need to be taken into account first.
Member-function calling convention in C++ is called __thiscall. This convention is almost identical to __stdcall, the only significant difference being that, before the effective call is made, ECX
is set to be the pointer this
of the object of which's method is called.
To illustrate this and answer your question at the same time, let's say that the class AClass
has a member function declared like this: int AClass::myFunction(int a, int b)
and that we have an instance of AClass
called aClassObject
.
Here's a rather hackish way to do what you initially asked for AND 'simulate' a AClass::myFunction
call on the aClassObject
once you obtain the raw pointer:
// 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);
And of course, the instance can be any instance of type AClass
.
Upvotes: 4
Reputation:
If this is what I suspect it is, just switch off incremental linking. In the mean time, you're getting the right answer.
My other suspicion is that TestFunc
may be virtual
. For virtual functions whose address is taken, VC++ fakes up a little thunk that does the vtable lookup, and gives a pointer to that thunk as the address. (This ensures the correct derived function is found when the actual object is of a more-derived type. There are other ways of doing this, but this allows such pointers to be a single pointer and simplifies the calling code, at the cost of double jump when they're called through.) Switch on assembly language output for your program, and look through the result; it should be clear enough what's going on.
Here, too, what you're getting is the correct answer, and there's no way to find out the address of the "actual" function. Indeed, a virtual function doesn't name one single actual function, it names whichever derived function is appropriate for the object in question. (If you don't like this behaviour, make the function non-virtual.)
If you REALLY need the genuine address of the actual function, you've got two options. The annoying one is to write some code to scan the thunk to find out the vtable index of the function. Then look in the vtable of the object in question to get the function.
(But note that taking the address of a non-virtual function will give you the address of the actual function to call, and not a thunk -- so you'd have to cater for this possibility as well. The types of pointers to virtual functions and pointers to non-virtual functions are the same.)
The easier one is to make a non-virtual function that contains the code for each virtual function, then have each virtual function call the non-virtual function. That gives you the same behaviour as before. And if you want to find out where the code is, take the address of the non-virtual function.
(In either case, this would be difficult to make work well, it would be annoying, and it would be rather VC++-specific -- but you could probably make it happen if you're willing to put in the effort.)
Upvotes: 0
Reputation: 22641
No, member function pointers can have a variety of sizes (from 4-16 bytes or more depending on platform, see the table in the article) and cannot reliably fit inside the space of an integer. This is because virtual functions and inheritence can cause the compiler to store several pieces of information in order to call the correct function, so in some cases there is not a simple address.
Upvotes: 4
Reputation: 19064
While I can't say definitively whether there is a portable way to do this, I generally recommend making a static wrapper function to provide this type of external access to a class method. Otherwise even if you succeeded you would be creating very tight coupling of the application to that class implementation.
Upvotes: 0