如何获取C++函数的被修饰符号?适配dlmopen加载的不可修改库
C++闭源共享库dlmopen后的符号获取方案
你遇到的核心问题是C的名字修饰(Name Mangling)——C编译器会将函数名、参数类型、名字空间等信息编码成唯一的修饰符号,而dlsym只能识别这种修饰后的符号。以下是具体解决步骤:
1. 获取库中的修饰后符号
首先需要从目标共享库中提取出目标函数对应的修饰符号,可通过以下命令实现:
- 使用
nm命令:
例如原函数是nm -D /myLib.so | grep <原函数名>void test(int),输出可能类似0000000000001234 T _Z4testi(GCC/Clang的修饰格式)。 - 使用
objdump命令(信息更详细):objdump -T /myLib.so | grep <原函数名>
注意:如果共享库被
strip处理过(移除了符号表),上述命令无法获取符号。这种情况下只能联系库提供者获取符号信息,或使用调试版本的库。
2. 调用dlsym获取函数指针
拿到修饰后的符号后,直接将其传入dlsym,并通过reinterpret_cast转换为正确的函数指针类型(必须保证签名完全匹配,包括返回值、参数类型、const修饰、引用/值传递等,否则会触发未定义行为)。
示例代码:
// 假设拿到的修饰符号是_Z4testi,原函数签名为void test(int) void (*test_func)(int) = reinterpret_cast<void(*)(int)>( dlsym(handle, "_Z4testi") ); // 调用函数(如果指针有效) if (test_func) { test_func(123); }
3. 兼容不同编译器/名字空间的情况
- 如果库由其他编译器编译(如MSVC,但Linux场景下少见),需要用相同编译器编写测试代码来匹配修饰规则:
新建一个测试文件test_sym.cpp:
编译后查看符号:// 完全复刻目标函数的签名、名字空间 namespace myns { void test(int); } int main() { return 0; }
得到的符号就是该编译器下的修饰结果,再去库中查找匹配项。g++ -c test_sym.cpp && nm test_sym.o - 若函数属于某个名字空间,修饰符号会包含名字空间信息,必须保证测试代码的名字空间与库中一致。
内容的提问来源于stack exchange,提问作者Hykosit
相关产品推荐
相关产品推荐

