15

pimplイディオムは、ABIの互換性を損なうことなく、またライブラリに依存するすべてのコードを再コンパイルすることなく、ダイナミックリンクライブラリのコードを変更できるようにするために一般的に使用されます。

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

ELFファイルと動的リンクが実際にどのように機能するかについて多くのことを読みましたが、共有ライブラリのクラスサイズを変更すると問題が発生することはまだわかりません。

Interface::some_methodたとえば、テスト共有ライブラリ(libInterface.so)のコード()を使用するテストアプリケーション(a.out)を次に示します。

aguthrie@ana:~/pimpl$ objdump -d -j .text a.out 
08048874 <main>:
...
 8048891:   e8 b2 fe ff ff          call   8048748 <_ZN9Interface11some_methodEv@plt>

some_method手続き型リンケージテーブル(PLT)を使用するための呼び出し:

aguthrie@ana:~/pimpl$ objdump -d -j .plt a.out 

08048748 <_ZN9Interface11some_methodEv@plt>:
 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>

その後、アドレス0x804a01cが含まれているグローバルオフセットテーブル(GOT)に移動します。

aguthrie@ana:~/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                            ....

そして、これはダイナミックリンカが魔法をかけ、LD_LIBRARY_PATHの共有ライブラリに含まれるすべてのシンボルInterface::some_methodを調べ、libInterface.soで見つけ、そのコードをGOTにロードする場所です。その後の呼び出しsome_methodで、GOTのコードは実際には共有ライブラリのコードセグメント。

またはそれらの線に沿った何か。

しかし、上記のことを考えると、共有ライブラリのクラスサイズまたはそのメソッドオフセットがここでどのように機能するのかはまだわかりません。私の知る限り、上記の手順はクラスのサイズに依存しません。ライブラリ内のメソッドのシンボル名のみがa.outに含まれているようです。クラスサイズの変更は、リンカーがコードをGOTにロードするときに、実行時に解決する必要があります。

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

4

1 に答える 1

19

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

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

于 2011-10-08T19:35:16.620 に答える