Связывание библиотек с несовместимыми зависимостями - PullRequest
9 голосов
/ 16 декабря 2011

Я работаю над проектом C ++, которому нужны две сторонние библиотеки ( libfoo.so и libbar.so ).Моя операционная система Linux.

libfoo.so динамически связана с libpng14.so.14 (1.4.8) (EDIT 1)

libbar.so , кажется, статически связан с неизвестной версией libpng libpng 1.2.8 (EDIT 1)

Я говорю "кажется "потому что:

  • ldd libbar.so ничего не показывает о png
  • 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=...)

Как видите, исключение выдается в Foo :: Image :: load , которые принадлежат libfoo.so

Отключение части моего кода, которая использует libbar.so и удаление ссылок на него, Foo :: Image :: load не выдает никаких исключений и работает нормально.

Так что я думаю, это может быть связано с некоторой двусмысленностью в таблице символов.Как я могу это исправить?

РЕДАКТИРОВАТЬ 1

png_access_version_number ()

  • С libbar.so связаны,png_access_version_number() возврат 10208: версия 1.2.8
  • без libbar.so, png_access_version_number() возврат 10408: версия 1.4.8

1 Ответ

4 голосов
/ 18 декабря 2011

Поскольку вы не можете перестроить ни одну из библиотек и поскольку библиотекам не разрешено находиться в одном и том же «пространстве имен динамического компоновщика» из-за конфликтующих символов, ваш единственный выбор - изолировать их .

Этого можно добиться, используя dlopen("lib*.so", RTLD_LOCAL) (для одной или обеих библиотек) вместо прямой ссылки на них.

Это может быть осуществимо, если вам нужно всего лишь несколько символов, например, libfoo.so - вы можете просто использовать dlsym вместо прямого вызова функций.

Если у вас «слишком много» зависимостей в обеих библиотеках, ваше другое решение может заключаться в создании библиотеки «interposer». Допустим, вы хотите вставить 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++ из-за искажения имени, только для обычного - C). Вуаля, источник изменений в приложении отсутствует, и вы по-прежнему изолировали libbar.so, поэтому его символы не будут видны остальной части приложения и, в частности, не будут конфликтовать с какими-либо символами в libpng.

...