GCC擴展 __attribute__ ((visibility("hidden")))

    試想這樣的情景,程序調用某函數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

   
   
            
   
   
  1. #include<stdio.h>  
  2. #include<stdlib.h>  
  3.  
  4.  
  5. __attribute ((visibility("default"))) void not_hidden ()  
  6. {  
  7. printf("exported symbol\n");  
  8. }  
  9.  
  10. void is_hidden ()  
  11. {  
  12. printf("hidden one\n");  
  13. }  


 


想要作的是,第一個函數符號能夠被導出,第二個被隱藏。
先編譯成一個動態庫,使用到屬性-fvisibility
string

   
   
            
   
   
  1. gcc -shared -o libvis.so -fvisibility=hidden vis.c 



如今查看
it

   
   
            
   
   
  1. # readelf -s libvis.so |grep hidden  
  2. 7: 0000040c 20 FUNC GLOBAL DEFAULT 11 not_hidden  
  3. 48: 00000420 20 FUNC LOCAL HIDDEN 11 is_hidden  
  4. 51: 0000040c 20 FUNC GLOBAL DEFAULT 11 not_hidden  

能夠看到,屬性確實有做用了。

如今試圖link
io

   
   
            
   
   
  1. vi main.c  
  2. int main()  
  3. {  
  4. not_hidden();  
  5. is_hidden();  
  6. return 0;  



試圖編譯成一個可執行文件,連接到剛纔生成的動態庫,
編譯

   
   
            
   
   
  1. gcc -o exe main.c -L ./ -lvis 


結果提示:


function

   
   
            
   
   
  1. /tmp/cckYTHcl.o: In function `main':  
  2. main.c:(.text+0x17): undefined reference to `is_hidden'  

說明了hidden確實起到做用了。class

相關文章
相關標籤/搜索