我正在使用某些GNU工具,即GNU C++编译器(g++)和GNU链接器(ld),以创建共享库(.so)文件和二进制可执行文件。
二进制可执行文件使用dlopen函数在运行时动态加载共享库文件。此外,共享库文件需要调用特定的类方法(称为ToolboxManager :: registerToolbox),该方法在二进制可执行文件中定义。这是通过强制二进制可执行文件导出类方法来实现的,这又是通过将二进制可执行文件与以下命令行选项链接来完成的;
请注意文件中使用的星号(*),它强制链接器导出所有以 "ToolboxManager::registerToolbox" 开头的符号。
当我在生成的可执行二进制文件上运行 GNU nm 工具("nm -C -g ./a.out"),它会显示关于上述类方法的以下信息;
或者,如果像上面那样调用nm实用程序,但这次没有使用-C命令行开关;
这看起来也是正确的。在类方法
然而,当我从命令行运行二进制可执行文件时出现了问题,导致显示以下错误信息;
如您所见,这两个混淆名称是相同的。因此,我无法理解为什么未定义的符号在运行时无法解析。
然后,我重新链接了二进制可执行文件,但这次我替换了以下链接器命令;
如果再次运行二进制可执行文件,这次它将正确执行,并且对dlopen函数的调用不会导致未定义的符号错误。这让我感到非常困惑,因为在最初版本的二进制可执行文件中,符号看起来已经被正确导出了。有人能看到问题吗?任何帮助都将不胜感激。
提前致谢。
二进制可执行文件使用dlopen函数在运行时动态加载共享库文件。此外,共享库文件需要调用特定的类方法(称为ToolboxManager :: registerToolbox),该方法在二进制可执行文件中定义。这是通过强制二进制可执行文件导出类方法来实现的,这又是通过将二进制可执行文件与以下命令行选项链接来完成的;
-Wl,--dynamic-list=${top_srcdir}/dynamic_symbol_table.txt
文件${top_srcdir}/dynamic_symbol_table.txt
包含以下内容:
{
extern "C++"
{
"ToolboxManager::registerToolbox*";
};
};
请注意文件中使用的星号(*),它强制链接器导出所有以 "ToolboxManager::registerToolbox" 开头的符号。
当我在生成的可执行二进制文件上运行 GNU nm 工具("nm -C -g ./a.out"),它会显示关于上述类方法的以下信息;
08053da0 T ToolboxManager::registerToolbox
(
std::string&,
std::string&,
std::map
<
std::string,
Factory_DSPB_Base*,
std::less
<
std::string
>,
std::allocator
<
std::pair
<
std::string const,
Factory_DSPB_Base*
>
>
>&
)
或者,如果像上面那样调用nm实用程序,但这次没有使用-C命令行开关;
08053da0 T _ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
到目前为止,这看起来很好。类方法ToolboxManager::registerToolbox
定义前面的"T"表示该方法位于文件的Text/Code部分。
同样,如果我在共享库文件上运行nm实用程序(nm -C -g ./toolbox.so
),它将显示有关同一上述类方法的以下信息;
U ToolboxManager::registerToolbox
(
std::string&,
std::string&,
std::map
<
std::string,
Factory_DSPB_Base*,
std::less
<
std::string
>,
std::allocator
<
std::pair
<
std::string const,
Factory_DSPB_Base*
>
>
>&
)
这看起来也是正确的。在类方法
ToolboxManager::registerToolbox
的定义前面的“U”表示该方法在共享库文件中未定义。然而,当我从命令行运行二进制可执行文件时出现了问题,导致显示以下错误信息;
./toolbox.so: undefined symbol: _ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
以下是运行时消息中出现的混淆类方法名,作为两行中的第一行。为了比较,上面生成的混淆类方法名(使用nm -g
命令)作为两行中的第二行显示;
_ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
_ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
如您所见,这两个混淆名称是相同的。因此,我无法理解为什么未定义的符号在运行时无法解析。
然后,我重新链接了二进制可执行文件,但这次我替换了以下链接器命令;
-Wl,--dynamic-list=${top_srcdir}/dynamic_symbol_table.txt
使用这个;
-Wl,--export-dynamic
--export-dynamic
链接器选项指示GNU链接器将所有符号添加到动态符号表中。如果再次运行二进制可执行文件,这次它将正确执行,并且对dlopen函数的调用不会导致未定义的符号错误。这让我感到非常困惑,因为在最初版本的二进制可执行文件中,符号看起来已经被正确导出了。有人能看到问题吗?任何帮助都将不胜感激。
提前致谢。