Безопасно ли связывать объекты gcc 6, gcc 7 и gcc 8? - PullRequest
17 голосов
/ 17 апреля 2019

Безопасно ли связывать объекты C ++ 17, C ++ 14 и C ++ 11 спрашивает о связывании объектов, скомпилированных с различными языковыми стандартами, и превосходный ответ Джонатана Уэйкли на этот вопрос объясняет Стабильность ABI обещает gcc / libstdc ++, чтобы убедить, что это работает.

Есть еще одна вещь, которая может меняться между версиями gcc - язык ABI через -fabi-version. Допустим, для простоты у меня есть три объектных файла:

  • 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 может?

Ответы [ 2 ]

10 голосов
/ 17 апреля 2019

Большинство изменений языка 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());
}

two.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 было передано с использованием регистров, проблем не будет.)

4 голосов
/ 18 апреля 2019

Большинство из них изменяют искажение незначительными способами, что может привести к появлению некоторых неопределенных ссылок при связывании или просто некоторому увеличению объема кода из-за идентичного исходного кода, создающего два эквивалентных символа с разными именами, поэтому компоновщик не будет объединен.

может измениться соглашение о вызовах для пустых типов классов в 12?

Да, определенно.Если у вас есть не окончательные параметры, которые являются пустыми типами, это влияет на ABI для функции, и различия могут привести к неопределенному поведению (на практике, доступ к нежелательной почте в стеке или параметры, получающие неправильные значения).

...