2011-10-08 16 views
11

pimpl idiomは、ABIとの互換性を損なうことなく、ライブラリに依存するすべてのコードを再コンパイルすることなく、動的にリンクされたライブラリのコードを変更できるようにするためによく使用されます。プライベートメンバー変数を追加するとC++ ABIとの互換性が損なわれますか?

ほとんどのexplanations新しいプライベートメンバー変数を追加すると、そのクラスのパブリックメンバーとプライベートメンバーのオフセットが変更されることに言及します。それは私には意味がある。私が理解できないことは、実際にはこれが実際に依存するライブラリをどのように破壊するかということです。

私はELFファイルと動的リンクの実際の動作について多くの読書をしましたが、共有ライブラリのクラスサイズを変更することでどのように物事が損なわれるかはまだ分かりません。

など。ここでは、テストアプリケーション(a.outが)私は、テスト共有ライブラリ(libInterface.so)からコード(Interface::some_method)を使用して書いている:

[email protected]:~/pimpl$ objdump -d -j .text a.out 
08048874 <main>: 
... 
8048891: e8 b2 fe ff ff   call 8048748 <[email protected]> 

some_methodへの呼び出しは、手続きリンクテーブル(PLT)を使用しています。

その後アドレス0x804a01cが含まれるグローバルオフセットテーブル(GOT)に移行
[email protected]:~/pimpl$ objdump -d -j .plt a.out 

08048748 <[email protected]>: 
8048748: ff 25 1c a0 04 08  jmp *0x804a01c 
804874e: 68 38 00 00 00   push $0x38 
8048753: e9 70 ff ff ff   jmp 80486c8 <_init+0x30> 

[email protected]:~/pimpl$ readelf -x 24 a.out 

Hex dump of section '.got.plt': 
    0x08049ff4 089f0408 00000000 00000000 de860408 ................ 
    0x0804a004 ee860408 fe860408 0e870408 1e870408 ................ 
    0x0804a014 2e870408 3e870408 4e870408 5e870408 ....>...N...^... 
    0x0804a024 6e870408 7e870408 8e870408 9e870408 n...~........... 
    0x0804a034 ae870408       .... 

そしてこれがある場合、動的リンカーWO LD_LIBRARY_PATHの共有ライブラリに含まれるすべてのシンボルを調べ、libInterface.so内にあるInterface::some_methodを見つけて、そのコードをGOTにロードします。そのため、後でsome_methodを呼び出すと、GOTのコードは実際に共有からのコードセグメントになりますとしょうかん。

またはこれらの行に沿ったもの。

しかし、私はまだ共有libのクラスサイズまたはそのメソッドのオフセットがどのように再生されるのか分かりません。私が知る限り、上記のステップはクラスのサイズには無関心です。ライブラリ内のメソッドのシンボルだけがa.outに含まれているようです。クラスのサイズの変更は、リンカがコードをGOTにロードするときに実行時に解決する必要がありますか?

私はここで何が欠けていますか?

答えて

15

主な問題は、クラスの新しいインスタンス(スタックまたはnew経由)を割り当てると、呼び出しコードがオブジェクトのサイズを知る必要があることです。後で(プライベートメンバーを追加して)オブジェクトのサイズを変更すると、必要なサイズが増えます。あなたの発信者はまだ古いサイズを使用しています。したがって、オブジェクトを保持するのに十分な領域を割り当てられなくなり、オブジェクトのコンストラクタは十分な領域があるとみなしてスタック(またはヒープ)を破棄します。

さらに、インラインメンバー関数がある場合、そのコード(メンバー変数へのオフセットを含む)が呼び出しコードにインライン展開されることがあります。末尾以外にプライベートメンバーを追加すると、これらのオフセットが正しくなくなり、メモリ破損につながります(メモ:最後に追加しても、サイズの不一致は依然として問題です)。

+0

Aha!とった。実際、Interfaceのctorが呼び出される前に逆アセンブリを少し見上げると、オブジェクトのスペース(この場合は4bytes)を割り当てることができます。 – adg

関連する問題