在运行时替换动态共享库

时间:2012-05-03 11:40:44

标签: c linux shared-libraries

我需要在程序的执行周期中使用不同的动态库。看dlfcn.h我认为这是可能的。我承认没有阅读很多关于动态库加载的文献。

好的,这就是我的工作 -

  • 我创建了名为`libdynamicTest.so.1`的共享库
  • 主APP打开此solib( dlopen ),获取函数指针( dlsym ),运行它然后将其关闭( dlclose 的)

到此为止,一切都很好。

  • 现在假设我用另一个libdynamicTest.so.1替换了我的libdynamicTest.so.1(一些代码差异)我看到了一个Segmentation错误。此外,我确保在 dlclose 之后和 dlopen 之前替换solib。

有人可以解释为什么这个分段错误吗?

我注意到即使我删除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

分享的代码库

编辑: - 添加日志LD_DEBUG =全部

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

2 个答案:

答案 0 :(得分:10)

来自“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>'

更新

你有几个错误:

  1. 您正在将test_agentlibdynamic.so.1 直接关联
    cc -o test_agent -L. ...-ldl build/test_agent/hello.o libdynamic.so.1

    完成此操作后,您再也无法期望此库永远卸载。

  2. 通过这样做:

    *((int *)handle) = 0;

    你实际上是在破坏动态加载程序的状态, 导致后续的dlsym给你伪造的地址,当你尝试使用它时会导致SIGSEGV

  3. 一旦你解决问题#2,你的程序将不再崩溃,尽管它仍然不会卸载库。要实际让库卸载,您还需要修复问题#1。

    如果您首先解决问题#1,那么问题#2将不再破坏动态加载程序。它会破坏堆,你可以用Valgrind轻松地观察它。

答案 1 :(得分: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%确定这是相关的,但听起来可能是这样。