I know this is compiler/ABI dependent, not necessarily standardized, etc. I've always assumed, from what I've read in several places (e.g. an answer here or the example in wikipedia), that a typical thing a compiler does is having a pointer to the vtable of Class at the start of an object of type Class.

I'm now debugging and instrumenting a function that receives a Class* parameter. Class has virtual functions. I want to determine if it belongs to a class that I care about. I probably also want to do other things with it, so I'm trying to get a good understanding.

I look at the disassembly in Ghidra, and I find this about the vtable of that class (paste is coming from an example I wrote, but it's equivalent in a real binary that I want to RE):

                             * vtable for DerivedClass                                    *
                             _ZTV12DerivedClass                              XREF[3]:     Entry Point(*), 
                             DerivedClass::vtable                                         operator():001039d1(*), 
        00107c70 00 00 00        ptrdiff_
                 00 00 00 
                 00 00
           00107c70 [0]                                  0h
        00107c78 88 7c 10        addr       DerivedClass::typeinfo                           = 
                 00 00 00 
                 00 00
                             PTR_ARRAY_00107c80                              XREF[2]:     operator():001039d8(*), 
        00107c80 94 42 10        addr[1]
                 00 00 00 
                 00 00
           00107c80 94 42 10 00 00  addr      DerivedClass::someVirt  [0]                               XREF[2]:     operator():001039d8(*), 
                    00 00 00                                                                                         operator():001039dc(*)  

And here is where my surprise is:

  1. I get the address of _ZTV12DerivedClass (e.g. via Frida, Module.findExportByName(null, "_ZTV12DerivedClass") or in GDB, info address _ZTV12DerivedClass).
  2. I get the address of the vtable of the object (it's 64 bits, so 8 first bytes of the object), again, in the debugger or with Frida.
  3. I compare the two, and I get that they are 16 bytes away, the size of 2 pointers: the pointer in the object instance is not to the start of the vtable, but at the start of the array of pointers to the virtual functions!

This is not Earth-shattering in order to compare the pointers, of course. Just add 16. I've seen explanations of what those first two pointers should be. But I have some doubts:

  1. Is it reliable to assume that the difference of 16 is going to be consistent in all classes in the same binary?
  2. Is this common in more compilers?
  3. Do the two positions in the table (the very start of it and the start of the array of pointers to the virtual functions) have any naming convention? I find it surprising that there is a pointer to something and it's not the start of the vtable as found on the disassembly.
  4. Could be some historical legacy? If C++ first had virtual functions but without virtual inheritance or RTTI, it might explain that those two extra pointers were added to the top to not change some other assumptions.

The Itanium C++ ABI is sometimes not very clear about what exactly is “vtable”.

In practice, the symbol such as _ZTV12DerivedClass points to the complete vtable structure, which includes the two pointer-sized slots before it (RTTI pointer and offset to top).

So, to get the start of the virtual function pointers table (what is commonly understood as “the vtable”), you have to add 16 (or 8 on 32-but platforms) to the symbol’s address.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.