簡體   English   中英

鏈接可執行文件中的共享庫與另一個共享庫

[英]Linking a shared library in executable vs. another shared lib

tl; dr

如果庫是通過可執行文件或其他共享庫鏈接的,則linux加載和鏈接共享庫的方式是否有所不同?

背景

假設我有一個共享庫(例如libA.so ),其中包含一個帶有靜態std::map和一組單例類。 每個單例類都可以訪問地圖,並將自身的實例靜態添加到地圖。

有兩種情況:

  1. 我在可執行文件中使用共享庫( libA.so )從全局映射中讀取所有已注冊的類。
  2. 我在另一個共享庫( libB.so )中使用共享庫( libA.so ),並在可執行文件中使用這個新庫。 在這種情況下, libB.so使用libA.so的映射為可執行文件提供某些功能(例如外觀)。

問題

如果我在可執行文件中使用(即鏈接)此共享庫(場景1),則上述映射包含單例類的列表, 但是 ,如果我在另一個共享庫中使用此庫,然后在可執行文件中使用新的共享庫(場景1) 2),地圖似乎是空的。

在這兩種情況下,我似乎都無法理解鏈接器如何處理共享庫。

更新資料

因為它變成了libB.so不鏈接到libA.so正確,即使使用的明確指示-lA的標志g++ 雖然我不能看到libA.so通過鏈接libB.so使用lddpmapobjdump ,我使用的類時,沒有得到運行時錯誤libA.so 如果使用clang++運行相同的命令,則可以看到列出了所有必需的庫。

Drepper的論文“ 如何編寫共享庫”是該主題的很好參考,應該回答您的問題。

您應該確保在第二種情況下,庫僅鏈接一次(例如,使用完全相同的路徑)。 參見ld-linux(8)並使用例如LD_DEBUG等...

您可能還會strace執行以了解發生了什么。

並且您應該檢查(使用pmap或使用cat /proc/$ThePid/maps )該庫僅加載一次。

我將描述一種可能產生您所看到的行為的方案。

  1. 調用單例對象的全局構造函數,並針對地圖進行注冊。
  2. 映射的全局構造函數被調用,從而導致將映射初始化為空的數據結構。

另一種情況:

  • 如果您正在從全局構造函數的libB.so中讀取映射,則可能在任何對象有機會注冊自身之前調用它。

通常,不能保證從不同的翻譯單元(當然也不能從不同的共享庫)執行全局構造函數的順序。

上面第一個問題的解決方案是為地圖使用單例樣式模式,以便在使用時進行初始化,而不是通過全局構造函數進行初始化。

TheMap & GlobalMap () {
    static TheMap instance;
    return instance;
}

上面第二個問題的解決方案是禁止從全局構造函數訪問全局地圖。 也就是說,將libB.so所有全局構造函數更改為在使用時進行初始化,而不是在全局構造函數中進行初始化。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM