cpp attribute 之 visibility

attribute ((visibility(“”)))

是 gcc 的编译器指令,用于设置在 shared object 中所修饰的符号对外的可见性。该修饰对 .a 文件不生效,只对 .so 库生效。

attribute ((visibility(“default”)))

该修饰用于修饰符号的可见性为默认对外可见。意思是通过该符号修饰的函数可以在 so 文件外访问到。

func.cpp:

1
2
3
__attribute__ ((visibility("default"))) void func1(int a) {
cout << a << endl;
}

main.cpp:

1
2
3
4
5
6
#include <iostream>
using namespace std;
extern void func1(int a);
int main() {
func1(10);
}
1
2
@└────> g++ func.cpp --shared -fPIC -o libfunc.so
@└────> g++ main.cpp -L./ -lfunc

之后发现是可以编译成功的。因为该符号是可见的。

1
2
@└────> nm libfunc.so | grep func
0000000000001179 T _Z5func1i

大写的 T 表示定义在 text 段,并且可被外部引用。如果你是通过编译 .o 文件再链接为 .so 文件的,还可以使用 readelf -s 查看 .o 文件的可见性.

attribute ((visibility(“hidden”)))

该修饰用于修饰符号的可见性为默认对外不可见。意思是通过该符号修饰的函数不可以在 so 文件外访问到,只能在 so 文件内部访问到。

func.cpp:

1
2
3
__attribute__ ((visibility("hidden"))) void func2(int a) {
cout << a << endl;
}

main.cpp:

1
2
3
4
5
6
#include <iostream>
using namespace std;
extern void func2(int a);
int main() {
func2(10);
}
1
2
3
4
5
@└────> g++ func.cpp --shared -fPIC -o libfunc.so
@└────> g++ main.cpp -L./ -lfunc
/usr/bin/ld: /tmp/cc7GABC5.o: in function `main':
fstream.cpp:(.text+0xe): undefined reference to `func2(int)'
collect2: error: ld returned 1 exit status

之后发现是可以编译失败,因为符号不可见.

1
2
@└────> nm libfunc.so | grep func
00000000000011ef T _Z5func2i

其他

1
2
__attribute__ ((visibility("internal")))
__attribute__ ((visibility("protected")))

上述两种一样是用于修饰符号, internal 对外不可见,而 protected 对外可见。
此外,在编译 so 文件时可以通过指定 -fvisibility=xxx 来指定默认的没有给出修饰的符号属性。
如:

1
@└────> gcc -fPIC -shared -o libtest.so -fvisibility=hidden test.c

这样在 test.c 中没用经过修饰的符号对外都不可见,而修饰为 default 的依旧对外可见。