GCC 符号冲突的坑
2025-07-05 21:00:14
前些天踩了一个 GCC 的坑,事情是这样的:项目中引入了一个共享库,在共享库接口内调用了另一个函数,问题是这个函数并未执行。
1 | int my_api_init() |
由于初始化接口未成功执行,后续的接口都调用失败了。
起初以为是 GCC 优化问题,然后为函数加了个参数,变为了这样
1 | int my_api_init() |
暂时解决了问题。
后来网上求助,有人提到可能是符号冲突,然后偶然发现项目中使用了另一个共享库,内部也有个同名的方法,函数签名一模一样,于是尝试在这个函数中打印日志,果然执行到了这里!
于是再次查看符号确认
1 | readelf -s a.so | grep init |
两个模块中导出了一模一样的符号!
原来 GCC 在不主动设置的情况下,默认会导出所有符号,于是我在 CMake 中加入了fvisibility
选项
1 | add_compile_options(-fvisibility=hidden) |
来默认隐藏符号,然后在要导出的 API 前加上
1 |
|
这样生成的文件体积也小了很多。
问题原因是因为两个库都没有使用-fvisibility
控制符号可见性,GCC 默认将所有符号都导出了,而项目中同时加载了这两个库,后加载的库的同名符号被忽略掉了。