GCC 符号冲突的坑
2025-07-05 21:00:14

前些天踩了一个 GCC 的坑,事情是这样的:项目中引入了一个共享库,在共享库接口内调用了另一个函数,问题是这个函数并未执行。

1
2
3
4
int my_api_init()
{
return internal::init(); // internal::init并没有被执行到
}

由于初始化接口未成功执行,后续的接口都调用失败了。
起初以为是 GCC 优化问题,然后为函数加了个参数,变为了这样

1
2
3
4
int my_api_init()
{
return internal::init(1);
}

暂时解决了问题。
后来网上求助,有人提到可能是符号冲突,然后偶然发现项目中使用了另一个共享库,内部也有个同名的方法,函数签名一模一样,于是尝试在这个函数中打印日志,果然执行到了这里!
于是再次查看符号确认

1
2
readelf -s a.so | grep init
readelf -s b.so | grep init

两个模块中导出了一模一样的符号!
原来 GCC 在不主动设置的情况下,默认会导出所有符号,于是我在 CMake 中加入了fvisibility选项

1
add_compile_options(-fvisibility=hidden)

来默认隐藏符号,然后在要导出的 API 前加上

1
2
3
4
5
6
7
#if defined(__GNUC__) && (__GNUC__ >= 4)
# define MY_API __attribute__((visibility("default")))
#else
# define MY_API
#endif

MY_API int my_api_init();

这样生成的文件体积也小了很多。


问题原因是因为两个库都没有使用-fvisibility控制符号可见性,GCC 默认将所有符号都导出了,而项目中同时加载了这两个库,后加载的库的同名符号被忽略掉了。

相关阅读

GCC的符号可见性 -fvisibility=hidden
C/C++符号隐藏与依赖管理:库的符号隐藏

上一页
2025-07-05 21:00:14