March 24th, 2005

Pointers to virtual functions with adjustors

As a mental exercise, let’s combine two mind-numbing facts about pointers to member functions, namely that all pointers to virtual functions look the same and that pointers to member functions are very strange animals. The result may make your head explode.

Consider:

class Class1 {
 public: virtual int f() { return 1; }
};
class Class2 {
 public: virtual int g() { return 2; }
};
class Class3 : public Class1, public Class2 {
};
int (Class3::*pfn)() = Class3::g;

Here, the variable pfn consists of a code pointer and an adjustor. The code pointer gives you the virtual call stub:

 mov eax, [ecx]             ; first vtable
 jmp dword ptr [eax]        ; first function

and the adjustor is sizeof(Class1) (which in our case would be 4 on a 32-bit machine). The result, then, of compiling a function call (p->*pfn)() might look something like this:

 mov ecx, p
 lea eax, pfn
 add ecx, dword ptr [eax+4] ; adjust
 call dword ptr [eax]       ; call
-- transfers to
 mov eax, [ecx]             ; first vtable
 jmp dword ptr [eax]        ; first function
-- transfers to
 mov eax, 2                 ; return 2
 ret

Okay, I lied. It’s really not all that complicated after all. But you can probably still impress your friends with this knowledge. (If you have really geeky friends.)

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

0 comments

Discussion are closed.