9

2 つのサードパーティ ライブラリ ( libfoo.solibbar.so )を必要とする C++ プロジェクトに取り組んでいます。私のオペレーティングシステムは Linux です。

libfoo.soは libpng14.so.14 (1.4.8) (EDIT 1)に動的にリンクされています

libbar.soは、libpng libpng 1.2.8 (EDIT 1)の不明なバージョンに静的にリンクされているようです

私が「そうらしい」と言ったのは、次の理由による。

  • ldd libbar.sopngについては何も表示されません
  • nm -D libbar.so | grep png_read_png「004f41b0 T png_read_png」と言います
  • less libbar.so | grep png_read_png「4577: 004f41b0 738 FUNC GLOBAL DEFAULT 10 png_read_png」と言う

プログラムを開始すると、中止されます:

terminate called after throwing an instance of 'char const*'

これは gdb バックトレースです:

#0  0xb7ffd424 in __kernel_vsyscall ()
#1  0xb5e776a1 in raise () from /lib/libc.so.6
#2  0xb5e78de2 in abort () from /lib/libc.so.6
#3  0xb60a997f in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#4  0xb60a78a5 in ?? () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#5  0xb60a78e2 in std::terminate() () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#6  0xb60a7a21 in __cxa_throw () from /usr/lib/gcc/i686-pc-linux-gnu/4.4.5/libstdc++.so.6
#7  0xb5abf76d in ?? () from /usr/lib/libfreeimage.so.3
#8  0xb6fb9346 in png_error () from lib/libfsdk.so
#9  0xb6fa2a59 in png_create_read_struct_2 () from lib/libfsdk.so
#10 0xb6fa2b7a in png_create_read_struct () from lib/libfsdk.so
#11 0xb5abfa44 in ?? () from /usr/lib/libfoo.so
#12 0xb5aa766b in FreeImage_LoadFromHandle () from /usr/lib/libfreeimage.so.3
#13 0xb5aa59f6 in FreeImage_LoadFromMemory () from /usr/lib/libfreeimage.so.3
#14 0xb68a94a5 in Foo::Image::load (this=0xb4eff560, input=...)

ご覧のとおり、libfoo.so に属するFoo::Image::loadで例外がスローされます。

libbar.soを使用するコードの一部を無効にし、それへのリンクを削除すると、Foo::Image::loadは例外をスローせず、正常に動作します。

したがって、シンボルテーブルのあいまいさが原因である可能性があると思います。どうすれば修正できますか?

編集1

png_access_version_number()

  • libbar.so がリンクされている場合は、バージョン 1.2.8をpng_access_version_number()返します。10208
  • libbar.so がリンクされていない場合は、バージョン 1.4.8をpng_access_version_number()返します。10408
4

1 に答える 1

5

どちらのライブラリも再構築できず、シンボルの競合によりライブラリが同じ「動的リンカー名前空間」に存在することを許可できないため、唯一の選択肢はそれらを分離することです。

dlopen("lib*.so", RTLD_LOCAL)ライブラリに直接リンクするのではなく、(どちらかまたは両方のライブラリに対して) を使用することで、それを実現できます。

たとえば、いくつかのシンボルのみが必要な場合、これは実行可能です。関数を直接呼び出す代わりに、libfoo.so単純に使用できます。dlsym

両方のライブラリに「多すぎる」依存関係がある場合、他の解決策は「インターポーザー」ライブラリを構築することです。を挿入したいとしましょう。そこから, , ...libbar.soが必要です。bar1()bar2()bar1000()

次のようなソース ファイルを記述 (または単純な Perl スクリプトで生成) します。

static void *handle;
void *bar1()
{
   static void* (*pfn)(void *arg1, void *arg2, void *arg3, ..., argN);
   if (pfn == NULL) {
      if (handle == NULL)
        handle = dlopen("libbar.so", RTLD_LOCAL|RTLD_LAZY);
      pfn = dlsym(handle, "bar1");
   }
   return (*pfn)(arg1, arg2, ..., argN);
}
... repeat for all other libbar functions you depend on

次に、このソースをコンパイルしてlibbar_interposer.soリンクし、アプリケーションをリンクします (これはC++、名前マングリングのために機能しません。plain- の場合のみですC)。ほら、アプリケーションのソースは変更されず、まだ分離されlibbar.soているため、そのシンボルはアプリケーションの残りの部分から見えず、特に のシンボルと競合しませんlibpng

于 2011-12-18T04:24:00.163 に答える