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

时间:2011-09-13 01:25:45

标签: linker gnu ld

我正在使用某些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 个答案:

答案 0 :(得分:3)

我设法解决了这个问题。我发现如果我删除以下行中的引号;

"ToolboxManager::registerToolbox*"

在文件${top_srcdir}/dynamic_symbol_table.txt中,然后重新链接二进制可执行文件,然后它可以工作。也就是说,dlopen函数不会再失败了。

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