試想這樣的情景,程序調用某函數A,A函數存在於兩個動態連接庫liba.so,libb.so中,而且程序執行須要連接這兩個庫,此時程序調用的A函數究竟是來自於a仍是b呢?sql
這取決於連接時的順序,好比先連接liba.so,這時候經過liba.so的導出符號表就能夠找到函數A的定義,並加入到符號表中,連接libb.so的時候,符號表中已經存在函數A,就不會再更新符號表,因此調用的始終是liba.so中的A函數ide
這裏的調用嚴重的依賴於連接庫加載的順序,可能會致使混亂;gcc的擴展中有以下屬性__attribute__ ((visibility("hidden"))),能夠用於抑制將一個函數的名稱被導出,對鏈接該庫的程序文件來講,該函數是不可見的,使用的方法以下:函數
-fvisibility=default|internal|hidden|protected
gcc的visibility是說,若是編譯的時候用了這個屬性,那麼動態庫的符號都是hidden的,除非強制聲明。
1.建立一個c源文件,內容簡單
spa
- #include<stdio.h>
- #include<stdlib.h>
- __attribute ((visibility("default"))) void not_hidden ()
- {
- printf("exported symbol\n");
- }
- void is_hidden ()
- {
- printf("hidden one\n");
- }
想要作的是,第一個函數符號能夠被導出,第二個被隱藏。
先編譯成一個動態庫,使用到屬性-fvisibility
string
- gcc -shared -o libvis.so -fvisibility=hidden vis.c
如今查看it
- # readelf -s libvis.so |grep hidden
- 7: 0000040c 20 FUNC GLOBAL DEFAULT 11 not_hidden
- 48: 00000420 20 FUNC LOCAL HIDDEN 11 is_hidden
- 51: 0000040c 20 FUNC GLOBAL DEFAULT 11 not_hidden
能夠看到,屬性確實有做用了。
如今試圖link
io
- vi main.c
- int main()
- {
- not_hidden();
- is_hidden();
- return 0;
- }
試圖編譯成一個可執行文件,連接到剛纔生成的動態庫,
編譯
- gcc -o exe main.c -L ./ -lvis
結果提示:
function
- /tmp/cckYTHcl.o: In function `main':
- main.c:(.text+0x17): undefined reference to `is_hidden'
說明了hidden確實起到做用了。class