最近,給同事定位了一個符號表的沖突問題,簡單記錄一下。
A代碼作為靜態鏈接庫,被包含進了B代碼,然后編譯成了動態鏈接庫,B.so
A代碼同時作為靜態鏈接庫,被編譯進入了main的主代碼。
main函數調用B.so里面的函數,同時B.so里面的函數調用了A代碼,結果進程異常退出了。
查看符號表,發現調用的A代碼,其實運行的是直接編譯進入main主函數的代碼,而不是B.so里面包含的A代碼。
而且比較湊巧的是,符號名稱是相同的,但是代碼邏輯卻不相同,
由於是arm的嵌入式單板,所有的空間被設置成了只讀,導致無法生成core文件,還花了幾個小時去分析。
那么,怎么避免這種情況?
1.如果我們要求so文件優先使用自己的庫文件內的符號,需要在編譯時使用-Wl,-Bsymbolic參數,這是個鏈接參數,會被傳遞給連接器ld使用,告訴so,優先使用庫內符號。
2.我們還要考慮我們自身庫的符號先得到加載的話,不會去覆蓋其他庫或者程序的符號,因此這里需要將不必導出的符號進行隱藏,只導出外部需要使用的符號。
這里我們在編譯時使用-fvisibility=hidden參數來隱藏符號,但是只這樣的話會把庫內的所有的符號都隱藏了,包括調用者需要的函數,於是我們在需要導出的的函數和變量前加上
__attribute__ ((visibility ("default")))屬性,這樣就可以使用導出的函數了。