Есть ли у C стандартный ABI?

Из обсуждения где-то еще:

C++ не имеет стандартного ABI (бинарного интерфейса приложения).

Но и C тоже, верно?

На любой данной платформе это в значительной степени так. Он не был бы полезен в качестве лингва-франка для межъязыкового общения, если бы его не было.

Что вы думаете об этом?


c abi
person fredoverflow    schedule 20.12.2010    source источник
comment
АБИ? Вы имеете в виду интерфейс прикладного программирования API?   -  person duffymo    schedule 20.12.2010
comment
Я думаю, что OP означает двоичный интерфейс приложения.   -  person doron    schedule 20.12.2010
comment
Нет, ABI как в Application Binary Interface.   -  person Simone    schedule 20.12.2010
comment
Я думаю, что @FredOverflow означает двоичный интерфейс приложения ABI en.wikipedia.org/wiki/Application_binary_interface   -  person Manuel Salvadores    schedule 20.12.2010
comment
Я думаю, что на любой данной платформе это немного многословно, предположительно случайно. Вы могли бы почти определить платформу, используя один и тот же C ABI. В частности, любой определенный формат для динамически загружаемого кода должен определять ABI для вызовов через исполняемые границы. Этот ABI, безусловно, должен поддерживать C, чтобы иметь какое-либо практическое применение (при условии, что люди собираются писать исполняемые файлы на C или C++), и может также поддерживать C++, если вам повезет. Если он поддерживает C, но не C++, вы пишете C++ с extern "C" во всем, что публикуете, и/или используете тот же компилятор для связанных исполняемых файлов.   -  person Steve Jessop    schedule 20.12.2010
comment
Также см. другой, но близкий вопрос: Что может C/C++ «проиграют», если они определят стандартный ABI?   -  person Hibou57    schedule 18.04.2013
comment
Я думаю, что единственный способ узнать намерение OP — это явно спросить их, вы имели в виду бинарный интерфейс приложения? @fredoverflow   -  person jasonleonhard    schedule 03.02.2021
comment
@jasonleonhard 10 лет спустя: Да, я имел в виду двоичный интерфейс приложения.   -  person fredoverflow    schedule 03.02.2021
comment
Лучше поздно, чем никогда. Спасибо за разъяснения.   -  person jasonleonhard    schedule 03.02.2021


Ответы (9)


C не определяет ABI. На самом деле, он из кожи вон лезет, чтобы избежать определения ABI. Те люди, которые, как и я, посвятили большую часть своей жизни программированию на C для 16/32/64-битных архитектур с 8-битными байтами, арифметикой с дополнением до 2 и плоскими адресными пространствами, обычно будут весьма удивлены, прочитав запутанный язык текущий стандарт C.

Например, почитайте про указатели. Стандарт не говорит ничего такого простого, как «указатель — это адрес», поскольку это было бы предположением об ABI. В частности, он позволяет указателям находиться в разных адресных пространствах и иметь разную ширину.

ABI — это сопоставление модели исполнения языка с конкретной комбинацией машины/операционной системы/компилятора. Нет смысла определять его в спецификации языка, потому что это может привести к исключению реализаций C на некоторых архитектурах.

person JeremyP    schedule 20.12.2010
comment
«[…] обычно очень удивятся, прочитав запутанный язык текущего стандарта C.»: с какой версии стандарта? Что касается указателей, я никогда не проверял, разрешено ли это ISO C или нет, но я знаю, что были так называемые модели малой, объемной и средней памяти (средняя была несколько смешанной), которые были известны во времена 16 бит. DOS (много раз работал на 32-битной машине); уже не гарантируется, что указатели всегда будут одного и того же размера. - person Hibou57; 18.04.2013
comment
@ Hibou57 Hibou57, когда я писал ответ, текущим стандартом C был C99. Сомневаюсь, что в C11 многое изменилось. Модели малой, большой и средней памяти не были частью C, но частью большинства реализаций C на архитектуре 8086. - person JeremyP; 24.02.2014
comment
@curiousguy Ну, это может быть индекс в массиве, или это может быть дескриптор, который перенаправляет через таблицу адресов, или это может быть сегмент и смещение, или это может быть тегированный дескриптор. Стандарт C нигде не говорит, что это должен быть адрес. - person JeremyP; 01.01.2020
comment
@JeremyP Сегмент + смещение определяет адрес; разница с чистым адресом заключается в том, что потенциально существует несколько способов указать на один адрес, но он по-прежнему кодирует адрес. Таблица адресов не совместима с арифметикой ptr. - person curiousguy; 01.01.2020
comment
@curiousguy Если вы собираетесь сказать, что все, что можно декодировать в адрес, является адресом, то адресом является все, кроме литерала. Вы делаете слово практически бессмысленным. - person JeremyP; 01.01.2020
comment
@JeremyP Сегмент + смещение - это способ представления адресов с некоторыми режимами адресации памяти; это самый близкий к числовому адресу, который вы могли бы даже использовать, когда у вас даже нет регистра, который может содержать полный числовой адрес. OTOH индекс таблицы адресов может представлять только ограниченное количество адресов и не является ближайшим к адресу на машине. Итак, первое — это адрес, а второе — нет. - person curiousguy; 01.01.2020
comment
@curiousguy Не обязательно. Сегмент не обязательно должен быть базовым адресом сегмента. Это может быть индекс в таблице сегментов. Например, на 8086 это может быть число от 0 до 3, представляющее CS, DS, ES или SS. Однако адреса на 8086 представляют собой 20-битные двоичные числа. - person JeremyP; 04.01.2020
comment
@JeremyP Даже если регистр сегмента является индексом, а не базовым адресом, смещение представляет собой число, которое действительно является относительным адресом. Таким образом, вы можете выполнять арифметику ptr, что невозможно, если ptr представлены в виде индексов в массиве числовых адресов. - person curiousguy; 04.01.2020
comment
@curiousguy Почему бы и нет? - person JeremyP; 06.01.2020

C в принципе не имеет стандартного ABI, но на практике это редко имеет значение: вы делаете то, что делает ваш поставщик ОС.

Возьмем, к примеру, соглашения о вызовах в x86 Windows: Windows API использует так называемое «стандартное» соглашение о вызовах (stdcall). Таким образом, любой компилятор, который хочет взаимодействовать с ОС, должен реализовать это. Однако stdcall поддерживает не все возможности языка C90 (например, вызов функций без прототипов, функции с переменным числом переменных). Поскольку Microsoft предоставила компилятор C, было необходимо второе соглашение о вызовах, называемое соглашением о вызовах 'C' (cdecl). Большинство компиляторов C в Windows используют это как соглашение о вызовах по умолчанию и, таким образом, совместимы.

В принципе, то же самое могло бы случиться и с C++, но поскольку ABI C++ (включая соглашение о вызовах) неизбежно является гораздо более сложным, поставщики компиляторов не договорились о едином ABI, но все же могли взаимодействовать, возвращаясь к extern "C".

person Christoph    schedule 20.12.2010
comment
Это правильно, но недостаточно ясно. Дело не столько в том, что поставщики не договариваются между собой об общем ABI (это может решить комитет по стандартизации). Это больше о том, что один и тот же поставщик не соглашался сам с собой в разное время из-за того, что не всегда предсказывал будущее развитие событий. - person Patrick Fromberg; 05.09.2019

ABI для C специфичен для платформы — он охватывает такие вопросы, как распределение регистров и соглашения о вызовах, которые, очевидно, специфичны для конкретного процессора. Вот некоторые примеры:

x86 имеет много соглашений о вызовах, какие расширения в Windows определяют, какое из них используется. ABI платформы для встроенного Linux также со временем изменились, что привело к несовместимости пользовательского пространства. См. некоторую историю переноса на ARM Linux здесь, которая показывает проблемы при переходе на более новую ABI.

person Adrian Cox    schedule 20.12.2010
comment
Я пошел дальше и удалил неработающую ссылку. - person jasonleonhard; 03.02.2021

ABI, даже для C, имеет части, которые совершенно не зависят от платформы, части, которые зависят от процессора (какие регистры должны быть сохранены, какие используются для передачи параметров,...) и части, которые зависят от ОС (более или менее те же факторы, что и для процессора, поскольку некоторые варианты выбора не навязываются архитектурой, а являются результатом компромиссов, плюс некоторые ОС имеют понятие исключения, не зависящее от языка, и поэтому компилятор для любого языка должен генерировать то, что нужно обрабатывать в этом случае обработка потоков также может накладывать некоторые вещи на ABI — если регистр указывает на TLS, вы не можете использовать его для того, что хотите).

Теоретически у каждого компилятора может быть свой собственный ABI. Но обычно для пары процессор/ОС ABI фиксируется поставщиком ОС, который часто также предоставляет компилятор C и общие библиотеки, которые используют этот ABI, и конкуренты предпочитают быть совместимыми. (Я не удивлюсь, если есть исключения для некоторых ОС, для которых C не является основным языком программирования).

Но поставщик ОС может переключить ABI по той или иной причине (новые версии процессоров могут иметь функции, которые вы хотите использовать в ABI для одной — например, некоторые запросили 32-битный ABI для x86_64, позволяющий использовать все регистры) . На этапе миграции, который может занять очень много времени, вам, возможно, придется обрабатывать два ABI.

person AProgrammer    schedule 20.12.2010

как и C, верно?
Правильно

На любой платформе это почти так и есть. Он не был бы полезен в качестве лингва-франка для межъязыкового общения, если бы его не было.
В значительной степени может относиться к значениям по умолчанию для конкретной архитектуры, выбранным поставщиками компилятора C, которые адаптируются для других языков. . Таким образом, если компилятор Keil ARM C будет использовать порядок параметров с прямым порядком байтов слева направо и стек для передачи аргументов и некоторый заранее определенный регистр для возвращаемого значения, тогда extern «C» из других компиляторов предполагает совместимость с такой схемой.

Хотя такое соглашение можно считать частью ABI, в отличие от контекста управляемого выполнения, такого как песочница браузера JVM, само по себе это далеко не полный стандартный ABI.

person Chawathe Vipul S    schedule 10.04.2013

Хотя было предпринято несколько попыток определить единый ABI для данной архитектуры в нескольких операционных системах (в частности, для i386 в системах Unix), эти усилия не увенчались успехом. Вместо этого операционные системы, как правило, определяют свои собственные ABI...

Цитирование... Системное программирование Linux стр. 4.

person Manuel Salvadores    schedule 20.12.2010

C не имеет стандартного ABI. Это легко проиллюстрировать всеми соглашениями о вызовах (cdecl, fastcall и stdcall), которые там используются. Каждый из них представляет собой отдельный ABI.

person doron    schedule 20.12.2010

До стандарта C89 компиляторы C для многих платформ использовали по существу один и тот же ABI, за исключением различий в размерах данных. Для машин, стек которых растет вниз, код, вызывающий функцию, помещает аргументы в стек по порядку справа налево, а затем вызывает функцию (помещая адрес возврата в процессе). Вызываемая функция оставляет свои аргументы в стеке, а вызывающая сторона на досуге настраивает указатель стека, чтобы удалить их [или, в некоторых архитектурах, может корректировать значения в стеке на месте]. В то время как <stdarg.h> избавил большинство программ от необходимости полагаться на это соглашение, оно использовалось в течение многих лет, потому что было простым и работало довольно хорошо. Хотя не было «официального» документа, устанавливающего, что это кроссплатформенный «стандарт», большинство компиляторов, предназначенных для машин с растущими вниз стеками, работали именно так, что приводило к более высокому уровню согласованности, чем существует сегодня.

person supercat    schedule 09.01.2017
comment
Итак, точно так же, как ABI, только с таким количеством изменений, что не имеет смысла называть его ABI? ;) - person hmijail mourns resignees; 16.07.2017
comment
@hmijail: почти все, кто писал компиляторы C для таких машин, знали бы, что делают другие компиляторы, и следовали бы их примеру, если бы не было причин делать что-то еще. Многие стандарты создаются не органом по стандартизации, а просто процессом, когда один человек делает что-то, а другие делают то же самое. - person supercat; 17.07.2017
comment
Большинство процессоров могут обращаться к регистрам быстрее, чем к стеку, поэтому нет смысла стандартизировать вызов, требующий передачи всех аргументов в стек. И любой метод, который предпочитает передавать аргументы с помощью регистров, очевидно, сильно зависит от аппаратного обеспечения и не может быть стандартным кросс-платформенным. - person Mikko Rantalainen; 21.07.2021

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

Например, даже amd64 (он же x86-64) имеет два соглашения о вызовах: Microsoft x64 и System V AMD64 ABI. Первый помещает 4 первых аргумента в регистры, а остальные в стек. Последний помещает 6 первых аргументов в регистры, а остальные в стек. Я понятия не имею, почему Microsoft создала несовместимое соглашение о вызовах для оборудования amd64. Насколько я знаю, вариант Microsoft имеет немного худшую производительность и был создан позже.

Для получения дополнительной информации см. https://en.wikipedia.org/wiki/X86_calling_conventions.

person Mikko Rantalainen    schedule 21.07.2021