1. 程式人生 > >linux下動態庫的符號衝突、隱藏和強制優先使用庫內符號

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