Мое приложение добавляет библиотеку со статическим кодом инициализации. Все остальные библиотеки делают то же самое и загружаются нормально раньше, но эта умирает при вызове функции из другой библиотеки. Это что-то вроде:
0x12311 <-- bad address
_static_initialization_0 <-- function call
....
dlopen
Теперь вызов функции в разборке выглядит так
call _Z6MyFuncRA37_Kc@plt
Однако этот вызов завершается вызовом неверного адреса 0x12311, т. Е. Запись PLT получает неправильный адрес.
Проблема весьма вероятна в том, что рассматриваемая библиотека является сторонней, то есть поставляется в двоичной предварительно собранной форме, даже если она зависит от других библиотек. На прошлой неделе мы провели большую оптимизацию, изменили много заголовков и так далее. Функция MyFunc, неправильный PLT, находится в нашей (другой) библиотеке, которая претерпела значительные изменения в оптимизации.
Как это возможно? Точный вопрос:
Кроме того, то же самое приложение прекрасно работает при компиляции с оптимизацией -O2, что я и называю странным (двоичная библиотека одинакова в обоих случаях).
Постскриптум Ubuntu 12.04 x86_64, но приложение i386.
ОБНОВЛЕНИЕ: предложение в комментариях (по какой-то причине удалено) проверить LD_DEBUG было хорошо, в привязках LD_DEBUG = я вижу это в «сбойной» версии приложения:
10272: /media/EXT/work/build32/bin/libMyLib.so: error:
symbol lookup error: undefined symbol: omp_set_num_threads (fatal)
И тогда он прекращает связывать символы libMyLib.so, в то время как в исправной версии он продолжает связывать другие символы. Но я не понимаю, почему он продолжает выполнение и пытается загрузить родительскую библиотеку. На самом деле схема выглядит следующим образом:
libA -> libB -> libMyLib
Сбой libMyLib (как указано в выводе LD_DEBUG выше), поэтому он пропускает его, а также libB полностью (!) и продолжает связывать символы libA. В исправной версии полностью загружаются символы libMyLib, затем продолжается символы libB, а затем символы libA.
Честно говоря, для меня это выглядит как жук.
Что касается того, почему оптимизированная версия работает, я предполагаю, что метод omp_ действительно не нужен и отбрасывается оптимизацией компоновщика, таким образом, он не может не найти его во время выполнения.
Вот что я вижу в LD_DEBUG = весь журнал после того, как символ omp_ не найден для libC:
19225: symbol=omp_set_num_threads; lookup in file=/usr/lib/i386-linux-gnu/libXdmcp.so.6 [0]
19225: /media/EXT/Work/libC.so: error: symbol lookup error: undefined symbol: omp_set_num_threads (fatal)
19225:
19225: file=/media/EXT/libA.so [0]; destroying link map
19225:
19225: file=/media/EXT/libA.so [0]; dynamically loaded by /media/EXT/libX.so [0]
19225: file=/media/EXT/libA.so [0]; generating link map
19225: dynamic: 0xf2fdb764 base: 0xf2f81000 size: 0x00064a28
19225: entry: 0xf2f8ffd0 phdr: 0xf2f81034 phnum: 7
19225:
19225: checking for version `GCC_3.0' in file /lib/i386-linux-gnu/libgcc_s.so.1 [0] required by file /media/EXT/libA.so [0]
... few more checking
19225: object=/media/EXT/libA.so [0]
19225: scope 0: bin/mainapp /lib/i386-linux-gnu/libpthread.so.0 /media/EXT/libX.so ...
19225: scope 1:...
19225:
19225:
19225: relocation processing: /media/EXT/libA.so
19225: symbol=_ZTVN10__cxxabiv117__class_type_infoE; lookup in file=bin/mainapp [0]
19225: symbol=_ZTVN10__cxxabiv117__class_type_infoE; lookup in file=/lib/i386-linux-gnu/libpthread.so.0 [0]
19225: symbol=_ZTVN10__cxxabiv117__class_type_infoE; lookup in file=/media/EXT/libX.so [0]
19225: binding file /media/EXT/libA.so [0] to /media/EXT/libX.so [0]: normal symbol `_ZTVN10__cxxabiv117__class_type_infoE'
... here it continues to bind libA symbols, and after finishing that
19225:
19225:
19225: calling init: /media/EXT/libC.so
19225:
он вызывает init для неинициализированного модуля libC.so.
(Следует упомянуть, что libX.so является базовым модулем, который вызывает dlopen, а также содержит базовые методы, используемые всеми другими библиотеками.)
После уничтожения карты ссылок для libA журнал показывает, что она генерируется снова, я просто не понимаю, продолжает ли загрузчик загружать libA или начинает с нуля на этот раз, не беспокоясь о libB / libC. Ну, в любом случае он игнорирует libB / libC, пока init не будет вызван для libC.
omp_set_num_threads
относится к Поддержка OpenMP внутри GCC.
Вы, вероятно, должны пройти -fopenmp
флаг для gcc при компиляции & время ссылки (даже если вы просто dlopen
-ing библиотеки с использованием OpenMP).
Может быть, оригинальный поставщик библиотеки забыл это.
(OpenMP изменяет все поведение процесса компиляции)
Других решений пока нет …