C++符号在共享对象中具有不同的大小
C++ symbol has different size in shared object
我一直在开发一个跨平台窗口库,专门用于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
恐怕这是我所能提供的全部帮助,因为我真的不知道该尝试或研究什么。就像我说的,我相信会需要更多的信息,所以请说,我会提供我能提供的。我正在从我的项目根运行这些命令,包住你想知道的。
wilsonmichaelpatrick的答案基本上是正确的,但使用gdb
可能不是找到问题的最快方法,如果您有一个未调试的构建,则可能根本不起作用。
首先,你应该确认事实上存在一个问题:
readelf -Ws _dist/x64-linux-debug/bin/test _dist/x64-linux-debug/lib64/libvendor.so |
grep glXCreateContextAttribsARB
这应该显示在test
和libvendor.so
中定义的具有不同大小的符号。
第二,用-Wl,-y,glXCreateContextAttribsARB
标志重新链接test
和libvendor.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)
这告诉你所拥有的数据的含义。特别是,这告诉您test
和libvendor.so
中的符号大小相同(8
)。因此,问题是这两个ELF文件中的而不是,而是其他地方。在其他库上运行readelf
,并查找具有不同大小的glXCreateContextAttribsARB
的定义。然后按照程序的其余部分进行操作。
运行时注意到,在共享对象中编译的glXCreateContextAttribsARB和在主程序中编译的glXCreateContextAttribsARB(甚至可能是以前链接的其他共享对象)具有不同的大小。这意味着,在共享对象和引用该对象的其他对象的单独构建中,他们必须查看定义该对象的不同代码(可能在共享对象中)。有时这是因为他们查看不同的文件,有时这是由于不同的#定义导致对同一文件的不同解释。无论是什么原因,您绝对需要确保在运行时链接在一起的所有内容中以相同的方式定义相同的符号(例如结构)(即具有相同的成员变量和大小)。
事实上,它拒绝运行是一件非常好的事情,因为当代码的两个部分在运行时以不同的方式解释相同的内存时,这是一场灾难。(毫不夸张地说,如果允许这样做,任何事情都可能发生。)
您可能只想尝试在gdb中加载可执行文件(不运行它)并键入
info types
看看它是在哪里定义的,然后在gdb中加载共享对象(不运行它),并在那里执行另一个info types
,看看他们每个人认为它在看什么。如果是一样的,请检查预处理器指令。
我遇到了一个与不同大小的对象相关的乏味问题,所以我想分享我的经验——尽管我很清楚这只是解释不同对象大小的一个原因——而不是强制性的OP。
症状是调试模式下不同大小的对象,发布模式下没有。链接器产生了相应的警告。符号名称很难破译,但与类模板实例中的一些未命名静态变量有关。
原因是LOG("Do something.");
的调试日志记录功能。LOG宏使用了C ANSI宏__FILE__
,该宏扩展到另一个路径,这取决于头是由应用程序还是由共享库包含。这个字符串正是前面提到的未命名的静态变量。
更乏味的是,由于我们的make环境,__FILE__
宏有时扩展到C:tempfile.h
,有时扩展到C:other..tempfile.h
,因此从同一个地方构建应用程序和库也不能解决问题。
我希望这段经历能给你们中的一些人留出一些时间。
在大多数情况下,您可能只是链接到了错误的库(不同的版本)。例如,您安装了两次libfoo
,并将可执行文件与-L /path/to/version1 -lfoo
链接,但在运行时,您将与/path/to/version2
链接(您可以使用ldd yourprogram
看到此链接)。
一个原因可能是可执行文件与-rpath,/path/to/version1
链接,但(就像最近的版本一样)这设置了动态部分中的RUNPATH
条目;而你有CCD_ 32。当设置了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
其现在优先于CCD_ 38并且因此也解决了该问题。然而,这不是推荐的方式:如果您设置LD_LIBRARY_PATH
,您应该知道自己在做什么。如果这不起作用,您应该修复LD_LIBRARY_PATH
或删除有问题的库。
- 为什么我的共享库中存在展开符号
- 仅在少数方法(静态或共享库)中解析的外部符号
- 共享对象、符号、C/C++ 库链接和加载
- 共享对象中的符号
- 如何防止 CMake 在构建时(而不是在安装时)为共享库创建符号链接?
- 使用共享库编译可执行文件时仅链接所需的符号
- 为什么 std:: 符号在共享库中被强制导出?
- 使用 C++ 标准库避免共享库中的符号冲突
- 隐藏共享库中的"_init"和"_fini"符号
- 共享对象中的符号名称与文件中.cpp函数不同
- C++:在共享对象中调用抽象基类构造函数/未定义的符号
- 共享库中使用"使用命名空间"定义的符号错误
- GCC 中使用 -O3 的共享库编译不会导出与 -O0 中那样多的符号
- Cython:共享对象中未定义的符号
- 不同的数学符号绑定与共享库与 dlopen 并直接链接到可执行文件 (Linux)
- 尝试与从 CUDA 对象构建的共享库链接时未定义的符号
- 在链接链接静态(GSOAP)库的共享库时,为什么会得到一个未定义的符号
- 共享库中非模板基的模板子类导致未定义的符号类型信息'class'链接错误
- 静态库将转换为共享的lib符号隐藏
- 在共享C++库中加载共享库时C++未定义的符号,该库本身由 Python 加载