讓動態函式庫的全域變數 symbol 變為預設 local

動態函式庫 .so 中,如果宣告了一個全域變數,gcc 編譯連結後,這個全域變數 symbol 會是 global 的。換句話說,如果一個 application 也宣告了同一個變數,當 application 使用如 dlopen 的方式動態載入該 .so 後,使用這個全域變數會發生問題。

目前看到的是可能 application 會當掉,或者是資料會被兩個不同的執行緒改來改去,端看變數型態與使用情境。

解決方式最直接當然是沒必要成為 global 的全域變數,就該使用 static。但是寫程式的人可能有好幾個,也有可能原本的程式就很龐大不太想改?總之要透過一種機制讓此情形不再發生,才是比較好的。一個方式是使用 gcc 中的 --version-script 參數指定要匯出的 symbol。

在 Qt pro 檔中加入:

QMAKE_LFLAGS += -Wl,--version-script=exportmap

然後 exportmap 的格式為:

{
global: foo;
local: *;
};

foo 為要 export 的 symbol,沒寫在 global 中的就全部會變 local symbol。
可以使用 nm 來觀察一個 .so 檔在加入以上參數後,一個未初始化的全域變數其 symbol 屬性有什麼差異。我們應該會看到原本屬性是 B(global 未初始化),變成 b(local 未初始化)。

這樣子就可以確保所有 dlopen 所載入的 .so 檔中,縱使有與 application 同個全域變數,也不會發生衝突進而導致錯誤。

那 Windows 平台的 DLL 呢?因為 Windows 平台都要使用 dllexport 等關鍵字才會真正 export symbol,所以 Windows 平台沒有此問題。

留言

熱門文章