【问题标题】:Is it safe to link gcc 6, gcc 7, and gcc 8 objects?链接 gcc 6、gcc 7 和 gcc 8 对象是否安全?
【发布时间】:2019-09-07 21:39:20
【问题描述】:

Is it safe to link C++17, C++14, and C++11 objects 询问有关链接使用不同语言标准编译的对象的问题,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 中空类类型的调用约定更改可能会?

【问题讨论】:

    标签: c++ gcc c++17


    【解决方案1】:

    大多数语言 ABI 更改似乎不会引起问题,但 12 中空类类型的调用约定更改可能会?

    更改空类的调用约定可能会导致 x86-64 出现问题。这是一个例子:

    def.hpp

    struct Empty { };
    
    struct Foo {
        char dummy[16];
        int a;
    
        Foo() : a(42) { }
    };
    
    void fn(Empty, Foo);
    

    one.cpp

    #include "def.hpp"
    
    int main() {
        fn(Empty(), Foo());
    }
    

    两个.cpp

    #include <stdio.h>
    #include "def.hpp"
    
    void fn(Empty e, Foo foo) {
        printf("%d\n", 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 使用寄存器传递,则没有问题。)

    【讨论】:

      【解决方案2】:

      它们中的大多数会以较小的方式改变修饰,这可能会在链接时导致一些未定义的引用,或者由于相同的源代码产生两个具有不同名称的等效符号而导致一些代码膨胀,因此不会被链接器合并。

      12 可能对空类类型的调用约定进行更改?

      是的,当然。如果您有空类型的非最终参数,那么这会影响函数的 ABI,并且差异可能导致未定义的行为(实际上,访问堆栈上的垃圾,或参数获取错误的值)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-30
        • 1970-01-01
        • 2013-01-18
        • 1970-01-01
        • 2011-02-09
        相关资源
        最近更新 更多