我有一個跨平臺的C++應用程序,它被分成幾個共享庫並從插件共享庫中加載附加功能。插件庫應該是自包含的,並且可以獨立運行,而無需知道或依賴於調用應用程序。具有重複符號的C++插件庫中的Segfault
其中一個插件包含從主應用程序複製的代碼,因此包含與引擎中的符號名稱重複的符號名稱。 (是的,我知道這通常是一個禁忌,但是在編寫插件時引擎是一個單一的二進制文件,無法共享庫。)在Windows上,一切運行良好。在Linux上,我們得到了段錯誤。通過查看錯誤的堆棧跟蹤,它在調用重複類名稱中的函數時發生在插件中。它似乎是引擎和插件共享代碼版本稍有不同的結果(某些類功能在插件中已被註釋掉)。就好像這個插件獲得它的符號運行時間鏈接到引擎而不是它自己的。我們通過將dlopen
的參數更改爲dlopen(pFilepath, RTLD_LAZY | RTLD_LOCAL)
來「解決」了問題。
但是,當我們重新編寫引擎以拆分爲共享庫時(爲了在插件中重用的最終目的),我們再次獲取了段錯誤。並看着堆棧跟蹤,它從引擎 - >插件 - >引擎。
是否有一種方法可以指定運行時鏈接程序不將該插件的符號映射到引擎(特別是如果它們是在插件中定義的)?
謝謝! 馬特
編輯2009-12-3
我第一次嘗試包插件的代碼在它自己的命名空間。這不起作用,因爲它與鏈接到引擎的庫靜態鏈接。靜態庫的版本不同,所以段錯誤!
然後我改變了引擎的構建,它的庫被靜態鏈接。當我運行它時,我不再有這個問題。所以看起來這是導出共享庫符號,然後在打開時動態重定位到插件的結果。但是,當引擎的所有代碼都在單個可執行文件中時,它不會導出它的符號(所以它不會嘗試將插件的符號重定位到引擎中)。
儘管我仍然有一個問題,因爲有一個並行版本的程序(使用Open-MPI),並且仍然收到段錯誤。看起來它仍在導出引擎的符號並重新定位插件。這可能與Open-MPI如何執行應用程序有關。
是否有任何可用於插件共享庫的鏈接器標誌,它會告訴它不要在運行時動態重定位這些符號?或者隱藏它的符號,以免重新定位?我試過-s
(「省略所有符號信息」),但顯然沒有改變動態符號(使用nm -D <plugin>
進行檢查)。
這些符號是全局變量還是函數名?你可以對代碼做一些小改動嗎? – 2009-11-30 17:28:06
它們是類和它們的成員函數。從引擎代碼庫中使用了36個文件,因此我不想修改每個類名稱或文件。雖然最終的目標是重寫插件,但由於時間限制和代碼的驗證,如果我不必這樣做,我不希望這樣做。 – CuppM 2009-11-30 17:36:14
@CuppM,例如,你有一個類「Foo」,其中有一個成員「bar」定義在2個地方?在這兩種情況下,「Foo」在相同的命名空間中?如果是這樣,這將永遠不適合你。將其中一個「Foo」移動到它自己的命名空間,生活將變得更加簡單。 – Glen 2009-11-30 17:48:39