Заменить динамическую общую библиотеку во время выполнения
Мне нужно использовать другую динамическую библиотеку в течение цикла выполнения программы. Глядя на dlfcn.h
, я подумал, что это возможно. Я признаюсь, что не читал много литературы по динамической загрузке библиотеки.
ОК, вот что я делаю -
- Я создал общую библиотеку под названием `libdynamicTest.so.1`
- Основной APP открывает этот solib (dlopen), получает указатель на функцию ( dlsym), запускает его, а затем закрывает ( dlclose)
Все хорошо, пока здесь.
- Теперь предположим, что я заменяю свой libdynamicTest.so.1 другим libdynamicTest.so.1 (некоторый код diff). Я вижу ошибку сегментации. Далее я убедился, что solib заменяется после dlclose и до dlopen.
Может кто-нибудь объяснить, почему эта ошибка сегментации?
Я заметил, даже если я удалю libdynamicTest.so.1, программа по-прежнему выполняется, тихо странная.
SysTrace(("opening dynamic library"));
handle = dlopen("libdynamicTest.so.1",RTLD_LAZY);
fn = dlsym (handle,"dylib_print_msg");
SysTrace(("Using dynamic library"));
if(!fn)
{
printf("unknown dylib_print_msg..!!\n");
}
else
{
(*fn)();
}
ret = dlclose(handle);
SysTrace(("closed dynamic library status = [%s]", (ret==0?"OK":"NOK")));
P.S. Я не пытаюсь изменить поведение любой существующей программы и не представлять угрозы. Я выполнял проверку выполнимости, чтобы выполнять интеграционные тесты в виде разделяемых библиотек.
изменить
Я попытался с помощью gdb, так как это была трассировка стека, когда произошла ошибка.
Program received signal SIGSEGV, Segmentation fault.
0x0000003e92408b7b in check_match.8509 () from /lib64/ld-linux-x86-64.so.2
#0 0x0000003e92408b7b in check_match.8509 ()
from /lib64/ld-linux-x86-64.so.2
#1 0x0000003e92409024 in do_lookup_x () from /lib64/ld-linux-x86-64.so.2
#2 0x0000003e92409222 in _dl_lookup_symbol_x ()
from /lib64/ld-linux-x86-64.so.2
#3 0x0000003e92908f14 in do_sym () from /lib64/libc.so.6
#4 0x0000003e93001104 in dlsym_doit () from /lib64/libdl.so.2
#5 0x0000003e9240ced6 in _dl_catch_error ()
from /lib64/ld-linux-x86-64.so.2
#6 0x0000003e9300150d in _dlerror_run () from /lib64/libdl.so.2
#7 0x0000003e930010ba in dlsym () from /lib64/libdl.so.2
изменить
база кода, совместно используемая при svn checkout http://subversion.assembla.com/svn/dynamic_libso
edit: - добавлены журналы LD_DEBUG = all
32564: binding file ./test_agent [0] to /lib64/libc.so.6 [0]: normal symbol `__libc_start_main' [GLIBC_2.2.5]
32564:
32564: initialize program: ./test_agent
32564:
32564:
32564: transferring control: ./test_agent
32564:
32564: symbol=printf; lookup in file=./test_agent [0]
32564: symbol=printf; lookup in file=/lib64/libdl.so.2 [0]
32564: symbol=printf; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: symbol=printf; lookup in file=/lib64/libc.so.6 [0]
32564: binding file ./test_agent [0] to /lib64/libc.so.6 [0]: normal symbol `printf' [GLIBC_2.2.5]
32564: symbol=putchar; lookup in file=./test_agent [0]
32564: symbol=putchar; lookup in file=/lib64/libdl.so.2 [0]
32564: symbol=putchar; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: symbol=putchar; lookup in file=/lib64/libc.so.6 [0]
32564: binding file ./test_agent [0] to /lib64/libc.so.6 [0]: normal symbol `putchar' [GLIBC_2.2.5]
-hello.c main():20 Msg : hello world ..!!
-hello.c main():24 Msg : opening dynamic library
32564: symbol=dlopen; lookup in file=./test_agent [0]
32564: symbol=dlopen; lookup in file=/lib64/libdl.so.2 [0]
32564: binding file ./test_agent [0] to /lib64/libdl.so.2 [0]: normal symbol `dlopen' [GLIBC_2.2.5]
32564: opening file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]; direct_opencount=1
32564:
32564: symbol=dlerror; lookup in file=./test_agent [0]
32564: symbol=dlerror; lookup in file=/lib64/libdl.so.2 [0]
32564: binding file ./test_agent [0] to /lib64/libdl.so.2 [0]: normal symbol `dlerror' [GLIBC_2.2.5]
-hello.c main():26 Msg : Opened dynamic library handle = [a16d9000]
32564: symbol=dlsym; lookup in file=./test_agent [0]
32564: symbol=dlsym; lookup in file=/lib64/libdl.so.2 [0]
32564: binding file ./test_agent [0] to /lib64/libdl.so.2 [0]: normal symbol `dlsym' [GLIBC_2.2.5]
32564: symbol=_dl_sym; lookup in file=./test_agent [0]
32564: symbol=_dl_sym; lookup in file=/lib64/libdl.so.2 [0]
32564: symbol=_dl_sym; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: symbol=_dl_sym; lookup in file=/lib64/libc.so.6 [0]
32564: binding file /lib64/libdl.so.2 [0] to /lib64/libc.so.6 [0]: normal symbol `_dl_sym' [GLIBC_PRIVATE]
32564: symbol=solib_print_msg; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: binding file /user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0] to /user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]: normal symbol `solib_print_msg'
-hello.c main():28 Msg : Using dynamic library
32564: symbol=printf; lookup in file=./test_agent [0]
32564: symbol=printf; lookup in file=/lib64/libdl.so.2 [0]
32564: symbol=printf; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: symbol=printf; lookup in file=/lib64/libc.so.6 [0]
32564: binding file /user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0] to /lib64/libc.so.6 [0]: normal symbol `printf' [GLIBC_2.2.5]
32564: symbol=putchar; lookup in file=./test_agent [0]
32564: symbol=putchar; lookup in file=/lib64/libdl.so.2 [0]
32564: symbol=putchar; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: symbol=putchar; lookup in file=/lib64/libc.so.6 [0]
32564: binding file /user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0] to /lib64/libc.so.6 [0]: normal symbol `putchar' [GLIBC_2.2.5]
-dynamic.c solib_print_msg():9 Msg : nice nice..!!
32564: symbol=dlclose; lookup in file=./test_agent [0]
32564: symbol=dlclose; lookup in file=/lib64/libdl.so.2 [0]
32564: binding file ./test_agent [0] to /lib64/libdl.so.2 [0]: normal symbol `dlclose' [GLIBC_2.2.5]
32564:
32564: closing file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1; direct_opencount=0
-hello.c main():40 Msg : closed dynamic library status = [OK]
-hello.c main():24 Msg : opening dynamic library
32564: opening file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]; direct_opencount=1
32564:
-hello.c main():26 Msg : Opened dynamic library handle = [0]
32564: symbol=solib_print_msg; lookup in file=/user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]
32564: binding file /user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0] to /user/skm/coding/fTest/approach/dynamic_library/gravity/contribs/libs/libdynamicTest.so.1 [0]: normal symbol `solib_print_msg'
-hello.c main():28 Msg : Using dynamic library
Segmentation fault
Ответы
Ответ 1
От "man dlclose":
The function dlclose() decrements the reference count on the dynamic
library handle handle. If the reference count drops to zero and
no other loaded libraries use symbols in it, then the dynamic library
is unloaded.
Я предполагаю, что вы работаете с , никакие другие загруженные библиотеки не используют в нем символы.
Чтобы отладить, запустите свою программу с помощью LD_DEBUG=bindings
и найдите сообщения типа:
binding file <some.so> [0] to libdynamicTest.so.1 [0]: normal symbol `<symbol>'
Update:
У вас есть несколько ошибок:
-
Вы связываете test_agent
с libdynamic.so.1
напрямую:
cc -o test_agent -L. ...-ldl build/test_agent/hello.o libdynamic.so.1
Как только вы это сделаете, вы больше не можете ожидать, что эта библиотека будет всегда выгружена.
-
Сделав это:
*((int *)handle) = 0;
вы на самом деле искажаете состояние динамического загрузчика, и это приводит к тому, что последующий dlsym
дает вам фиктивный адрес, который вызывает ваш SIGSEGV
, когда вы пытаетесь его использовать.
Как только вы исправите проблему №2, ваша программа больше не будет разбита, хотя она все равно не выгрузит библиотеку. Чтобы на самом деле получить библиотеку для разгрузки, вам также нужно исправить проблему № 1.
Если вы сначала исправите проблему №1, проблема №2 больше не испортит динамический загрузчик. Вместо этого он испортит кучу, и вы можете тривиально заметить это с Valgrind.
Ответ 2
Согласно man 8 ld.so
:
BUGS
Currently ld.so has no means of unloading and searching for com‐
patible or newer version of libraries.
Я не уверен на 100%, что это связано, но похоже, что это возможно.