如何让GCC通过dladdr获取匿名命名空间中的函数名称?
GCC下dladdr无法获取匿名命名空间函数名称的解决方法
问题背景
使用dladdr函数根据函数指针获取函数名称时,GCC与Apple Clang表现存在差异:匿名命名空间内的函数foo,在GCC 13.1编译后无法被dladdr识别;但Apple Clang 14.0.3可以正常返回其名字修饰后的完整符号。
示例代码
#include <iostream> #include <dlfcn.h> namespace { std::string function_name(void const* f) { Dl_info di; auto res = dladdr(f, &di); if (res && di.dli_sname) { return di.dli_sname; } return {}; } } namespace { void foo() {} } void bar() {} int main() { std::cout << "1." << function_name((void const*)&foo) << '\n' << "2." << function_name((void const*)&bar) << '\n'; }
编译输出对比
- GCC 13.1输出:
1. 2._Z3barv
- Apple Clang 14.0.3输出:
1._ZN12_GLOBAL__N_13fooEv 2._Z3barv
解决方法
GCC默认对匿名命名空间内的函数采用hidden符号可见性,这类符号不会进入动态符号表,导致dladdr无法读取。可通过以下两种方式调整:
方法1:全局修改符号可见性
编译时添加-fvisibility=default选项,取消默认的符号隐藏规则,让所有符号默认可见:
g++ -fvisibility=default your_code.cpp -o your_program
此时匿名命名空间内的foo会被加入动态符号表,dladdr就能返回其修饰后的名称。
方法2:单独指定目标函数的可见性
若不想全局修改符号规则,可给匿名命名空间内的目标函数添加可见性属性,单独导出该符号:
namespace { __attribute__((visibility("default"))) void foo() {} }
该方式仅让foo符号可见,其他匿名命名空间内的符号仍保持默认隐藏状态。
原理说明
GCC默认将匿名命名空间符号标记为hidden,这类符号不会出现在动态符号表中;而dladdr依赖动态符号表查找符号信息。Clang则默认保留匿名命名空间符号到动态符号表,因此能被dladdr识别。调整可见性后,符号会被加入动态符号表,dladdr即可正常获取函数名称。
内容的提问来源于stack exchange,提问作者Kyle Knoepfel
相关产品推荐
相关产品推荐

