0

objdump ユーティリティと逆アセンブルされたコードを使用して、 VTABLE (対応する vptr)のアドレスを知るにはどうすればよいでしょうか。vptr は通常、オブジェクトの最初のバイトに格納されます (これを修正/編集してください)。仮想関数を使用したこの単純なコードがあります。

class base
{
public:
    int x;
    virtual void func()
    {
        //test function

    }

};

class der : public base
{
   void func()
    {
        //test function

    }

};

/*
 * 
 */
int main() {
    int s = 9;
    base b;
    der d ;
    std::cout<<"the address of Vptr is = "<<(&b+0)<<std::endl;
    std::cout<<"the value at Vptr is = "<<(int*)*(int*)((&b+0))<<std::endl;

    return 0;
}

以下はコードの出力です:

the address of Vptr is = 0x7fff86a78fe0
the value at Vptr is = **0x400c30**

以下は main 関数の一部です - コードの逆アセンブル:

base b;
  4009b4:   48 8d 45 d0             lea    -0x30(%rbp),%rax
  4009b8:   48 89 c7                mov    %rax,%rdi
  4009bb:   e8 f4 00 00 00          callq  400ab4 <_ZN4baseC1Ev>
    der d ;
  4009c0:   48 8d 45 c0             lea    -0x40(%rbp),%rax
  4009c4:   48 89 c7                mov    %rax,%rdi
  4009c7:   e8 fe 00 00 00          callq  400aca <_ZN3derC1Ev>

ここでは、_ZN4baseC1Ev がベース オブジェクトのアドレスであり、_ZN3derC1Ev が派生オブジェクトのアドレスであることを示しています。

_ZN4baseC1Ev で

0000000000400ab4 <_ZN4baseC1Ev>:
  400ab4:   55                      push   %rbp
  400ab5:   48 89 e5                mov    %rsp,%rbp
  400ab8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400abc:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400ac0:   48 c7 00 30 0c 40 00    movq   $0x400c30,(%rax)
  400ac7:   c9                      leaveq 
  400ac8:   c3                      retq   
  400ac9:   90                      nop

    0000000000400aca <_ZN3derC1Ev>:
        }


#include<iostream>
class base
{
public:
    int x;
    virtual void func()
  400a8a:   55                      push   %rbp
  400a8b:   48 89 e5                mov    %rsp,%rbp
  400a8e:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
    {
        //test function

    }
  400a92:   c9                      leaveq 
  400a93:   c3                      retq   

0000000000400a94 <_ZN3der4funcEv>:

};

class der : public base
{
   void func()
  400a94:   55                      push   %rbp
  400a95:   48 89 e5                mov    %rsp,%rbp
  400a98:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
    {
        //test function

    }
  400a9c:   c9                      leaveq 
  400a9d:   c3                      retq   

0000000000400a9e <_ZN4baseC2Ev>:
 */

#include <stdlib.h>
#include<iostream>
class base
{
  400a9e:   55                      push   %rbp
  400a9f:   48 89 e5                mov    %rsp,%rbp
  400aa2:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400aa6:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400aaa:   48 c7 00 50 0c 40 00    movq   $0x400c50,(%rax)
  400ab1:   c9                      leaveq 
  400ab2:   c3                      retq   
  400ab3:   90                      nop

0000000000400ab4 <_ZN4baseC1Ev>:
  400ab4:   55                      push   %rbp
  400ab5:   48 89 e5                mov    %rsp,%rbp
  400ab8:   48 89 7d f8             mov    %rdi,-0x8(%rbp)
  400abc:   48 8b 45 f8             mov    -0x8(%rbp),%rax
  400ac0:   48 c7 00 50 0c 40 00    movq   $0x400c50,(%rax)
  400ac7:   c9                      leaveq 
  400ac8:   c3                      retq   
  400ac9:   90                      nop

0000000000400aca <_ZN3derC1Ev>:
    }

};

objdump -S exeファイルの出力へのリンクは次のとおりです

また、objdump -t virtualfunctionsize | grep vtable はこれを与えます:

0000000000400c40  w    O .rodata    0000000000000018              vtable for base
0000000000601e00 g     O .dtors 0000000000000000              .hidden __DTOR_END__
0000000000400b00 g     F .text  0000000000000089              __libc_csu_init
0000000000400c20  w    O .rodata    0000000000000018              vtable for der

私が知りたかったのは、VTABLEアドレスとそれに対応する仮想関数がそれによって示されていることです。

  • Vptr のアドレスは = 0x7fff86a78fe0 です。これは何を表していますか - VTABLE の場所?

  • Vptr の値 = 0x400c30 - これは何を表していますか? 基本クラスの最初の仮想関数?

  • 派生クラスの仮想関数の後続のアドレスを見つけるにはどうすればよいですか?

Rgds、ソフト

4

2 に答える 2

2

Gcc は次の C++ ABI に従います: http://refspecs.linuxbase.org/cxxabi-1.83.html#vtable

gcc が生成する vtable を確認するには、"gcc -S" でコンパイルしてアセンブリ ソースを生成し、c++filt でフィルター処理します。

次の vtable が生成されていることがわかります。

    .type   vtable for base, @object
    .size   vtable for base, 24
vtable for base:
    .quad   0
    .quad   typeinfo for base
    .quad   base::func()

最初の 2 つの 8 バイト値が 0 (これは、先頭へのオフセット、ベース内の派生クラスのオフセット) であり、typeinfo へのポインターであることがわかります。次に、実際の vtable (仮想関数へのポインター) が開始されます。そして、それがデバッグ出力に表示される vptr 値です。これが +0x10 オフセットの説明です。

于 2012-05-11T11:31:01.220 に答える
1

_ZN4baseC1Evbase::base()、基本コンストラクターで_ZN3derC1Evあり、派生コンストラクターです。のようなツールを使用してc++filt、名前をデマングルすることができます。実際のオブジェクトのアドレスではありません。

ベースオブジェクトのアドレスは、b予想0x7fff86a78fe0どおり、スタック上にあるです。このコンパイラの場合、これはvptrのアドレスと同じです。これは、仮想メンバーへの関数ポインタの配列へのポインタです。

逆参照すると、基本クラスの最初の仮想関数(0x400c30)へのポインターのアドレスが取得されます。

編集:のアドレスを取得するには、もう一度逆参照する必要がありますbase::func()。次のようなものを使用します (int*)*(int*)*(int*)(&b)

于 2012-05-11T10:25:11.107 に答える