发布和调试之间的 ABI 兼容性

Posted

技术标签:

【中文标题】发布和调试之间的 ABI 兼容性【英文标题】:ABI Compatibility between release and debug 【发布时间】:2016-05-31 14:19:18 【问题描述】:

在使用 GCC 时,考虑到我有时在发布时和有时在调试时编译同一个库,ABI 是否保证兼容?

(使用相同的编译器)

我有一个可执行文件和一些共享对象(一些依赖于其他对象),我希望能够在不重新编译所有内容的情况下交换发布/调试共享对象,但 只有感兴趣的共享对象。

这可能吗,或者在某些情况下我可能会以这种方式得到一些未定义的行为? (假设我的代码是严格打包的,并且在发布和调试中都进行了填充)

编辑:

我将详细说明我们遇到的问题。我们有一个自定义版本的intrusive_ptr,在调试模式下我们有我们自己的intrusive_ptr,它有一个单个 成员,它是boost::intrusive_ptr,在发布时我们只使用boost::intrusive_ptr。我们intrusive_ptr的API和boost::intrusive_ptr是一样的,而且我们在类中没有任何虚函数。 我们看到的是这样的: 如果我们使用所有调试库或所有发布库都可以正常工作。如果我们将调试可执行文件与发布库混合使用,intrusive_ptr 会发生内存泄漏,并且不会释放对象。

我们的intrusive_ptrboost::intrusive_ptr 的大小在调试和发布时都是相同的(我们的类不会在顶部增加任何大小开销)。

所以我想知道是什么导致了泄漏,唯一想到的就是 ABI 差异。

想法?

【问题讨论】:

术语“调试”和“发布”在 gcc 领域没有很好的定义,往往是 IDE 的一个特性。如果您的“调试”构建在调试模式下使用 libstdc++,那么不,安全迭代器功能会更改集合对象布局。混合会导致随机内存损坏。 其实我已经检查过了,代码没有用libstdc++编译 @MaxShifrin 你找出问题的原因了吗? 是的,ABI 不保证是兼容的,据我回忆,在我们的例子中,这是对象结构中的一些额外填充。因此我们不能以这种方式做指针技巧,必须围绕这个问题进行设计。 【参考方案1】:

我知道有几个编译器会为发布和调试生成不兼容的代码(尽管这些编译器早已被弃用)。面对现实,我不会相信对象模块完全兼容,除非它们是用完全相同的标志编译的。

这就是为什么 makefile(遵循 GNU 原则)和像 Eclipse 这样的 IDE 将 release/debug/profile 对象构建到不同的目录中的原因。以确保它们永远不会混淆。

【讨论】:

我们在发布/调试之间通常使用相同的标志,我们主要更改优化级别并从发布版本中删除调试符号。据我所知,所有其他选项都是相同的。显然,我们通常构建到 2 个单独的目录中,但在某些情况下,您希望混合调试和发布对象。例如,您在发布中部署系统,并且想要调试给定模块中的某些特定功能,理论上您应该能够仅用调试版本替换该模块以便能够调试它。 (在开发期间)。 @MaxShifrin:很少有编译器能保证目标文件是兼容的。 启用一些优化会消除对象中的填充(以节省空间),从而留下链接器不会发现的 ABI 损坏。这是我能想到的第一个,破解 ABI 并不需要太多。 这也是为什么您看到公司在发布库时会提供两个版本的库的原因。一个调试版本和一个发布版本(如果它们还提供库的静态和动态版本,则为四个)。 gcc.gnu.org/onlinedocs/gcc/Compatibility.htmlSome GCC compilation options cause the compiler to generate code that does not conform to the platform's default ABI. Other options cause different program behavior for implementation-defined features that are not covered by an ABI.【参考方案2】:

通常不会,因为发布和调试构建之间的通常区别只是使调试步进工作更好的选项。但是意外的行为仍然可能发生,如果您在发布版本和调试版本之间以不同的方式定义其他选项(例如整数大小、目标体系结构、??),调用者参数可能与被调用者的期望不匹配。也可能存在异常安全性和运行时链接器可能无法检查的常量性问题。

【讨论】:

我们显然在两者中使用相同的 64 位架构,两种编译中的整数变量大小相同。 (对于我们使用的变量)

以上是关于发布和调试之间的 ABI 兼容性的主要内容,如果未能解决你的问题,请参考以下文章

Eclipse 是不是必须处理 C++ ABI 兼容性问题?

Java Native Interface (JNI) 是不是受 C++ ABI 兼容性问题的影响?

不同 C/C++ 语言版本 + GNU 扩展的 ABI 兼容性

缔造程序兼容的契约(ABI)

Qt5 for Android:不兼容的 ABI

Swift 5.0 计划年底发布:主打 ABI 稳定性,不向前兼容