linux 下 動態鏈接庫 so 之間的符號衝突

在 linux 下編寫動態鏈接庫程序,需要注意 dll 之間的符號衝突。
當我們鏈接庫需要提供給很多方集成使用,需要面對複雜的集成環境,其中一個大問題就是與第三方集成環境的符號衝突。

這些衝突有些不是通過嚴格控制名字空間解決的,比如當我們使用了一些開源庫,我們不清楚第三方集成環境有沒有這些庫,即使有是不是版本匹配,我們也不想對第三方集成環境提太多要求,這會增加集成成本。在這種情況下,我們會將這些開源庫靜態鏈接到我們的動態鏈接庫中,僅提供一個 so 文件。但是這樣做不足以避免符號衝突。

linux 下的動態鏈接機制允許多個 so 庫定義相同的符號,不會在構建時出現符號重複定義錯誤。這種衝突在運行時也不會出現錯誤警告信息,運行時鏈接過程一般使用重複定義的符號中最早出現的版本,除非明確使用 dlsym 系統 API 獲取。

因此,在運行時,到底會綁定到那個版本的符號上,是不確定的事。這種衝突是雙向的,我們的鏈接庫可能錯誤使用了第三方集成環境的符號版本,另一方面,第三方環境也可能錯誤綁定我們的鏈接庫中的開源庫的符號版本。

解決衝突的方法是將我們使用的開源庫裏面的符號隱藏起來。程序構建分爲編譯和鏈接兩步,在這兩步都有隱藏符號的方法。

在編譯階段,可以指定符號的可見屬性 __attribute__ ((visibility("hidden"))),比如:

void func() __attribute__ ((visibility("hidden")));
但是我們不可能對所有符號一個個添加可見屬性,所以 gcc 提供了 -fvisibility=hidden 編譯 flag,可以設置所有符號都隱藏。此時,需要爲應該導出的符號明確可見屬性,比如:

void export_func() __attribute__ ((visibility("default")));
在鏈接階段,可以通過 version script 文件將符號分爲 local、global 兩類。要導出的符號歸於 global 類。如我們創建文件 mylib.ver,內容爲:
{
        global:
                export_func;

        local: *;
};
在鏈接時指定 flag:“-Wl,--version-script=mylib.ver” 即可。
————————————————
版權聲明:本文爲CSDN博主「luansxx」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/luansxx/article/details/17056433

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章