【问题标题】:C++ symbol has different size in shared objectC++ 符号在共享对象中具有不同的大小
【发布时间】:2013-02-24 18:22:39
【问题描述】:

我一直致力于开发一个跨平台的窗口库,专门用于 OpenGL,目前专注于 linux。我正在使用 glload 来管理 OpenGL 扩展,并且正在将其与我稍后将使用的其他库一起编译为 .so。正如您所期望的那样,这个 `.so 正在被动态加载,但在运行时程序会给出以下输出(手动包装,因此更容易阅读):

_dist/x64-linux-debug/bin/test: Symbol `glXCreateContextAttribsARB' has \
different size in shared object, consider re-linking

现在,显然我已经尝试重新链接,甚至多次重建整个项目(测试一下,而不是盲目地希望它会神奇地让一切变得更好)。该程序似乎确实愿意运行,因为它会产生一些我所期望的日志输出。我已使用nm 确认“符号”在.so

nm _dist/x64-linux-debug/lib64/libvendor.so | grep glXCreateContextAttribsARB
00000000009e0e78 B glXCreateContextAttribsARB

如果我使用 readelf 查看正在定义的符号,我会得到以下信息(同样,我手动包装了前三行以进行格式化):

readelf -Ws _dist/x64-linux-debug/bin/test \
_dist/x64-linux-debug/lib64/libvendor.so | \
grep glXCreateContextAttribsARB
   348: 000000000062b318  8 OBJECT  GLOBAL DEFAULT  26 glXCreateContextAttribsARB
   421: 000000000062b318  8 OBJECT  GLOBAL DEFAULT  26 glXCreateContextAttribsARB
  1370: 00000000009e0e78  8 OBJECT  GLOBAL DEFAULT  25 glXCreateContextAttribsARB
 17464: 00000000009e0e78  8 OBJECT  GLOBAL DEFAULT  25 glXCreateContextAttribsARB

恐怕这就是我能提供的所有帮助,因为我真的不知道该尝试或研究什么。就像我说的,我确信需要更多信息,所以请说我会提供我能提供的。我正在从我的项目根目录运行这些命令,包括你想知道的。

【问题讨论】:

  • 我认为没有真正的“答案”,有一些回答会有所帮助,但我认为我没有找到这个问题的根源。

标签: c++ linux linker shared-libraries glload


【解决方案1】:

wilsonmichaelpatrick 的回答大部分是正确的,但使用 gdb 可能不是找到问题的最快方法,如果您有非调试版本,则可能根本无法工作。

首先,你应该确认确实有问题:

readelf -Ws _dist/x64-linux-debug/bin/test _dist/x64-linux-debug/lib64/libvendor.so |
  grep glXCreateContextAttribsARB

这应该显示在testlibvendor.so中定义的符号,大小不同。

其次,用-Wl,-y,glXCreateContextAttribsARB 标志重新链接testlibvendor.so。这将告诉您哪些对象文件(或库)提供了(不同的)定义。

最后,使用-E-dD 标志对生成上述目标文件的源进行预处理,看看它们之间有什么不同。

更新:

我需要帮助来消化它在说什么

不要束手无策。阅读man readelf,或者手动运行它。你会看到这样的东西:

readelf -Ws /bin/date | head -5

Symbol table '.dynsym' contains 75 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
     1: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND __ctype_toupper_loc@GLIBC_2.3 (2)

这会告诉您所获得数据的含义。特别是,这告诉您testlibvendor.so 中符号的大小是相同的(8)。因此,问题出在这两个 ELF 文件中不是,而是其他地方。在您的other 库上运行readelf,并查找具有不同大小的glXCreateContextAttribsARB 的定义。然后按照其余的程序进行操作。

【讨论】:

  • 我在运行readelf 后更新了问题,但是,我需要帮助来消化它所说的内容
【解决方案2】:

运行时注意到在共享对象中编译的 glXCreateContextAttribsARB 和在主程序中编译的 glXCreateContextAttribsARB(或者甚至可能之前链接的其他一些共享对象)具有不同的大小。这意味着,在共享对象的单独构建中以及引用该对象的任何其他内容中,他们必须查看定义 this 的不同代码(可能在共享对象中)。有时这是因为他们正在查看不同的文件,有时这是因为不同的#defines 导致对同一文件的不同解释。不管是什么原因,您绝对需要确保在运行时链接在一起的所有内容中以相同的方式定义相同的符号(例如结构)(即具有相同的成员变量和大小)。

它拒绝运行实际上是一件非常好的事情,因为当代码的两个部分在运行时以不同的方式解释同一位内存时,这是一场灾难。 (如果允许继续进行,任何事情都可能发生,这并不为过。)

您可能想尝试在 gdb 中加载可执行文件(不运行它)并输入

info types

查看它的定义位置,然后在 gdb 中加载共享对象(不运行它)并在那里执行另一个 info types 以查看每个人认为它在看什么。如果是同一件事,请检查预处理器指令。

【讨论】:

  • 酷,感谢您的意见。我将不得不首先阅读如何实际使用 GDB:P
【解决方案3】:

我遇到了一个与不同大小的对象相关的繁琐问题,所以我想分享我的经验 - 尽管我很清楚这只是可能解释不同对象大小的一个原因 - 而不是强制要求的 OP。

症状是调试模式下不同大小的对象,发布模式下没有。链接器产生了相应的警告。符号名称难以破译,但与类模板实例中的一些未命名的静态变量有关。

原因是调试日志功能 à la LOG("Do something.");。 LOG 宏使用了 C ANSI 宏 __FILE__,它根据标头是包含在应用程序中还是包含在共享库中而扩展到另一个路径。而这个字符串正是前面提到的未命名的静态变量。

更乏味的是,由于我们的 make 环境,__FILE__ 宏有时会扩展为 C:\temp\file.h,有时会扩展为 C:\other\..\temp\file.h,因此从同一个地方构建应用程序和库不会'也解决不了问题。

我希望这段经历可以为你们中的一些人节省一些时间。

【讨论】:

    【解决方案4】:

    在大多数情况下,您可能只是链接到了错误的库(不同的版本)。例如,您安装了两次libfoo,并将您的可执行文件与-L /path/to/version1 -lfoo 链接,但在运行时您与/path/to/version2 链接(您可以通过ldd yourprogram 看到这个)。

    一个原因可能是可执行文件与-rpath,/path/to/version1 链接,但是(与最近的版本一样)这在动态部分设置了RUNPATH 条目;而你有LD_LIBRARY_PATH=/path/to/version2。当设置RUNPATH 时,LD_LIBRARY_PATH 优先。在这种情况下,从 /path/to/version2 中删除库(或从 LD_LIBRARY_PATH 中删除该路径)。

    示例

    $ minimal
    /home/carlo/minimal: Symbol `_ZN6libcwd8libcw_doE' has different size in shared object, consider re-linking
    COREDUMP    : /home/carlo/projects/libcwd/libcwd/elfxx.cc:2381: void libcwd::elfxx::objfile_ct::load_dwarf(): Assertion `size == sizeof(address)' failed.
    

    (libcwd 也很聪明,可以看到它;也就是这里的问题在于 libcwd):

    $ ldd minimal | grep libcwd_r
            libcwd_r.so.5 => /usr/local/install/6.0.0-1ubuntu2/lib/libcwd_r.so.5 (0x00007f0b69840000)
    
    $ echo $LD_LIBRARY_PATH
    /usr/local/install/6.0.0-1ubuntu2/lib
    
    $ objdump -a -x minimal | grep PATH
      RUNPATH /opt/gitache/libcwd_r/888f62c44fd64f1486176bf9e35b36f79612790017c31f95e117fc59743a54ca/lib
    

    取消设置 LD_LIBRARY_PATH 或从该路径中删除 libcwd 会导致

    $ unset LD_LIBRARY_PATH
    $ ldd minimal | grep libcwd_r
            libcwd_r.so.5 => /opt/gitache/libcwd_r/888f62c44fd64f1486176bf9e35b36f79612790017c31f95e117fc59743a54ca/lib/libcwd_r.so.5 (0x00007f11d7298000)
    

    然后事情又开始了。或者,我可以添加到项目的 CMakeLists.txt 中:

    $ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--disable-new-dtags")
    

    之后我们得到,

    $ objdump -a -x minimal | grep PATH
      RPATH                /opt/gitache/libcwd_r/888f62c44fd64f1486176bf9e35b36f79612790017c31f95e117fc59743a54ca/lib
    

    现在优先于LD_LIBRARY_PATH,因此也解决了这个问题。然而,这不是推荐的方式:如果你设置LD_LIBRARY_PATH,你应该知道你在做什么。如果这不起作用,您应该修复 LD_LIBRARY_PATH 或删除有问题的库。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-07
      • 1970-01-01
      • 2019-08-24
      • 1970-01-01
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 2011-04-07
      相关资源
      最近更新 更多