我正在尝试打印虚拟成员函数的地址。 如果我知道哪个类实现了该函数,我可以编写:
print("address: %p", &A::func);
但是我想要做类似这样的事情:
A *b = new B();
printf("address: %p", &b->func);
printf("address: %p", &b->A::func);
然而,这并不能编译。可能有办法做到这一点吗?也许可以在运行时查找vtable中的地址?
我正在尝试打印虚拟成员函数的地址。 如果我知道哪个类实现了该函数,我可以编写:
print("address: %p", &A::func);
但是我想要做类似这样的事情:
A *b = new B();
printf("address: %p", &b->func);
printf("address: %p", &b->A::func);
然而,这并不能编译。可能有办法做到这一点吗?也许可以在运行时查找vtable中的地址?
目前在C++中没有标准的方法来做到这一点,尽管信息必须是可用的。否则,程序如何调用函数呢?然而,GCC提供了一个扩展,允许我们检索虚拟函数的地址:
void (A::*mfp)() = &A::func;
printf("address: %p", (void*)(b->*mfp));
假设成员函数的原型是 void func()
。
当你想要缓存虚函数的地址或在生成的代码中使用时,这非常有用。 GCC会警告你这种构造,除非你指定-Wno-pmf-conversions
。其他编译器很可能不支持此功能。
sizeof
获取其长度。通过普通的C++代码获取虚函数的指针
对该地址处的jmp
指令进行反汇编
从反汇编字符串中解析出真正的地址
// 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;
}
对我来说没有太多意义。如果您有一个普通函数:
void f( int n ) {
}
然后您可以获取其地址:
f
但是你不能获取函数调用的地址,这似乎是你想要做的。