如何获取未调用的C++头文件函数的名字修饰符号?
问题描述
我需要在不调用任何函数的前提下,生成所包含头文件中函数的名字修饰符号。比如头文件mylib.hpp包含ns命名空间下的MyClass类及其printHello()成员函数,当我编译仅包含该头文件的use_mylib.cpp(g++ -c use_mylib.cpp -o symbols.o)时,生成的目标文件里没有任何符号——因为函数未被调用。
我想获取ns::MyClass::printHello()对应的名字修饰符号_ZN2ns7MyClass10printHelloEv,但直接用g++编译无法实现,这不符合编译器的常规逻辑(仅生成被引用/调用的符号)。
我的背景需求是:制作共享库时希望仅编译一次源码,发布时只保留公开符号,但测试阶段需要用到未发布的符号。目前计划采用“先保留所有公开符号再剥离”的方案,当前瓶颈是如何通过公开头文件生成需要保留的导出名字修饰符号。
可行解决方案
1. 利用GCC的-fdump-lang-class选项
编译包含头文件的代码时添加-fdump-lang-class参数,GCC会生成一个后缀为.lang-class的输出文件,其中包含类的详细信息,包括成员函数的名字修饰符号:
g++ -c use_mylib.cpp -fdump-lang-class
打开生成的use_mylib.cpp.lang-class文件,可直接找到类似_ZN2ns7MyClass10printHelloEv的条目。
2. 基于Clang AST解析提取符号
使用Clang的AST转储功能分析头文件,提取函数的全限定名后转换为修饰符号:
- 第一步,转储AST结构:
clang++ -Xclang -ast-dump -fsyntax-only mylib.hpp - 第二步,编写脚本(如Python)遍历AST输出,提取所有公开函数的全限定名(如
ns::MyClass::printHello)。 - 第三步,将提取到的函数名转换为修饰符号:可以编写一个临时C++文件,声明对应函数的指针,编译后用
nm提取符号,或者直接利用Clang的API生成修饰名。
3. 自动生成临时代码提取符号
编写脚本解析头文件(可先通过cpp预处理),自动生成包含函数指针引用的临时C++代码,编译后提取符号:
- 生成的临时代码示例:
#include "mylib.hpp" // 为每个公开函数生成指针引用 void* sym_printHello = (void*)&ns::MyClass::printHello; - 编译临时文件并提取符号:
输出结果中即可得到目标名字修饰符号。g++ -c temp.cpp -o temp.o nm temp.o | grep -v "sym_"
4. 针对共享库场景的优化方案
如果是为了共享库的符号管理,也可以直接在编译阶段通过可见性控制实现:
- 编译共享库时添加
-fvisibility=hidden,默认隐藏所有符号; - 对需要公开的函数/类添加
__attribute__((visibility("default")))标记; - 这样编译出的共享库默认只保留公开符号,无需后续剥离,测试时可以编译不添加
-fvisibility=hidden的版本即可。
内容的提问来源于stack exchange,提问作者Mozartenhimer

