Linux下动态库的符号冲突、隐藏和强制优先使用库内符号

    本文摘自:https://blog.csdn.net/wwyyxx26/article/details/48289659


    我司为客户提供sdk包供开发使用,就是几个so文件,在so文件中我司封装了tinyxml2这个库,客户再做开发时也时候用了tinyxml2这个库,但是所使用的版本是不同的,造成了再运行时,会崩溃。应该是在程序运行时,先加载了他们的tinyxml库,然后我们的sdk在寻找tinyxml库的相关符号是找到的是他们库的符号。

    SIGSEGV : 段错误
    16 stack frames.
    ./test.out() [0x804e314]
    [0x618400]
    /lib/libc.so.6() [0x7a07b0]
    ./test.out(_ZN8tinyxml28DynArrayIPKcLi10EE14EnsureCapacityEi+0x4f) [0x8054c87]
    ./test.out(_ZN8tinyxml28DynArrayIPKcLi10EE4PushES2_+0x1e) [0x80548a4]
    ./test.out() [0x8052fac]
    ./test.out(_ZN8tinyxml210XMLPrinter10VisitEnterERKNS_10XMLElementEPKNS_12XMLAttributeE+0x21) [0x80536f1]
    ./test.out(_ZNK8tinyxml210XMLElement6AcceptEPNS_10XMLVisitorE+0x29) [0x8051fcf]
    ./libnmchelper.so(+0x61336) [0xc8a336]
    ./libnmchelper.so(+0x421df) [0xc6b1df]
    ./libnmchelper.so(+0x38fd6) [0xc61fd6]
    ./libnmchelper.so(+0x37a91) [0xc60a91]
    ./libnmchelper.so(nmc_login+0x56) [0xc7d85c]
    ./test.out() [0x804ee09]
    /lib/libc.so.6(__libc_start_main+0xe6) [0x680ce6]
    ./test.out() [0x804e0e1]
    
    *** glibc detected *** ./test.out: munmap_chunk(): invalid pointer: 0xbf9252c4 ***
    ======= Backtrace: =========
    /lib/libc.so.6[0x6dae31]
    /usr/lib/libstdc++.so.6(_ZdlPv+0x22)[0x3a26552]
    ./test.out(_ZN8tinyxml211XMLDocumentD0Ev+0x1c)[0x805229c]
    ./libnmchelper.so(_ZN8tinyxml211XMLDocument5ParseEv+0x85)[0xbdc987]
    ./libnmchelper.so(+0x626e4)[0xbdc6e4]
    ./libnmchelper.so(+0x3da59)[0xbb7a59]
    ./libnmchelper.so(+0x33fc9)[0xbadfc9]
    ./libnmchelper.so(+0x32715)[0xbac715]
    ./libnmchelper.so(nmc_login+0x65)[0xbcbc46]
    ./test.out[0x804ee09]
    /lib/libc.so.6(__libc_start_main+0xe6)[0x680ce6]
    ./test.out[0x804e0e1]


    经过一段探索,先解决方法如下:

    首先,我们要求so文件优先使用自己的库文件内的符号,因此在编译是使用-Wl,-Bsymbolic参数,这是个链接参数,会被传递给连接器ld使用,告诉so,优先使用库内符号。


    译:

    -Bsymbolic

               When creating a shared library, bind references to global symbols to the definition within the shared library, if any.  Normally, it is possible for a program linked against a shared library to override the definition within the shared library.  This  option is only meaningful on ELF platforms which support shared libraries.


    当创建一个动态库时,如果由对全局符号的引用,则把引用绑定到动态库内的定义上。通常,程序在链接到一个动态库时由可能会覆盖这个动态库的符号定义。这个选项只在支持ELF格式动态库的平台有用。


    其次,我们还要考虑我们自身库的符号先得到加载的话,不会去覆盖其他库或者程序的符号,因此这里需要将不必导出的符号进行隐藏,只导出外部需要使用的符号。

    这里我们在编译时使用-fvisibility=hidden参数来隐藏符号,但是只这样的话会把库内的所有的符号都隐藏了,包括调用者需要的函数,于是我们在需要导出的的函数和变量前加上

    __attribute__ ((visibility ("default")))属性,这样就可以使用导出的函数了。

    为了方便,宏定义如下定义

    #ifdef WIN32 //windows platform
     
    #ifdef NMC_USER_MODULE_EXPORTS
    #define NMC_API __declspec(dllexport)
    #else
    #define NMC_API __declspec(dllimport)
    #endif
     
    #ifndef NMC_CALL_TYPE
    #define NMC_CALL_TYPE  	__stdcall  
    #endif
     
    #else //linux platform
     
    #ifndef NMC_API
    #define NMC_API __attribute__ ((visibility ("default")))
    #endif
     
    #ifndef NMC_CALL_TYPE
    #define NMC_CALL_TYPE
    #endif
     
    #endif


作者:Lory | 时间:2019-04-17 16:25:10 | 分类:编程经验 | 浏览:0 | 评论:0