C ++符号在共享对象中具有不同的大小

我一直在研究一个跨平台的窗口库,专门用于OpenGL,目前专注于Linux。 我正在使用glload来pipe理OpenGL扩展,并且正在编译以及稍后将使用的其他库,并将其编译为.so 。 这个`.so正在像你期望的那样dynamic加载,但是在运行时程序给出了下面的输出(手动包装,这样更容易阅读):

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

现在,很显然我已经尝试过重新连接,甚至重build整个项目多次(testing的东西,不只是盲目地希望它会神奇地使一切更好)。 该程序似乎是愿意运行,因为它会产生一些日志输出,如我所料。 我用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 

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

其次,用libvendor.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文件中,而是在其他地方。 在其他库上运行readelf ,并查找具有不同大小的glXCreateContextAttribsARB定义。 然后按照程序的其余部分。

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

它拒绝运行实际上是一件非常好的事情,因为当代码的两个部分在运行时以不同的方式解释同一位内存时,这是一场灾难。 (如果允许这样做,不要夸大其词。)

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

info types

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

我面对一个与大小不同的对象有关的单调乏味的问题,所以我想分享我的经验 – 尽管我很清楚,这只是解释不同对象大小的一个原因 – 而不是强制执行OP。

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

原因是调试日志功能LOG("Do something."); 。 LOG宏使用扩展到另一个路径的C ANSI宏__FILE__ ,具体取决于应用程序或共享库是否包含头。 而这个字符串正是前面提到的未命名的静态变量。

更麻烦的是,由于我们的make环境, __FILE__宏有时会扩展到C:\temp\file.h ,有时会扩展到C:\other\..\temp\file.h这样构建应用程序和来自同一地点的图书馆也没有解决问题。

我希望这段经历可能会让你们中的一些人有所收获。