-fvisibility=hidden作用于静态库的符号隐藏内部原理问询
编译阶段的符号属性标记
-fvisibility是编译期选项,作用对象是单个编译单元(.o文件),和最终生成的是静态库还是共享库没有关系:
- 编译
libB.a的每个源文件时指定-fvisibility=hidden,会让生成的所有.o文件里的全局符号、弱符号默认被标记为 hidden 可见性,只有显式添加__attribute__((visibility("default")))的符号才会是默认可见性。 - 静态库本身只是多个.o文件的归档打包,没有额外的符号处理逻辑,所以
libB.a里所有携带的符号默认都保留了hidden的可见性属性。
共享库链接阶段的符号导出规则
链接器生成libA.so时,对合并进来的所有符号的处理遵循固定规则:
- 只有可见性为
default的符号才会被写入共享库的动态符号表(.dynsym段),动态符号表是外部程序或其他库访问该共享库符号的唯一入口。你执行nm -C libA.so默认输出的就是动态符号表的内容,hidden属性的符号不会出现在这里。 - hidden属性的符号不会被导出到动态符号表,但是在共享库内部有固定的相对地址,
libA.so自身的代码可以正常访问这些符号,不需要走动态重定向逻辑。 - 链接时
libB.a中被依赖的.o文件会被整体合并到libA.so的代码段、数据段中,同时保留原有的符号可见性:因为libB.a的符号全是hidden属性,自然不会被导出到libA.so的动态符号表,外部完全无法访问,也不会被nm等工具扫描到。
常见误区说明
很多开发者误以为
-fvisibility仅对共享库生效,编译静态库不需要指定,这个认知是错误的:
- 如果你编译
libB.a时不加-fvisibility=hidden,那么libB的符号默认都是default可见性。哪怕编译libA.so时加了该选项,这些来自libB的default可见性符号依然会被导出到libA.so的动态符号表中,对外暴露。 - 核心原因是
-fvisibility只修改当前编译的源文件生成的符号的默认可见性,不会改动已经存在于其他.o/静态库中的符号属性。
内容的提问来源于stack exchange,提问作者Irbis
相关产品推荐
相关产品推荐

