我正在使用某些GNU工具,即GNU C++编译器(g ++)和GNU链接器(ld)来创建共享库(.so)文件以及二进制可执行文件.
二进制可执行文件利用该dlopen函数在运行时动态加载共享库文件.除此之外,共享库文件需要调用ToolboxManager::registerToolbox在二进制可执行文件中定义的特定类方法(被调用).通过强制二进制可执行文件导出类方法来实现这一点,而类方法又通过链接二进制可执行文件和以下命令行选项在链接时完成;
-Wl,--dynamic-list=${top_srcdir}/dynamic_symbol_table.txt
Run Code Online (Sandbox Code Playgroud)
文件${top_srcdir}/dynamic_symbol_table.txt包含以下内容;
{
extern "C++"
{
"ToolboxManager::registerToolbox*";
};
};
Run Code Online (Sandbox Code Playgroud)
请注意在文件中使用星号(*)来强制链接器导出所有以#开头的符号ToolboxManager::registerToolbox.
当我nm -C -g ./a.out在生成的二进制可执行文件上运行GNU nm实用程序()时,它显示有关上述类方法的以下信息;
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*
>
>
>&
)
Run Code Online (Sandbox Code Playgroud)
或者,如果如上所述调用nm实用程序,但这次不使用-C命令行开关;
08053da0 T _ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
Run Code Online (Sandbox Code Playgroud)
到目前为止,这看起来很好.类方法定义前面的"T" ToolboxManager::registerToolbox表示该方法位于文件的Text/Code部分.
同样,如果我nm -C -g ./toolbox.so在共享库文件上运行nm实用程序(),它会显示有关上述类方法的相同信息;
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*
>
>
>&
)
Run Code Online (Sandbox Code Playgroud)
这看起来也很好.类方法定义前面的"U" ToolboxManager::registerToolbox表示该方法在共享库文件中未定义.
但是,当我从命令行运行二进制文件时出现问题,此问题导致显示以下错误消息;
./toolbox.so: undefined symbol: _ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
Run Code Online (Sandbox Code Playgroud)
出现在此运行时消息中的受损类方法名称如下所示,作为两行中的第一行.为了进行比较,上面的错位类方法名称(以及使用该nm -g命令生成的)在下面显示为两行中的第二行;
_ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
_ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
Run Code Online (Sandbox Code Playgroud)
可以看出,两个受损的名称是相同的.因此,我无法理解为什么在运行时无法解析未定义的符号.
然后我重新链接了二进制可执行文件,但是这次我替换了以下链接器命令;
-Wl,--dynamic-list=${top_srcdir}/dynamic_symbol_table.txt
Run Code Online (Sandbox Code Playgroud)
与这一个;
-Wl,--export-dynamic
Run Code Online (Sandbox Code Playgroud)
该--export-dynamic连接器选项指示GNU链接器将所有符号添加到动态符号表.
如果然后再次运行二进制可执行文件 这次它正确执行并且对dlopen函数的调用没有导致未定义的符号错误.这让我感到非常困惑,因为它看起来好像在二进制可执行文件的初始版本中正确导出符号.有人能在这里看到问题吗?任何援助都将受到极大的赞赏.
提前致谢.
小智 3
我已经设法解决了这个问题。我发现如果我从以下行中删除引号;
"ToolboxManager::registerToolbox*"
Run Code Online (Sandbox Code Playgroud)
在文件中${top_srcdir}/dynamic_symbol_table.txt,然后重新链接二进制可执行文件,然后它就可以工作了。也就是说,dlopen函数不会再失败了。
我不禁想知道在 GNU binutils 邮件列表上提出这个问题是否比在本网站上提出更合适。