为啥 C 程序会在运行时针对 C++ 库编译和链接 C 编译器然后 SIGILL?

Posted

技术标签:

【中文标题】为啥 C 程序会在运行时针对 C++ 库编译和链接 C 编译器然后 SIGILL?【英文标题】:Why would a C program compile and link with a C compiler against C++ libraries then SIGILL at runtime?为什么 C 程序会在运行时针对 C++ 库编译和链接 C 编译器然后 SIGILL? 【发布时间】:2016-01-21 05:47:24 【问题描述】:

我最近在 IBM AIX 上编写的第 3 方插件出现问题。追查需要相当长的时间。该插件采用 C 可执行文件的形式。可执行文件是针对 3rd 方库编译的。为强制升级提供了这些库的新版本。

当使用 IBM C 编译器 12.1 编译和链接时,我现有的代码将生成一个二进制文件,如果使用 OLSON 设置时区并使用 SIGILL 崩溃并且如果使用 POSIX 设置时区则没有可用的回溯。

使用调试 printfs 到日志文件并刷新日志文件,我能够相当快地追踪到调用 3rd 方 API 的崩溃。但是第 3 方提供商花了一些时间才提到新版本的 API 在他们自己的代码中引入了 C++ 库的使用。

问题已通过使用 IBM C 编译器进行编译但使用 IBM C++ 链接器 (xlC) 链接得到解决。

所以我的问题是:

1) 为什么 C 链接器无法生成有效的可执行文件?

必须已生成半有效的二进制文件,否则代码将无法在 OLSON 时区下运行。这意味着所有符号都存在并且任何名称修改都已处理(尽管可能不正确)

2) 如何判断编译器和链接器生成的二进制文件是否有效?

我能想到的唯一方法是通过单元测试尽可能充分地练习代码。

3) 如何防止不同代码出现类似情况?

我是否应该始终使用 C++ 链接器进行链接?这对我来说似乎不对。

抱歉,我无法发布代码,但我无权这样做。

【问题讨论】:

Off:插件应该是“共享对象”而不是“可执行文件”。 On:使用 C++ 是一种很快就会陷入困境的方法;例如,如果其中一个源模块是用 -D_THREAD_SAFE(或 -pthread)编译的,而另一个没有它,它们将无法一起工作。不同的 C++ 编译器(xlc 和 g++)也可能是二进制不兼容的。 (另外,在链接时,g++ 使用称为 collect2 的特殊组件,该组件在 AIX 上已损坏。) 注意:公平地说,如果没有 C++,您也可能会遇到二进制不兼容;例如,如果您尝试将使用大文件支持编译的模块与没有大文件支持编译的模块混合使用。 注意:如果插件有未解析的符号(检查dump -H libfoo.so的最后一行),主程序必须用-Wl编译,-brtllib 缺少此选项会导致奇怪的错误,包括 SIGILL。 'Plugin' 在这种情况下就是产品开发人员所说的。可执行文件作为完整的 exe 启动,并带有来自另一个服务器产品的主例程。 所以你的“插件”是一个独立的可执行文件。无论如何,如果它包含 C++,那么它的每个部分都应该用 C++ 编译器/链接器进行编译和链接。还要注意不兼容问题,例如线程安全是/否、大文件支持是/否、不同的编译器(-version)、不同版本的共享库、缺少 -Wl、-brtllib 等 【参考方案1】:

Zsigmond 有很多好话。我们至少需要查看链接行及其选项来帮助您。很多时候,开源链接带有“忽略未解析的符号”,因为它们不理解导入文件。因此,该链接将成功生成一个完全无用的二进制文件——因为这就是它被要求这样做的原因。

【讨论】:

在每种情况下,传递给 xlc 的唯一显式选项是 -g、-c 和 -o 加上相同的库文件集。这并不是说编译器没有将默认选项传递给链接器。我只是对链接器没有失败感到惊讶。

以上是关于为啥 C 程序会在运行时针对 C++ 库编译和链接 C 编译器然后 SIGILL?的主要内容,如果未能解决你的问题,请参考以下文章

为啥要为 c 和 c++ 使用 gcc 和 g++ 编译器驱动程序

为啥即使使用 -cudart static 编译,库用户仍然需要链接到 cuda 运行时

与动态库链接导致的可执行运行时崩溃

为啥我可以链接两个库在 VC 中导出相同的 C-Function?

ubuntulinux链接库

用 C++ 链接 C 库