18

Say you have a C++ class like:

class Foo {
 public:
  virtual ~Foo() {}
  virtual DoSomething() = 0;
};

The C++ compiler translates a call into a vtable lookup:

Foo* foo;

// Translated by C++ to:
//   foo->vtable->DoSomething(foo);
foo->DoSomething();

Suppose I was writing a JIT compiler and I wanted to obtain the address of the DoSomething() function for a particular instance of class Foo, so I can generate code that jumps to it directly instead of doing a table lookup and an indirect branch.

My questions are:

  1. Is there any standard C++ way to do this (I'm almost sure the answer is no, but wanted to ask for the sake of completeness).

  2. Is there any remotely compiler-independent way of doing this, like a library someone has implemented that provides an API for accessing a vtable?

I'm open completely to hacks, if they will work. For example, if I created my own derived class and could determine the address of its DoSomething method, I could assume that the vtable is the first (hidden) member of Foo and search through its vtable until I find my pointer value. However, I don't know a way of getting this address: if I write &DerivedFoo::DoSomething I get a pointer-to-member, which is something totally different.

Maybe I could turn the pointer-to-member into the vtable offset. When I compile the following:

class Foo {
 public:
  virtual ~Foo() {}
  virtual void DoSomething() = 0;
};

void foo(Foo *f, void (Foo::*member)()) {
  (f->*member)();
}

On GCC/x86-64, I get this assembly output:

Disassembly of section .text:

0000000000000000 <_Z3fooP3FooMS_FvvE>:
   0:   40 f6 c6 01             test   sil,0x1
   4:   48 89 74 24 e8          mov    QWORD PTR [rsp-0x18],rsi
   9:   48 89 54 24 f0          mov    QWORD PTR [rsp-0x10],rdx
   e:   74 10                   je     20 <_Z3fooP3FooMS_FvvE+0x20>
  10:   48 01 d7                add    rdi,rdx
  13:   48 8b 07                mov    rax,QWORD PTR [rdi]
  16:   48 8b 74 30 ff          mov    rsi,QWORD PTR [rax+rsi*1-0x1]
  1b:   ff e6                   jmp    rsi
  1d:   0f 1f 00                nop    DWORD PTR [rax]
  20:   48 01 d7                add    rdi,rdx
  23:   ff e6                   jmp    rsi

I don't fully understand what's going on here, but if I could reverse-engineer this or use an ABI spec I could generate a fragment like the above for each separate platform, as a way of obtaining a pointer out of a vtable.

Brad
  • 2,261
  • 3
  • 22
  • 32
Josh Haberman
  • 4,170
  • 1
  • 22
  • 43
  • 1
    This is not really an answer, but you should read http://codesourcery.com/cxx-abi/. Ignore mentions of Itanium; GCC uses that ABI (with appropriate processor-specific tweaks) universally, and so do pretty much all other compilers for \*nix nowadays. MSVC is of course different, but probably not *that* different -- there are only so many ways to do it. – zwol Feb 24 '11 at 04:33
  • You should look into how to use debug symbols. This sort of thing is quite easy if symbols are available. I answered this question http://stackoverflow.com/questions/5740155/access-v-table-at-run-time/5740839#5740839 with references for how to access vtable pointer's, their layout, where they are derived from etc... Check out my reference to wikipedia's page on C++ RTT information, this may help you out http://en.wikipedia.org/wiki/Run-time_type_information – RandomNickName42 Apr 21 '11 at 07:21

5 Answers5

5

First, class types have a vtable. Instances of that type have a pointer to the vtable. This means that if the contents of the vtable change for a type all instances of that type are affected. But specific instance can have their vtable pointer changed.

There is no standard way to retrieve the vtable pointer from an instance because it is dependent upon the compiler's implementation. See this post for more details. However, G++ and MSVC++ seem to layout class objects as described on wikipedia. Classes can have pointers to multiple vtables. For the sake of simplicity I'll talk about classes that only have one vtable pointer.

To get the pointer of a function out of a vtable it can be done as simply as this:

int* cVtablePtr = (int*)((int*)c)[0];
void* doSomethingPtr = (void*)cVtablePtr[1];

Where c is an instance of class C for this class definition:

class A
{
public:
    virtual void A1() { cout << "A->A1" << endl; }
    virtual void DoSomething() { cout << "DoSomething" << endl; };
};

class C : public A
{
public:  
    virtual void A1() { cout << "C->A1" << endl; }
    virtual void C1() { cout << "C->C1" << endl; }
};

The class C is just a struct whose first member is the pointer to a vtable in this case.

In the case of a JIT compiler it might be possible to cache the lookup in the vtable by regenrating code.

At first the JIT compiler might produce this:

void* func_ptr = obj_instance[vtable_offest][function_offset];
func_ptr(this, param1, param2)

Now that the func_ptr is known the JIT can kill off that old code and simply hard code that function address into the compiled code:

hardcoded_func_ptr(this, param1, param2)

One thing I should note is while you can overwrite the instances vtable pointer it is not always possible to overwrite the contents of a vtable. For example, on Windows the vtable is marked as read only memory but on OS X it is read/write. So on windows trying to change the contents of the vtable will result in an Access Violation unless you change the page access with VirtualProtect.

Community
  • 1
  • 1
Evan
  • 6,151
  • 1
  • 26
  • 43
  • 1
    I'd like to add that to observe how MSVC sets up the vtable and vtable pointers, one can use the compiler option `/d1reportSingleClassLayoutX`, where `X` is the name of the class you want to check. This switch isn't officially documented, but it's mentioned in an MSDN blog and at various locations here on SO. [It also has a counterpart in `/d1reportAllClassLayout`, but I don't believe that one's mentioned anywhere on the MSDN.] – Justin Time - Reinstate Monica Jun 11 '16 at 17:52
  • why int* ? Expect something like ´void** vtbl´, such that vtable[index] is a void* and can be casted to a function pointer. – Sam Ginrich Mar 25 '22 at 14:50
4

I can think of two other solutions, rather than digging in the C++ object model.

The first (and obvious): Generic Programming (aka templates)

Don't use a base class, refactor the methods that depend on the base class so that they take the "Strategy" as a template argument. This will completely eliminate the virtual calls.

The second, less obvious, is to reverse the dependencies.

Instead of injecting the strategy in the algorithm, inject the algorithm in the strategy. This way you will have a single virtual call, at the beginning, and then it will proceed "normally". Templates can help once again here.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
2

Why do you think &DerivedFoo::DoSomething is different? Isn't this exactly what you're asking for? The way I think about it, any call to DerivedFoo::DoSomething() will call the same function, passing a different this pointer. The vtable merely distinguishes between different types derived from Foo, not instances.

unkulunkulu
  • 11,576
  • 2
  • 31
  • 49
Sean
  • 5,290
  • 2
  • 24
  • 21
  • Even if I have &DerivedFoo::DoSomething, that doesn't give me an address I can jump to, it's an offset into the vtable. I want to generate assembly language that says "jmp
    " where
    is the actual address of the function. The question is how to obtain
    .
    – Josh Haberman Feb 24 '11 at 03:31
  • I guess that's what I get for not reading carefully enough. Anyway, your post is tagged cross-platform but since it seems unlikely you'll find a truly cross-platform solution, have you seen this GCC extension? http://gcc.gnu.org/onlinedocs/gcc/Bound-member-functions.html#Bound-member-functions – Sean Feb 25 '11 at 03:31
2

This is not a direct answer, nor is it necessarily up to date, but it does go into a lot of the details and caveats you need to be aware of when trying to do something like this: http://www.codeproject.com/KB/cpp/FastDelegate.aspx

No there is not a standard C++ way of doing this. The above is similar to, but not the same as what you're asking for.

Logan Capaldo
  • 39,555
  • 5
  • 63
  • 78
  • A great article! If no one has a more definitive answer (like a link to a library that does this) I'll accept this one for sure. – Josh Haberman Feb 24 '11 at 03:40
-2

If you call derived->DoSomething(), and DoSomething() is not virtual in the derived class, the compiler should generate a straight call already.

If you call base->DoSomething(), the compiler has to check one way or another which version of DoSomething() to call, and a vtable is as efficient method as any. If you could guarantee it to always be an instance of the base class, you wouldn't need to make the method virtual in the first place.

Under select circumstances, it might make sense to do a static_cast before calling a bunch of non-virtual derived methods that are virtual in the base class, but as vtable lookups are common, accounted for, and relatively inexpensive, this definitely falls under the category of premature optimization.

Templates are another standard C++ means of reusing code without causing a vtable lookup.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
  • 4
    A JIT compiler can at runtime receive an instance of an object, and generate code specialized to calling that object. I'm not sure how you can tell me I'm prematurely optimizing when you have no idea what I'm doing. – Josh Haberman Feb 24 '11 at 03:43
  • 1
    I have a parser capable of parsing a binary serialization format at >500MB/s. The parser passes the parsed data to the client application through a set of callbacks. One of these callbacks is called for every value (every 5-10 bytes). A convenient way to provide a concrete implementation for a set of callbacks in C++ is to implement a virtual base class. A JITted version could parse 100s of megabytes. If I use plain C++ virtual function dispatch, every 5-10 bytes I have to chase two extra pointers in my critical path, and I have to use an indirect branch which may be predicted incorrectly. – Josh Haberman Feb 24 '11 at 05:55
  • @Josh, sounds like you fall under the "select circumstances" I mentioned, but there still might be a more idiomatic way than a JIT. How many different client classes are there, how many instances of each, and how frequently do they change? – Karl Bielefeldt Feb 24 '11 at 06:16
  • @Josh: In your position, I would measure. Compare the time it takes to process via the base class vs the time it takes to process by directly using one of the derived class. That'll give you the virtual pointer overhead. – Matthieu M. Feb 24 '11 at 07:20
  • @Matthieu: I measured the virtual pointer overhead at 25% in my test. When I used calls into non-virtual functions, I got 600MB/s. When I used calls into virtual functions, I got 485MB/s. And this was with just one set of callbacks, so the branch was perfectly predictable (in my real library, callbacks can delegate to each other, so the targets of the indirect branches will change and make the branch less predictable). – Josh Haberman Feb 24 '11 at 18:48