试想这样的情景,程序调用某函数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