2009-11-30 22 views
7

我有一個跨平臺的C++應用程序,它被分成幾個共享庫並從插件共享庫中加載附加功能。插件庫應該是自包含的,並且可以獨立運行,而無需知道或依賴於調用應用程序。具有重複符號的C++插件庫中的Segfault

其中一個插件包含從主應用程序複製的代碼,因此包含與引擎中的符號名稱重複的符號名稱。 (是的,我知道這通常是一個禁忌,但是在編寫插件時引擎是一個單一的二進制文件,無法共享庫。)在Windows上,一切運行良好。在Linux上,我們得到了段錯誤。通過查看錯誤的堆棧跟蹤,它在調用重複類名稱中的函數時發生在插件中。它似乎是引擎和插件共享代碼版本稍有不同的結果(某些類功能在插件中已被註釋掉)。就好像這個插件獲得它的符號運行時間鏈接到引擎而不是它自己的。我們通過將dlopen的參數更改爲dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL)來「解決」了問題。

但是,當我們重新編寫引擎以拆分爲共享庫時(爲了在插件中重用的最終目的),我們再次獲取了段錯誤。並看着堆棧跟蹤,它從引擎 - >插件 - >引擎。

是否有一種方法可以指定運行時鏈接程序不將該插件的符號映射到引擎(特別是如果它們是在插件中定義的)?

謝謝! 馬特


編輯2009-12-3

我第一次嘗試包插件的代碼在它自己的命名空間。這不起作用,因爲它與鏈接到引擎的庫靜態鏈接。靜態庫的版本不同,所以段錯誤!

然後我改變了引擎的構建,它的庫被靜態鏈接。當我運行它時,我不再有這個問題。所以看起來這是導出共享庫符號,然後在打開時動態重定位到插件的結果。但是,當引擎的所有代碼都在單個可執行文件中時,它不會導出它的符號(所以它不會嘗試將插件的符號重定位到引擎中)。

儘管我仍然有一個問題,因爲有一個並行版本的程序(使用Open-MPI),並且仍然收到段錯誤。看起來它仍在導出引擎的符號並重新定位插件。這可能與Open-MPI如何執行應用程序有關。

是否有任何可用於插件共享庫的鏈接器標誌,它會告訴它不要在運行時動態重定位這些符號?或者隱藏它的符號,以免重新定位?我試過-s(「省略所有符號信息」),但顯然沒有改變動態符號(使用nm -D <plugin>進行檢查)。

+0

這些符號是全局變量還是函數名?你可以對代碼做一些小改動嗎? – 2009-11-30 17:28:06

+0

它們是類和它們的成員函數。從引擎代碼庫中使用了36個文件,因此我不想修改每個類名稱或文件。雖然最終的目標是重寫插件,但由於時間限制和代碼的驗證,如果我不必這樣做,我不希望這樣做。 – CuppM 2009-11-30 17:36:14

+0

@CuppM,例如,你有一個類「Foo」,其中有一個成員「bar」定義在2個地方?在這兩種情況下,「Foo」在相同的命名空間中?如果是這樣,這將永遠不適合你。將其中一個「Foo」移動到它自己的命名空間,生活將變得更加簡單。 – Glen 2009-11-30 17:48:39

回答

4

我想我找到了解決方案,鏈接器標記-Bsymbolic。本質上,該標誌在共享庫中添加一個標誌,以告知運行時鏈接程序先嚐試解析其內部的符號名稱。當插件與該標誌鏈接在一起時,引擎能夠在所有情況下使用插件運行(單體exe,exe w/shared libs,插件w /和w/o包裝名稱空間)。

有似乎是有警告一些批評者有關-Bsymbolic
http://www.technovelty.org/code/c/bsymbolic.html
http://software.intel.com/en-us/articles/performance-tools-for-software-developers-bsymbolic-can-cause-dangerous-side-effects/

但考慮到他們的警告,我認爲這是對我來說是正確的選擇是什麼插件的意圖。最起碼到現在。

1

我同意格倫 - 你不會真的解決這個問題,除非你修改類名,可能通過命名空間。甚至36個文件可能需要更少的時間來修改,而不是更改符號名稱來嘗試修復它。

首先確定所有需要調整名稱的類。您的鏈接器可能已經爲您列出了它們。然後,我會至少暫時更改這兩個套類的名稱(例如,從Foo到Engine :: Foo和Plugin :: Foo)。這樣你可以讓編譯器找到對有問題的類的所有引用。直到插件編譯時引用正確的新插件類名爲止。完成之後,將Engine :: classes更改回原來的名稱(除非您想永久修改引擎源,這聽起來好像沒有)。該插件現在應編譯並鏈接到正確的,唯一命名的類。

+0

雖然你對此可能是正確的。雖然這不是一個令人滿意的答案,但爲了以防萬一,我不打算回答這個問題。我將修改插件代碼以將名稱空間添加到違規位。在我能夠使用引擎的共享庫重寫它之前,由於我更改了引擎中的所有代碼,因此修改副本並不重要。 – CuppM 2009-11-30 19:08:53

0

我只是用PluginX命名空間包裝所有插件的代碼。這肯定會讓你免於這些錯誤。 無論如何,這是一個非常好的重要練習。