无法让GNU链接器(ld)导出符号的问题

7
我正在使用某些GNU工具,即GNU C++编译器(g++)和GNU链接器(ld),以创建共享库(.so)文件和二进制可执行文件。
二进制可执行文件使用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函数的调用不会导致未定义的符号错误。这让我感到非常困惑,因为在最初版本的二进制可执行文件中,符号看起来已经被正确导出了。有人能看到问题吗?任何帮助都将不胜感激。
提前致谢。
1个回答

3
我已经成功解决了这个问题。我发现如果我从以下行中删除引号;
"ToolboxManager::registerToolbox*"

只需在文件${top_srcdir}/dynamic_symbol_table.txt中进行修改,然后重新链接可执行文件,就可以解决问题。也就是说,dlopen函数将不再失败。

我不禁想知道,在这个网站上提出这个问题是否比在GNU binutils邮件列表上更合适。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接