链接 gcc 6、gcc 7 和 gcc 8 对象是否安全?
Is it safe to link gcc 6, gcc 7, and gcc 8 objects?
链接C++17、C++14和C++11对象是否安全 询问链接使用不同语言标准编译的对象,Jonathan Wakely 对这个问题的出色回答解释了 gcc/libstdc++ 为确保这有效而做出的 ABI 稳定性承诺。
不过,在 gcc 版本之间还有一件事可以更改 - 通过-fabi-version
的语言 ABI .假设,为简单起见,我有三个目标文件:
foo.o
,使用 gcc 6.5 c++14 编译bar.o
,使用 gcc 7.4 c++14 编译quux.o
,使用 gcc 8.3 c++17 编译
所有这些都使用各自的默认语言 ABI(即 10、11 和 13)。根据链接的答案,从库的角度来看,将这些对象链接在一起是安全的。但是,从语言ABI的角度来看,是否有可能出错的事情?有什么我应该注意的吗?大多数语言 ABI 更改似乎不会引起问题,但是 12 中空类类型的调用约定更改可能会?
大多数语言 ABI 更改似乎不会引起问题,但是 12 中空类类型的调用约定更改可能会?
更改空类的调用约定可能会导致 x86-64 出现问题。下面是一个示例:
def.hpp:
struct Empty { };
struct Foo {
char dummy[16];
int a;
Foo() : a(42) { }
};
void fn(Empty, Foo);
一.cpp:
#include "def.hpp"
int main() {
fn(Empty(), Foo());
}
二.cpp:
#include <stdio.h>
#include "def.hpp"
void fn(Empty e, Foo foo) {
printf("%dn", foo.a);
}
现在,如果您使用 G++ 8 编译它们,具有不同的 ABI 11 和 12,例如:
g++ -c -fabi-version=11 one.cpp
g++ -c -fabi-version=12 two.cpp
g++ one.o two.o
生成的a.out
不会打印预期的42
。
原因是旧的 ABI (11) 为堆栈上的Empty()
保留了空间,但新的 ABI (12) 没有。因此,foo
的地址在主叫方和被叫方之间会有所不同。
(注意:我已经包含了Foo::dummy
以便使用堆栈而不是寄存器传递Foo
因此。如果使用寄存器传递Foo
,则不会有问题。
它们中的大多数都以次要的方式更改重整,这可能会导致链接时出现一些未定义的引用,或者只是由于相同的源代码生成两个具有不同名称的等效符号而导致一些代码膨胀,因此链接器不会合并。
空类类型的调用约定更改 12 可能?
是的,当然。如果您的非最终参数是空类型,那么这会影响函数的 ABI,并且差异可能导致未定义的行为(在实践中,访问堆栈上的垃圾,或参数获得错误的值)。
- 自定义对象的dlib序列化在gcc中失败
- 为什么库API+编译器ABI足以确保具有不同版本gcc的对象之间的兼容性
- GCC __attribute__((constructor)) 在对象构造函数之前调用
- l值引用对象上的Constexpr成员函数:Clang和gcc不同意
- 初始化不可移动对象数组:为什么这样的代码无法在 GCC 上编译?
- 告诉 GCC 假设对象已初始化
- 链接 gcc 6、gcc 7 和 gcc 8 对象是否安全?
- GCC 需要大量内存来编译堆栈上具有非常大对象的 C++ 文件
- GCC 对象按值或地址传递
- GCC:当层次结构中存在虚拟继承时,C++11 内联对象初始化(使用 "this")不起作用
- GNU GCC会跟踪以前使用箭头操作员对的对象
- GCC链接器 - 将存档中的所有对象文件映射到特定部分
- 如何动态链接 GCC 对象
- gcc编译错误,对象初始化被解释为函数指针
- 为什么gcc和msvc允许const对象没有用户提供的构造函数?这是个bug吗
- 带有本地创建对象的gcc未定义引用
- C++ "错误:"引用中缺少对象..."取决于 GCC 版本
- GCC 一起构建对象和依赖项文件
- GCC 在被杀时创建带有随机后缀的对象文件
- 如何将一个 ostringstream 对象复制到另一个对象中(使用 gcc-4.7.0)