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にロードするときに、実行時に解決する必要があります。
ここで何が欠けていますか?