Совместимы ли двоичные файлы (C) с разными компиляторами?

11

Я понимаю, что компиляторы C ++ не совместимы друг с другом. Однако я не смог найти что-либо по этой теме для C, в частности. Я знаю, что стандарт C оставляет много возможностей для реализации компиляторами, как они считают нужным: например, размер и выравнивание большинства (всех?) Типов данных определяется реализацией, за исключением некоторых минимальных гарантий. Следовательно, два компилятора (или две версии одного и того же компилятора) могут не соглашаться по многим деталям.

Правильно ли я считаю, что нет гарантии, что два объектных файла, скомпилированных с разными компиляторами, действительно будут правильно связываться? Например, размер указателей может быть 32 бита в одном объектном файле и 64 бита в другом. Но если это так, почему библиотеки C иногда распространяются в предварительно скомпилированном виде? Ожидается ли, что я буду использовать тот же компилятор, который они использовали (например, gcc), или какой-то де-факто стандарт, используемый для обеспечения двоичной совместимости? И как другие языки с Интерфейсом Иностранных Языков гарантируют, что все будет правильно выстраиваться при связывании с объектными файлами C?

Doval
источник
Насколько я помню, объектные файлы C должны быть совместимы друг с другом, если они скомпилированы для одной и той же платформы. Объектный файл - это просто архив, содержащий загружаемый двоичный код с некоторой таблицей символов, которую можно использовать для доступа к каждому символу внутри модуля.
Джорджио
2
libs можно сделать совместимыми, я не думаю, что obj гарантированно будет
ratchet freak
@Giorgo Под «той же платформой» вы подразумеваете архитектуру процессора или архитектуру процессора + ОС?
Доваль
@ratchetfreak У меня сложилось впечатление, что библиотека - это, по большей части, просто объединение нескольких объектных файлов. Это неправильно?
Доваль
Я не ожидал бы, что объекты будут совместимы между различными компиляторами.
old_timer

Ответы:

10

Общий ответ - нет, компиляторы языка C не совместимы друг с другом. Стандарт языка C не определяет никакой бинарной совместимости, и большинство разработчиков компиляторов даже не пытаются.

Мне нужно это квалифицировать. Объекты, испускаемые компилятором C, должны быть связаны с библиотеками времени выполнения, чтобы создать исполняемый файл или библиотеку времени выполнения. Хотя видимые функции, предоставляемые библиотекой времени выполнения C, должны быть совместимыми, будут также невидимые функции, которые являются уникальными для реализации и препятствуют взаимодействию.

Это отсутствие совместимости распространяется и на разные версии одного и того же компилятора. В общем, программы и библиотеки, скомпилированные с более старыми и новыми версиями компилятора, не могут быть связаны друг с другом, а программы, скомпилированные с помощью MSVC, не могут быть связаны с компилированными GCC.

Есть конкретное и очень полезное исключение. Каждая платформа обеспечивает динамическое связывание ABI (Application Binary Interface) и любой программы на любом языке, который может соответствовать этому ABI, является совместимым. Поэтому, как правило, можно создать DLL (в Windows) с помощью MSVC (или чего-то еще) и вызывать ее из программы, скомпилированной другой версией MSVC или GCC, и наоборот.

В Windows есть два других ABI: сборки COM и .NET, и они охватывают широкий спектр языков. Поэтому совместимость определенно возможна, но совместимы они не могут.


Степень несовместимости легко увидеть, сравнив карты компоновщика. Для использования GNU ld -M, для использования MSVC link /map. Изучите два сгенерированных файла. Оба будут содержать имена, которые вы узнаете, такие как printf и main, хотя (в зависимости от параметров) имена могут быть искажены различными способами. У них также будут совершенно разные имена, многие из которых вы не узнаете. Для того, чтобы объектные файлы, созданные разными компиляторами, были совместимыми, они должны согласовать все эти имена, и они никогда этого не делают. Даже разные версии одного и того же компилятора не всегда могут это сделать.

david.pfx
источник
Этот ответ, кажется, противоречит ответу Барта ; Похоже, что только общие библиотеки совместимы. Не могли бы вы объяснить, почему невидимые, специфичные для реализации функции библиотеки времени выполнения C предотвращают взаимодействие? Вы также говорите, что «объекты, испускаемые компилятором C, должны быть связаны с библиотеками времени выполнения для создания исполняемой или библиотеки времени выполнения» - как насчет статических библиотек?
Доваль
Как сказал Барт, совместимы только библиотеки с ABI. Общие библиотеки (в Unix) являются одним из видов ABI, есть и другие. Напишите HelloWorld.c, скомпилируйте его с помощью MSVC и gcc, сравните карты, и вы увидите, насколько они отличаются. «Библиотеки времени выполнения» означают основные вспомогательные функции, на которые автоматически ссылается каждый компилятор C / C ++, которые могут быть статически или динамически связаны. Прочитайте карту или исходный код CRT, чтобы увидеть их.
david.pfx
Я не знаю, что означает сравнение карт, поэтому я буду более конкретным: можно ли на практике предполагать, что все компиляторы для данной комбинации архитектуры ЦП и ОС совместимы? Например, у меня есть main.c, который я компилирую с помощью gcc, и mylibrary.c, который я компилирую с помощью clang, оба ориентированы на Linux x64. Если предположить, что достаточно распространенная ОС (Linux, Mac, Windows), можно ли предположить, что она будет работать независимо от того, что представляют собой два компилятора?
Доваль
1
Весьма маловероятно, проверьте карту лягушатника. Смотрите редактировать.
david.pfx
17

То, что вы ищете, называется ABI (Application Binary Interface).

Язык C не определяет ABI, поэтому в этом смысле действительно нет никакой гарантии, что файлы C, скомпилированные с разными компиляторами, будут работать друг с другом.

С другой стороны, на большинстве платформ ОС определяет ABI для взаимодействия с ним, и все компиляторы, предназначенные для этого семейства ОС и процессоров, также используют тот же ABI для взаимодействия с не-ОС компонентами. Таким образом, на практике объекты C, созданные разными компиляторами, могут работать друг с другом.

Барт ван Инген Шенау
источник
Это имеет смысл. Я так понимаю, разделяемые библиотеки тоже следуют ABI ОС?
Доваль
3
@Doval Особенно разделяемые библиотеки, они должны вызываться внешним миром.
toasted_flakes