Gcc制作动态符号导出表(动态库)
1.1 定义
在Linux下动态库(.so)中,通过GCC的C++ visibility属性可以控制共享文件导出符号。在GCC 4.0及以上版本中,有个visibility属性,可见属性可以应用到函数、变量、模板以及C++类。不指定gcc在制作动态库时,除了static修饰的函数、变量外,都默认可见。
1.2 优势
1. 限制符号可见性的原因
从动态库中尽可能少地输出符号是一个好的实践经验。输出一个受限制的符号会提高程序的模块性,并隐藏实现的细节。动态库装载和识别的符号越少,程序启动和运行的速度就越快。导出所有符号会减慢程序速度,并耗用大量内存。
2. 制作动态库原因
对于相同函数存在不同库的情况,文件只会优先使用先编译链接的动态库。
例如:gcc main.c -L. -lhello -lhello1,只会链接libhello.so
1.3 属性分类
1. “default”
用它定义的符号将被导出,动态库中的函数默认是可见的。
2. ”hidden”
用它定义的符号将不被导出,并且不能从其它对象进行使用,动态库中的函数是被隐藏的。default意味着该方法对其它模块是可见的。而hidden表示该方法符号不会被放到动态符号表里,所以其它模块(可执行文件或者动态库)不可以通过符号表访问该方法。
要定义GNU属性,需要包含__attribute__和用括号括住的内容。可以将符号的可见性指定为visibility(“hidden”),这将不允许它们在库中被导出,但是可以在源文件之间共享。实际上,隐藏的符号将不会出现在动态符号表中,但是还被留在符号表中用于静态链接。
导出列表由编译器在创建共享库的时候自动生成,也可以由开发人员手工编写。导出列表的原理是显式地告诉编译器可以通过外部文件从对象文件导出的符号是哪些。GNU用户将此类外部文件称作为”导出映射”。
1.4 动态库制作流程
1. Gcc指定编译选项,制作动态库
gcc -shared -fvisibility=hidden -o libhello.so hello.c
在编译时指定-fvisibility=hidden选项,未显式指定__attribute__(visibility(“default”))的符号都将被隐藏
2. 查看符号表
- 命令是readelf,选项是-s,如:readelf –s libhello.so
- 可设置隐藏.symtab符号表,命令为:strip libhello.so
symtab和.dynsym两个不同的symbol table,.dynsym用来保存与动态链接相关的导入导出符号,而 .symtab 则保存所有符号,包括 .dynsym 中的符号,.dynsym是.symtab的一个子集。