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

在同客户做对接时遇到了符号冲突的问题。

我司为客户提供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


http://gcc.gnu.org/wiki/Visibility

类也可以

class __attribute__ ((visibility ("default"))) JtClassA
{
public:
    JtClassA();
    ~JtClassA();
}

一、隐藏静态库的符号
参数:-Wl,--exclude-libs,ALL

应用场景:A.so 依赖了B.a,A.so不想对外提供B.a中的接口。

解决的问题:A.so和C.so同时依赖的B.a,如果B.a中有一个全局变量,并提供了两个函数Set和Get。此时,A调用Set后再调用Get,可能会Set调用的是A中的,Get调用的是C中的,导致程序运行不符合预期。这个问题也告诉我们静态库要设计成无状态的、幂等的。

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值