2011-08-26 52 views
4

幾天來我們正在處理非常奇怪的問題。Ld神奇地覆蓋靜態鏈接的符號

我不明白它是如何發生的 - 當第三方(MATLAB)程序使用我們的共享庫時,它會以某種方式覆蓋我們自己的一些符號(精確提升)。這些符號是靜態鏈接的(!!)本地。

這是處理 - 我們使用boost 1.47,MATLAB有提升1.40。目前,庫調用從我們的庫調用他們的boost(正則表達式)段錯誤。

所以,這裏是魔術:

  • 我們沒有庫的依賴,LDD:
 
    linux-vdso.so.1 => (0x00007fff4abff000) 
    libpthread.so.0 => /lib/libpthread.so.0 (0x00007f1a3fd65000) 
    libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f1a3fa51000) 
    libm.so.6 => /lib/libm.so.6 (0x00007f1a3f7cd000) 
    libgomp.so.1 => /usr/lib/libgomp.so.1 (0x00007f1a3f5bf000) 
    libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x00007f1a3f3a8000) 
    libc.so.6 => /lib/libc.so.6 (0x00007f1a3f024000) 
    /lib64/ld-linux-x86-64.so.2 (0x00007f1a414f9000) 
    librt.so.1 => /lib/librt.so.1 (0x00007f1a3ee1c000) 
  • 沒有CXX符號(我們的公共符號的POC下的二進制兼容性)從我們的圖書館出口,nm:
 
nm -g --defined-only libmysharedlib.so 

addr1 T OurCSymbol1 
addr2 T OurCSymbol2 
addr3 T OurCSymbol3 
... 
  • 不過,它使用了它們的提升。怎麼樣?堆棧跟蹤(路徑削減):
 
[ 0] 0x00007f21fddbb0a9 bin/libmwfl.so+00454825 fl::sysdep::linux::unwind_stack(void const**, unsigned long, unsigned long, fl::diag::thread_context const&)+000009 
[ 1] 0x00007f21fdd74111 bin/glnxa64/libmwfl.so+00164113 fl::diag::stacktrace_base::capture(fl::diag::thread_context const&, unsigned long)+000161 
[ 2] 0x00007f21fdd7d42d bin/glnxa64/libmwfl.so+00201773 
[ 3] 0x00007f21fdd7d6b4 bin/glnxa64/libmwfl.so+00202420 fl::diag::terminate_log(char const*, fl::diag::thread_context const&, bool)+000100 
[ 4] 0x00007f21fce525a7 bin/glnxa64/libmwmcr.so+00365991 
[ 5] 0x00007f21fb9eb8f0 lib/libpthread.so.0+00063728 
[ 6] 0x00007f21f3e939a9 libboost_regex.so.1.40.0+00342441 boost::re_detail::perl_matcher, std::allocator > >, boost::regex_traits > >::match_all_states()+000073 
[ 7] 0x00007f21f3eb6546 bin/glnxa64/libboost_regex.so.1.40.0+00484678 boost::re_detail::perl_matcher, std::allocator > >, boost::regex_traits > >::match_imp()+000758 
[ 8] 0x00007f21c04ad595 lib/libmysharedlib.so+04855189 bool boost::regex_match, std::allocator > >, char, boost::regex_traits > >(__gnu_cxx::__normal_iterator, __gnu_cxx::__normal_iterator, boost::match_results, std::allocator > > >&, boost::basic_regex > > const&, boost::regex_constants::_match_flags)+000245 
[ 9] 0x00007f21c04a71c7 lib/libmysharedlib.so+04829639 myfunc2()+000183 
[ 10] 0x00007f21c01b41e3 lib/libmysharedlib.so+01737187 myfunc1()+000307 

據瞭解,該MATLAB確實只有RTLD_NOW標誌dlopen的。

人們,請和我一起思考。 現在我不顧一切地解決這個問題,而只是簡單地理解精靈的行爲。

編輯: 小額外的問題:我怎麼理解,沒有特殊的鏈接器選項,linux.so庫中的符號永遠不會通過地址鏈接?所以即使靜態鏈接的本地符號在運行時解析?

回答

5

時退房-Bsymbolic選項LD

如果指定-Bsymbolic,則在創建共享對象 LD 的時間將嘗試到全局符號引用結合到定義 的共享庫。默認是推遲綁定到運行時。

這可能會更清楚一個例子。

example.o包含在 global.o定義的全局函數的引用,

$ nm example.o | grep ' U' 
    U _GLOBAL_OFFSET_TABLE_ 
    U globalfn 
$ nm global.o | grep ' T' 
00000000 T globalfn 

和兩個共享對象,normal.sosymbolic.so,被構建爲 如下:

$ cc -fPIC -c example.c 
$ cc -c global.c 
$ rm -f archive.a; ar cr archive.a global.o 
$ ld -shared -o normal.so example.o archive.a 
$ ld -Bsymbolic -shared -o symbolic.so example.o archive.a 

拆卸normal.so的代碼表示致電 globalfn實際上正在經歷過程鏈接表,並且 因此呼叫的最終目的地是在運行時確定的。

$ objdump --disassemble normal.so 
...snip... 
00000194 <example>: 
...snip... 
1a6: e8 d9 ff ff ff   call 184 <[email protected]> 
...snip... 
$ readelf -r normal.so 

Relocation section '.rel.plt' at offset 0x16c contains 1 entries: 
Offset  Info Type   Sym.Value Sym. Name 
00001244 00000207 R_386_JUMP_SLOT 000001b8 globalfn 

而在symbolic.so,呼叫總是調用的共享對象內 globalfn定義。

$ objdump --disassemble symbolic.so 
...snip... 
0000016c <shared>: 
...snip... 
17e: e8 0d 00 00 00   call 190 <globalfn> 
...snip... 
$ readelf -r symbolic.so 

There are no relocations in this file. 
+0

看起來像一個解決方案,我會檢查它))Thx。 立即問題 - 與-Bsymbolic是不是有可能重寫MATLAB符號並導致「對稱」段錯誤?作爲一個信息,我們庫中的所有提升符號都是「本地弱」。 – ALOR

+0

@ALOR'-Bsymbolic'在鏈接時完成它的工作,並且只改變 方式解析「對象內」引用。我已經擴大了我的回答 以澄清這一點。 – jkoshy

+0

您還應該考慮使用鏈接器版本腳本來完全隱藏'libmysharedlib.so'中的所有符號(特別是所有Boost符號),除了MatLab實際需要的符號。這樣做會加速程序的運行時加載*和*消除您的程序庫會影響稍後加載的某些其他程序庫的可能性。 –

3

這是處理 - 我們使用boost 1.47,MATLAB有提升1.40。目前,庫調用從我們的庫調用他們的boost(正則表達式)段錯誤。

您正在調用未定義的行爲,這是一個「醫生,當我這樣做時會感到痛苦」這種情況。 Matlab可執行文件已包含類boost::re_detail::perl_matcher<elided>的外部函數。當Matlab加載您的共享庫時,動態鏈接器會發現您的共享庫以與現有定義衝突的方式定義了完全相同的符號。未定義的行爲。

解決方案是構建一個與Matlab一起使用的庫的版本,該版本使用與Matlab相同版本的Boost。

+0

我同意。然而,問題是爲什麼在地獄裏他甚至碰到當地的符號? LD文檔相當不清楚。 如果我現在理解正確,沒有RTLD_DEEPBIND本地符號可能會被全局符號覆蓋? – ALOR

+0

是什麼讓你認爲共享庫中的這些符號是「本地」的?至少有一些不是。 –

+0

nm讓我覺得如此:)只有我們的public-C接口函數是全局的 - 庫編譯時使用了-fvisibility = hidden並且接口函數具有gcc屬性visibility = default – ALOR