I am trying to print the address of a virtual member function. If I know which class implements the function I can write:
print(\"address: %p\", &A::func
Doesn't make a lot a of sense to me. If you have a normal function:
void f( int n ) {
}
then you can take its address:
f
but you cannot take the address of a function call, which is what you seem to want to do.
Pointers to member functions are not always simple memory addresses. See the table in this article showing the sizes of member function pointers on different compilers - some go up to 20 bytes.
As the article outlines a member function pointer is actually a blob of implementation-defined data to help resolve a call through the pointer. You can store and call them OK, but if you want to print them, what do you print? Best to treat it as a sequence of bytes and get its length via sizeof
.
Currently there is no standard way of doing this in C++ although the information must be available somewhere. Otherwise, how could the program call the function? However, GCC provides an extension that allows us to retrieve the address of a virtual function:
void (A::*mfp)() = &A::func;
printf("address: %p", (void*)(b->*mfp));
...assuming the member function has the prototype void func()
.
This can be pretty useful when you want to cache the address of a virtual function or use it in generated code. GCC will warn you about this construct unless you specify -Wno-pmf-conversions
. It's unlikely that it works with any other compiler.
I found a way to do this using a disassembler (https://github.com/vmt/udis86). The steps are:
Get a pointer to the virtual function via normal C++ code
Disassemble the jmp
instruction at that address
Parse the real address from the disassembled string
Here is how I did it:
// First get the raw pointer to the virtual function
auto myVirtualFuncPtr = &MyClass::myFunc;
void* myVirtualFuncPtrRaw = (void*&)myVirtualFuncPtr;
// Resolve the real function!
void* myFuncPtr = resolveVirtualFunctionAddress(myVirtualFuncPtrRaw);
...
static void* resolveVirtualFunctionAddress(void* address)
{
const int jumpInstructionSize = 5;
static ud_t ud_obj;
ud_init(&ud_obj);
ud_set_mode(&ud_obj, sizeof(void*) * 8);
ud_set_syntax(&ud_obj, UD_SYN_INTEL);
ud_set_pc(&ud_obj, (uint64_t)address);
ud_set_input_buffer(&ud_obj, (unsigned uint8_t*)address, jumpInstructionSize);
std::string jmpInstruction = "";
if (ud_disassemble(&ud_obj))
{
jmpInstruction += ud_insn_asm(&ud_obj);
}
// TODO: Implement startsWith and leftTrim yourself
if (startsWith(jmpInstruction, "jmp "))
{
std::string jumpAddressStr = leftTrim(jmpInstruction, "jmp ");
return hexToPointer(jumpAddressStr);
}
// If the jmp instruction was not found, then we just return the original address
return address;
}
static void* hexToPointer(std::string hexString)
{
void* address;
std::stringstream ss;
ss << std::hex << hexString;
ss >> address;
return address;
}
From what I can tell in the standard, the only time you get dynamic binding is during a virtual function call. And once you've called a function, you're executing the statements within the function (i.e., you can't "stop halfway" into the call and get the address.)
I think it's impossible.