共享对象中的符号名称与文件中.cpp函数不同

symbol name in shared object differs from function in .cpp file

本文关键字:cpp 文件 函数 对象 符号 共享      更新时间:2023-10-16

在项目环境中,我想将共享对象的源文件从 c 更改为 cpp。我也确保更改其在CMakeLists.txt中的条目:

add_library(*name* SHARED *mysource*.cpp)
target_link_libraries(*name as target* *item*)

生成过程运行良好。不幸的是,当我尝试使用它时,出现一个错误,即找不到 .so 中的函数。

在使用 objdump -T 检查共享对象内的动态符号表后,我发现符号的名称与源文件中的名称不同。 例如

int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx);

成为

_Z17sr_plugin_init_cbP16sr_session_ctx_sPPv

在我的 Visual Studio 代码中,它说它可以正确构建对象并链接共享库,并且它还在输出中从 C 更改为 CXX,即使某些代码仅是 c++,也没有给我任何错误。

为什么符号名称会更改?

为什么符号名称会更改?

C++具有称为函数重载的功能。基本上发生的情况是,您声明了两个名称相同但略有不同的函数:

int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx);
int sr_plugin_init_cb(sr_session_ctx_t *session, void **private_ctx, int some_arg);

或者更糟糕的情况:

struct A {
# each of these functions can be different depending on the object
void func();
void func() const;
void func() volatile;
void func() volatile const;
};

函数的名称相同。Linker 看不到C++源,但它仍然必须区分这两个函数才能与它们链接。因此C++编译器会"破坏"函数名称,以便链接器可以区分它们。为了简单起见,它可能看起来像:

sr_plugin_init_cb_that_doesnt_take_int_arg
sr_plugin_init_cb_that_takes_int_arg
A_func
A_func_but_object_is_const
A_func_but_object_is_volatile
A_func_but_object_is_volatile_and_const

名称重整的规则很复杂,以使名称尽可能短。它们必须考虑任意数量的模板、参数、对象、名称、准数、lambda、重载、运算符等,并生成唯一的名称,并且它们必须仅使用与特定体系结构上的链接器兼容的字符。例如,这里是 gnu g++ 编译器使用的名称重整的参考。

符号名称_Z17sr_plugin_init_cbP16sr_session_ctx_sPPv是由函数的编译器名称所破坏的。

非常感谢您的详细回答。我现在明白这个问题了。 经过快速搜索,我找到了解决问题的方法。像这样封装函数原型可以避免名称重整。

extern "C" {
// Function prototypes
};