仮想関数テーブルを出力するには?
gccのオプションには、-fdump-class-hierarchyというオプションがあり
各クラスの階層構造と仮想関数テーブルのレイアウトの表現をファイルに ダンプします。ファイル名は、ソースファイル名に .class を追加して作成されます。 -options 形式が使用されるなら、options は -fdump-tree
と解説されています。
class Hoge { public: virtual void func(){} }; int main() { return 0; }
をビルドすると、main.cpp.t01.class
というファイルが作成され、中に
Vtable for Hoge Hoge::_ZTV4Hoge: 3u entries 0 (int (*)(...))0 4 (int (*)(...))(& _ZTI4Hoge) 8 Hoge::func Class Hoge size=4 align=4 base size=4 base align=4 Hoge (0x19af380) 0 nearly-empty vptr=((& Hoge::_ZTV4Hoge) + 8u)
という情報が出力されています。
どうやら、Vtableの2番目にfuncのアドレスが入っているようです。
ではこれの取り出し方を
#include <iostream> class Hoge { public: Hoge() { } virtual void func(){ std::cout << "func" << std::endl; } }; typedef void (*Func)(); int main( void ) { Hoge h; int *pAddr = (int *)&h; // h Address int *vptr = (int *)*pAddr; // vptr printf( "Addr : %X\n" , *( vptr - 0 ) ); // 8 Hoge::func printf( "Addr : %X\n" , *( vptr - 1 ) ); // 4 (int (*)(...))(& _ZTI4Hoge) printf( "Addr : %X\n" , *( vptr - 2 ) ); // 0 (int (*)(...))0 Func hoge = (Func)vptr[0]; hoge(); //=> func return 0; }
hのアドレスの先頭には、vptrが格納されているので、
hのアドレスの指す中身をint*でキャストして、vptrを取り出します。
vptrは、vtable + 8uの値がセットされているので、
先頭に格納されている中身を目的の関数ポインタでキャストしてコールすれば、
仮想関数を呼ぶ事が出来ます。