33

How do I get the absolute address of a member function in C++? (I need this for thunking.)

Member function pointers don't work because I can't convert them to absolute addresses (void *) -- I need to know the address of the actual function in memory, not simply the address relative to the type.

Matt
  • 19,570
  • 12
  • 62
  • 104
user541686
  • 189,354
  • 112
  • 476
  • 821
  • 2
    Might be worth mentioning that this is for Visual C++ in more than just tags, save anyone who overlooks them from wasting time on the obvious answer, "you can't". – Steve Jessop Nov 14 '11 at 12:12
  • 2
    @thiton: Suppose the function that Mehrdad wants the actual location of, happens to be a virtual function. Then the base class implementation still has an entry point somewhere in the executable, but a pointer-to-member for that function will not refer to that entry point, because a call through it uses the virtual mechanism. – Steve Jessop Nov 14 '11 at 12:15
  • 1
    @thiton: It doesn't work as simple as that. Virtual functions and multiple inheritance add complexity. – MSalters Nov 14 '11 at 12:16
  • Do you mean address of a `virtual` function which stored in a vtable? – masoud Nov 14 '11 at 12:22
  • You can fool the compiler with a union. MSVC generates a small helper function to make the call. A thunk. It does void the warranty. – Hans Passant Nov 14 '11 at 12:57
  • 2
    Out of interest, _why_ do you need the address for thunking? That is: why can't you just keep the member function pointer around, since you need to keep an instance pointer to use it anyway? – Useless Nov 14 '11 at 12:57
  • @Useless: There are certain problems you can only solve with thunking. – user541686 Nov 14 '11 at 15:09
  • The answer is "Don't do this.". There is no guarantee that a pointer to a member function even fits into a `void *`. Often they are bigger than a `void *`. Write your thunking system using templates or something that will auto-generate code that does it properly. For example, if you need "C" linkage for a bunch of stuff, just write a bunch of wrapper functions that forward to the member functions and declare them to have "C" linkage. – Omnifarious Sep 25 '17 at 19:24
  • That makes no sense. Either you're going by the C standard which doesn't guarantee that a pointer to *any* function (whether member or "C" linkage) fits in a `void *`, or you're going by the implementation which can easily guarantee both. In any case, the whole point of making a thunk is to dynamically generate a unique function that can call a function with some particular arguments, so merely writing one in C code won't work. (You're also 6 years late to the party...) – user541686 Sep 25 '17 at 20:18
  • @Omnifarious: Er, I meant C++ standard. – user541686 Sep 25 '17 at 21:29
  • @Mehrdad - I wasn't suggesting that you wrap the function in a "C" linkage one and then thunk using a pointer to it. Though it's far more likely that a C function pointer will fit in a `void *` than a C++ member function pointer. I was trying to guess why you wanted to auto-generate thunk functions. If you want to do it at runtime, I guess you sort of have no choice but to do what you did. But I don't know of any implementation in which pointers to a virtual member function fit into a `void *`, especially if multiple inheritance is involved. – Omnifarious Sep 25 '17 at 21:35
  • And yes, the command is late. I stumbled across this searching for why I couldn't do `&(this->func)`. – Omnifarious Sep 25 '17 at 21:37
  • 1
    @Omnifarious: I think you may have misunderstood the question then? Because I'm *not* trying to "fit" the pointer in a `void *`. Rather, I'm trying to *get the memory address of a member function*. It doesn't matter whether we're talking about a `C` function or about the override of some virtual diamond multiple virtual inheritance function (or whatever). There is still only 1 function and it must begin somewhere in memory, which can be represented by a `void *`. All the other headaches that are packed with a traditional member function pointer are for dynamic dispatch, which I don't need. – user541686 Sep 25 '17 at 21:46
  • @Mehrdad - Yes, I sort of did. My answer would've been to tell you to grab it by the mangled name using the symbol lookup features of Microsoft's DLLs. :-) – Omnifarious Sep 25 '17 at 21:55
  • @Omnifarious: that wouldn't work unless the function was exported... And it would also break silently as soon as the function name changes. Neither constraint is desirable. – user541686 Sep 25 '17 at 22:00

4 Answers4

31

There exists a syntax to get the address of the member function in MSVC (starting from MSVC 2005 IMHO). But it's pretty tricky. Moreover, the obtained pointer is impossible to cast to other pointer type by conventional means. Though there exists a way to do this nevertheless.

Here's the example:

// class declaration
class MyClass
{
public:
    void Func();
    void Func(int a, int b);
};

// get the pointer to the member function
void (__thiscall MyClass::* pFunc)(int, int) = &MyClass::Func;

// naive pointer cast
void* pPtr = (void*) pFunc; // oops! this doesn't compile!

// another try
void* pPtr = reinterpret_cast<void*>(pFunc); // Damn! Still doesn't compile (why?!)

// tricky cast
void* pPtr = (void*&) pFunc; // this works

The fact that conventional cast doesn't work, even with reinterpret_cast probably means that MS doesn't recommend this casting very strongly.

Nevertheless you may do this. Of course this is all implementation-dependent, you must know the appropriate calling convention to do the thunking + have appropriate assembler skills.

valdo
  • 11,718
  • 1
  • 34
  • 59
  • 3
    What you're seeing is implementation-dependent behavior and is nonportable. This technique may stop working at any time. As for the "why?" it's because member function pointers are not function pointers. They are weird complicated things. – Raymond Chen Nov 14 '11 at 14:22
  • 3
    @Raymond Chen: of course the is "implementation-dependent" and "nonportable". And I mentioned that. But this doesn't necessarily mean this should **never** be done. Do this at will, just be aware of consequences. – valdo Nov 14 '11 at 14:33
  • 5
    You may be surprised what happens if `Func` is a virtual function. – Raymond Chen Nov 14 '11 at 14:56
  • Oh damn, that's really clever. Thanks. – user541686 Nov 14 '11 at 15:08
  • 3
    I'm not sure whether this line `void* pPtr = (void*&) pFunc;` is portable or not but works in gcc and msvs. I most interested in knowing why `(void*&) pFunc;` but `(void*) pFunc;` doesn't works? . both are almost same thing except you add the lvalue ref. Can you explain why one works and other doesn't? – Mr.Anubis Apr 07 '12 at 09:55
  • @Soul Reaper: after adding the reference - we actually don't cast a pointer to another type. Instead we cast a variable that is a pointer to something - into a variable that is a pointer to something else. And this works, as discovered. – valdo Apr 07 '12 at 20:05
  • I would never approve of code like that in a code review. It may be clever but it's not maintainable. – C Johnson Apr 10 '12 at 23:06
  • 2
    7 years in advance and it still works... (On visual studio 2019) – L3n Aug 12 '19 at 01:32
  • Works even if member function is variadic: `class C { void func(const char* format, ...) {} };` ! – 4LegsDrivenCat Mar 15 '20 at 15:47
  • how do you call the member function after you got it, how to pass "this" to the function – worldterminator Sep 02 '20 at 07:45
  • @worldterminator you don't, you do something like (inst->*func)(args...) – Tab Jan 04 '21 at 15:28
5

try this. should let you cast anything to anything :)

template<typename OUT, typename IN>
OUT ForceCast( IN in )
{
    union
    {
        IN  in;
        OUT out;
    }
    u = { in };

    return u.out;
};

then

void* member_address = ForceCast<void*>(&SomeClass::SomeMethod);
HaPpY
  • 61
  • 2
  • 3
  • Just for the record this is undefined behavior. This uses type-punning which is only defined for casting to char* – Stephen Eckels Jul 09 '17 at 23:21
  • 1
    @StephenEckels: I think *any* answer to this question would be undefined behavior by the C++ standard (which is fine because the question is implementation-specific). – user541686 Sep 25 '17 at 21:28
4

By default, C++ member functions use the __thiscall calling convention. In order to Detour a member function, both the trampoline and the detour must have exactly the same calling convention as the target function. Unfortunately, the VC compiler does not support a __thiscall, so the only way to create legal detour and trampoline functions is by making them class members of a "detour" class.

In addition, C++ does not support converting a pointer to a member function to an arbitrary pointer. To get a raw pointer, the address of the member function must be moved into a temporrary member-function pointer, then passed by taking it's address, then de-referencing it. Fortunately, the compiler will optimize the code to remove the extra pointer operations.

from Microsoft Detour library. They deal with code injection and discuss getting address of non-virual member functions. Of course it is compiler implementation specific stuff.

you can find the library here http://research.microsoft.com/en-us/downloads/d36340fb-4d3c-4ddd-bf5b-1db25d03713d/default.aspx

kreuzerkrieg
  • 2,357
  • 21
  • 42
0

For anyone still looking for an answer of getting the memory address of the function (and not the jump), here is my solution:

UINT32 RelativityToTrampoline = *(UINT32*)((UINT64)&Func + 1);
UINT64 RealFuncAddr = (UINT64)&Func + RelativityToTrampoline + 5;