Я никогда не понимал, что такое ABI. Пожалуйста, не указывайте мне статью в Википедии. Если бы я мог это понять, я бы не стал публиковать такие длинные сообщения.
Это мое мышление о различных интерфейсах:
Пульт дистанционного управления - это интерфейс между пользователем и телевизором. Это существующий объект, но сам по себе бесполезный (не предоставляет никакой функциональности). Все функции каждой из кнопок на пульте реализованы в телевизоре.
Интерфейс: это слой «существующей сущности» между
functionality
иconsumer
этой функциональностью. Интерфейс сам по себе ничего не делает. Это просто вызывает функциональность, лежащую позади.Теперь в зависимости от того, кто пользователь, существуют различные типы интерфейсов.
Команды интерфейса командной строки (CLI) являются существующими объектами, потребитель является пользователем, а функциональность скрывается за ним.
functionality:
мой программный функционал, который решает какую-то цель, для которой мы описываем этот интерфейс.
existing entities:
команды
consumer:
пользовательОкно графического интерфейса пользователя (GUI) , кнопки и т. Д. Являются существующими объектами, и опять-таки пользователь является пользователем, а функциональность остается позади.
functionality:
моя функциональность программного обеспечения, которая решает некоторую проблему, к которой мы описываем этот интерфейс.
existing entities:
окно, кнопки и т. д.
consumer:
пользовательФункции интерфейса прикладного программирования (API) (или, если быть более точным), интерфейсы (в интерфейсном программировании) являются существующими объектами, потребитель здесь - другая программа, а не пользователь, и опять-таки функциональность находится за этим уровнем.
functionality:
моя функциональность программного обеспечения, которая решает некоторую проблему, к которой мы описываем этот интерфейс.
existing entities:
функции, интерфейсы (массив функций).
consumer:
другая программа / приложение.Двоичный интерфейс приложения (ABI) Вот где начинается моя проблема.
functionality:
???
existing entities:
???
consumer:
???
- Я написал программное обеспечение на разных языках и предоставил различные виды интерфейсов (CLI, GUI и API), но я не уверен, что когда-либо предоставлял ABI.
ABI охватывает такие детали, как
- тип данных, размер и выравнивание;
- соглашение о вызовах, которое управляет передачей аргументов функций и получением возвращаемых значений;
- номера системных вызовов и как приложение должно выполнять системные вызовы операционной системы;
Другие ABI стандартизируют детали, такие как
- искажение имени в C ++,
- распространение исключений и
- Соглашение о вызовах между компиляторами на одной платформе, но не требует кросс-платформенной совместимости.
Кому нужны эти детали? Пожалуйста, не говорите ОС. Я знаю ассемблерное программирование. Я знаю, как работают ссылки и загрузка. Я точно знаю, что происходит внутри.
Почему в C ++ появилось искажение имен? Я думал, что мы говорим на двоичном уровне. Почему языки входят?
В любом случае, я скачал [PDF] System V Application Binary Interface Edition 4.1 (1997-03-18), чтобы увидеть, что именно в нем содержится. Ну, большая часть этого не имела никакого смысла.
Почему он содержит две главы (4-ю и 5-ю) для описания формата файла ELF ? Фактически, это только две важные главы этой спецификации. Остальные главы посвящены «процессору». Во всяком случае, я думаю, что это совершенно другая тема. Пожалуйста, не говорите, что спецификации формата файлов ELF являются ABI. Это не может быть интерфейсом в соответствии с определением.
Я знаю, поскольку мы говорим на таком низком уровне, он должен быть очень конкретным. Но я не уверен, как это специфично для "архитектуры набора команд (ISA)"?
Где я могу найти Microsoft Windows ABI?
Итак, вот основные запросы, которые меня беспокоят.
Ответы:
Один простой способ понять «ABI» - это сравнить его с «API».
Вы уже знакомы с концепцией API. Если вы хотите использовать функции, скажем, некоторой библиотеки или вашей ОС, вы будете программировать с использованием API. API состоит из типов / структур данных, констант, функций и т. Д., Которые вы можете использовать в своем коде для доступа к функциональности этого внешнего компонента.
ABI очень похож. Думайте об этом как о скомпилированной версии API (или как API на уровне машинного языка). Когда вы пишете исходный код, вы получаете доступ к библиотеке через API. Как только код скомпилирован, ваше приложение получает доступ к двоичным данным в библиотеке через ABI. ABI определяет структуры и методы, которые ваше скомпилированное приложение будет использовать для доступа к внешней библиотеке (как это делал API), только на более низком уровне. Ваш API определяет порядок, в котором вы передаете аргументы функции. Ваш ABI определяет механику того, какэти аргументы передаются (регистры, стек и т. д.). Ваш API определяет, какие функции являются частью вашей библиотеки. Ваш ABI определяет, как ваш код хранится в файле библиотеки, так что любая программа, использующая вашу библиотеку, может найти нужную функцию и выполнить ее.
ABI важны, когда дело касается приложений, использующих внешние библиотеки. Библиотеки полны кода и других ресурсов, но ваша программа должна знать, как найти то, что ей нужно, внутри файла библиотеки. Ваш ABI определяет, как содержимое библиотеки хранится внутри файла, а ваша программа использует ABI для поиска в файле и поиска того, что ему нужно. Если все в вашей системе соответствует одному и тому же ABI, то любая программа может работать с любым библиотечным файлом, независимо от того, кто его создал. Linux и Windows используют разные ABI, поэтому программа Windows не знает, как получить доступ к библиотеке, скомпилированной для Linux.
Иногда изменения ABI неизбежны. Когда это происходит, любые программы, использующие эту библиотеку, не будут работать, если они не будут перекомпилированы для использования новой версии библиотеки. Если ABI изменяется, а API - нет, то старые и новые версии библиотеки иногда называют «совместимыми с исходным кодом». Это подразумевает, что, хотя программа, скомпилированная для одной версии библиотеки, не будет работать с другой, исходный код, написанный для одной версии, будет работать для другой, если перекомпилируется.
По этой причине разработчики стремятся поддерживать стабильный уровень своего ABI (чтобы минимизировать сбои). Поддержание стабильности ABI означает не изменение интерфейсов функций (возвращаемый тип и число, типы и порядок аргументов), определения типов данных или структур данных, определенные константы и т. Д. Можно добавлять новые функции и типы данных, но существующие должны оставаться то же. Если, например, ваша библиотека использует 32-разрядные целые числа для обозначения смещения функции и вы переключаетесь на 64-разрядные целые числа, то уже скомпилированный код, использующий эту библиотеку, не будет правильно обращаться к этому полю (или любому следующему за ним) , Доступ к членам структуры данных преобразуется в адреса и смещения памяти во время компиляции, и если структура данных изменяется,
ABI - это не обязательно то, что вы будете явно предоставлять, если только вы не занимаетесь проектированием систем очень низкого уровня. Это также не зависит от языка, поскольку (например) приложение C и приложение Pascal могут использовать один и тот же ABI после их компиляции.
Редактировать:Относительно вашего вопроса о главах, касающихся формата файлов ELF в документах ABI SysV: причина, по которой эта информация включена, заключается в том, что формат ELF определяет интерфейс между операционной системой и приложением. Когда вы указываете ОС запускать программу, она ожидает, что программа будет отформатирована определенным образом, и (например) ожидает, что первый раздел двоичного файла будет заголовком ELF, содержащим определенную информацию с определенными смещениями памяти. Так приложение передает важную информацию о себе в операционную систему. Если вы создаете программу в двоичном формате, отличном от ELF (например, a.out или PE), то ОС, которая ожидает приложения в формате ELF, не сможет интерпретировать двоичный файл или запустить приложение.
IIRC, Windows в настоящее время использует формат Portable Executable (или PE). В разделе «Внешние ссылки» этой страницы Википедии есть ссылки с дополнительной информацией о формате PE.
Также, что касается вашей заметки об искажении имен в C ++: при поиске функции в файле библиотеки функцию обычно ищут по имени. C ++ позволяет перегружать имена функций, поэтому одного имени недостаточно для идентификации функции. Компиляторы C ++ имеют свои собственные способы решения этой проблемы, называемые искажениями имен . ABI может определить стандартный способ кодирования имени функции, чтобы программы, созданные на другом языке или компиляторе, могли найти то, что им нужно. Когда вы используете программу
extern "c"
на C ++, вы указываете компилятору использовать стандартизированный способ записи имен, понятный для другого программного обеспечения.источник
Если вы знаете сборку и как все работает на уровне ОС, вы соответствуете определенному ABI. ABI управляет такими вещами, как передача параметров, размещение возвращаемых значений. Для многих платформ есть только один ABI на выбор, и в этих случаях ABI просто «как все работает».
Тем не менее, ABI также управляет такими вещами, как классы / объекты в C ++. Это необходимо, если вы хотите иметь возможность передавать ссылки на объекты через границы модуля или если вы хотите смешивать код, скомпилированный с разными компиляторами.
Кроме того, если у вас есть 64-разрядная ОС, которая может выполнять 32-разрядные двоичные файлы, у вас будут разные ABI для 32- и 64-разрядного кода.
Как правило, любой код, который вы ссылаете на один и тот же исполняемый файл, должен соответствовать одному и тому же ABI. Если вы хотите обмениваться данными между кодами, используя разные ABI, вы должны использовать протокол RPC или сериализацию.
Я думаю, что вы слишком усердно пытаетесь втиснуть различные типы интерфейсов в фиксированный набор характеристик. Например, интерфейс не обязательно должен быть разделен на потребителей и производителей. Интерфейс - это просто соглашение, по которому взаимодействуют два объекта.
ABI могут быть (частично) ISA-независимыми. Некоторые аспекты (такие как соглашения о вызовах) зависят от ISA, в то время как другие аспекты (такие как макет класса C ++) не зависят.
Хорошо определенный ABI очень важен для людей, пишущих компиляторы. Без четко определенного ABI было бы невозможно генерировать совместимый код.
РЕДАКТИРОВАТЬ: Некоторые примечания, чтобы уточнить:
источник
Тебе вообще не нужен ABI, если ...
Упрощенное резюме:
ABI - это набор правил, которых придерживаются компиляторы и компоновщики, чтобы скомпилировать вашу программу, чтобы она работала правильно. ABI охватывают несколько тем:
Более подробно рассмотрим соглашение о вызовах, которое я считаю основой ABI:
Сама машина не имеет понятия «функции». Когда вы пишете функцию на языке высокого уровня, таком как c, компилятор генерирует строку кода ассемблера, например
_MyFunction1:
. Это метка , которая в конечном итоге будет преобразована ассемблером в адрес. Эта метка отмечает «начало» вашей «функции» в коде сборки. В высокоуровневом коде, когда вы «вызываете» эту функцию, то, что вы действительно делаете, заставляет ЦП перейти на адрес этой метки и продолжить выполнение там.При подготовке к прыжку компилятор должен сделать кучу важных вещей. Соглашение о вызовах похоже на контрольный список, который следует компилятору для выполнения всего этого:
_MyFunction1:
). На этом этапе вы можете считать, что процессор находится «в» вашей «функции».Существует много различных ABI / соглашений о вызовах. Некоторые основные из них:
Вот отличная страница, которая фактически показывает различия в сборке, генерируемой при компиляции для различных ABI.
Другое дело упоминания о том , что ABI имеет значение не только внутри исполняемого модуля вашей программы. Он также используется компоновщиком, чтобы убедиться, что ваша программа правильно вызывает библиотечные функции. У вас есть несколько общих библиотек, работающих на вашем компьютере, и, пока ваш компилятор знает, какой ABI они используют, он может правильно вызывать функции из них, не разрушая стек.
Ваш компилятор понимает, как вызывать библиотечные функции, чрезвычайно важно. На размещенной платформе (то есть той, где ОС загружает программы), ваша программа не может даже мигать без вызова ядра.
источник
Двоичный интерфейс приложения (ABI) похож на API, но функция недоступна для вызывающей стороны на уровне исходного кода. Только двоичное представление доступно / доступно.
ABI могут быть определены на уровне архитектуры процессора или на уровне ОС. ABI - это стандарты, которым должна следовать фаза генерации кода компилятора. Стандарт фиксируется либо ОС, либо процессором.
Функциональность: Определите механизм / стандарт, чтобы сделать вызовы функций независимыми от языка реализации или конкретного компилятора / компоновщика / цепочки инструментов. Предоставьте механизм, который позволяет JNI или интерфейс Python-C и т. Д.
Существующие объекты: функции в форме машинного кода.
Потребитель: другая функция (в том числе на другом языке, скомпилированная другим компилятором или связанная другим компоновщиком).
источник
Функциональность: набор контрактов, которые влияют на компилятор, составители сборок, компоновщик и операционную систему. Контракты определяют, как распределяются функции, где передаются параметры, как передаются параметры, как работает функция. Они обычно относятся к кортежу (архитектура процессора, операционная система).
Существующие сущности: расположение параметров, семантика функций, распределение регистров. Например, архитектура ARM имеет множество ABI (APCS, EABI, GNU-EABI, не говоря уже о куче исторических случаев) - использование смешанного ABI приведет к тому, что ваш код просто не будет работать при вызове через границы.
Потребитель: Компилятор, сборщики, операционная система, специфичная для процессора архитектура.
Кому нужны эти детали? Компилятор, сборщики, компоновщики, которые выполняют генерацию кода (или требования выравнивания), операционную систему (обработка прерываний, интерфейс syscall). Если вы занимались программированием на ассемблере, вы соответствовали ABI!
Перенаправление имен в C ++ является особым случаем - проблема, связанная с компоновщиком и динамическим компоновщиком, - если искажение имени не стандартизировано, динамическое связывание не будет работать. Отныне C ++ ABI называется именно так, C ++ ABI. Это не проблема уровня компоновщика, а проблема генерации кода. Если у вас есть бинарный файл C ++, невозможно сделать его совместимым с другим ABI C ++ (искажение имени, обработка исключений) без перекомпиляции из исходного кода.
ELF - это формат файла для использования загрузчика и динамического компоновщика. ELF является контейнерным форматом для двоичного кода и данных, и как таковой определяет ABI части кода. Я бы не стал считать ELF ABI в строгом смысле, так как исполняемые файлы PE не являются ABI.
Все ABI специфичны для набора команд. ARM ABI не будет иметь смысла на процессоре MSP430 или x86_64.
В Windows есть несколько ABI - например, fastcall и stdcall - это два ABI общего назначения. Системный вызов ABI снова отличается.
источник
Позвольте мне хотя бы ответить на часть вашего вопроса. С примером того, как Linux ABI влияет на системные вызовы, и почему это полезно.
Системный вызов - это способ для программы пользовательского пространства запросить что-либо в пространстве ядра. Он работает, помещая числовой код для вызова и аргумента в определенный регистр и вызывая прерывание. Затем происходит переключение в пространство ядра, и ядро просматривает числовой код и аргумент, обрабатывает запрос, помещает результат обратно в регистр и запускает переключение обратно в пространство пользователя. Это необходимо, например, когда приложение хочет выделить память или открыть файл (системные вызовы "brk" и "open").
Теперь системные вызовы имеют короткие имена "brk" и т. Д. И соответствующие коды операций, которые определены в системном заголовочном файле. Пока эти коды операций остаются прежними, вы можете запускать одни и те же скомпилированные пользовательские программы с разными обновленными ядрами без необходимости перекомпиляции. Таким образом, у вас есть интерфейс, используемый предварительно скомпилированными бинарными файлами, отсюда и ABI.
источник
Чтобы вызвать код в общих библиотеках или код вызова между блоками компиляции, объектный файл должен содержать метки для вызовов. C ++ изменяет имена меток методов для обеспечения скрытия данных и допускает перегруженные методы. Вот почему вы не можете смешивать файлы из разных компиляторов C ++, если они явно не поддерживают один и тот же ABI.
источник
Лучший способ различить ABI и API - это знать, для чего и для чего он используется:
Для x86-64 обычно есть один ABI (а для x86 32-bit есть другой набор):
http://www.x86-64.org/documentation/abi.pdf
https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html
http://people.freebsd.org/~obrien/amd64-elf-abi.pdf
Linux + FreeBSD + MacOSX следуют за ним с некоторыми небольшими изменениями. И Windows x64 имеет свой собственный ABI:
http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/
Зная ABI и предполагая, что за ним следует и другой компилятор, тогда двоичные файлы теоретически знают, как вызывать друг друга (в частности, API библиотек) и передавать параметры через стек или через регистры и т. Д. Или какие регистры будут изменены при вызове функций и т. Д. По сути, эти знания помогут программному обеспечению интегрироваться друг с другом. Зная порядок расположения регистров / стека, я могу без особых проблем собрать воедино различные программы, написанные на сборках.
Но API разные:
Это имена функций высокого уровня с определенным аргументом, так что если различные части программного обеспечения создаются с использованием этих API, МОГУТ иметь возможность вызывать друг друга. Но необходимо соблюдать дополнительное требование ЖЕ АБИ.
Например, Windows раньше была POSIX API-совместимой:
https://en.wikipedia.org/wiki/Windows_Services_for_UNIX
https://en.wikipedia.org/wiki/POSIX
И Linux также совместим с POSIX. Но двоичные файлы нельзя просто переместить и запустить сразу. Но поскольку они использовали одни и те же NAMES в POSIX-совместимом API, вы можете взять одно и то же программное обеспечение на C, перекомпилировать его в другой ОС и сразу запустить.
API предназначены для облегчения интеграции программного обеспечения - этап предварительной компиляции. Таким образом, после компиляции программное обеспечение может выглядеть совершенно иначе - если ABI отличаются.
ABI предназначены для определения точной интеграции программного обеспечения на уровне двоичного кода / сборки.
источник
SYS_execve
11 на 32-битной Linux, но 59 на FreeBSD.personality(2)
можно установитьPER_BSD
. Я думаю, что помню, как все время виделpersonality(PER_LINUX)
вstrace
выводе, но современные 64-битные двоичные файлы Linux больше этого не делают.Пример минимально работающей ABI для общей библиотеки Linux
В контексте разделяемых библиотек наиболее важным следствием «наличия стабильного ABI» является то, что вам не нужно перекомпилировать свои программы после изменений библиотеки.
Так, например:
если вы продаете разделяемую библиотеку, вы избавляете своих пользователей от необходимости перекомпилировать все, что зависит от вашей библиотеки, для каждого нового выпуска
Если вы продаете программу с закрытым исходным кодом, которая зависит от общей библиотеки, присутствующей в дистрибутиве пользователя, вы можете выпустить и протестировать меньше предварительных сборок, если вы уверены, что ABI стабилен в определенных версиях целевой ОС.
Это особенно важно в случае стандартной библиотеки C, на которую ссылаются многие программы в вашей системе.
Теперь я хочу предоставить минимальный конкретный работоспособный пример этого.
main.c
mylib.c
mylib.h
Компилируется и работает нормально с:
Теперь предположим, что для v2 библиотеки мы хотим добавить новое поле для
mylib_mystruct
вызываемогоnew_field
.Если мы добавили поле до того,
old_field
как в:и восстановить библиотеку, но нет
main.out
, тогда утверждение не удается!Это потому что строка:
сгенерировал сборку, которая пытается получить доступ к самой первой
int
структуре, которая теперьnew_field
вместо ожидаемойold_field
.Поэтому это изменение сломало ABI.
Если, однако, мы добавим
new_field
послеold_field
:тогда старая сгенерированная сборка все еще обращается к первой
int
структуре, и программа все еще работает, потому что мы сохранили ABI стабильным.Вот полностью автоматизированная версия этого примера на GitHub .
Другим способом сохранения стабильности ABI было бы рассматривать его
mylib_mystruct
как непрозрачную структуру и обращаться к ее полям только через помощников методов. Это облегчает поддержание стабильности ABI, но может повлечь за собой снижение производительности, поскольку мы выполняем больше вызовов функций.API против ABI
В предыдущем примере интересно отметить, что добавление
new_field
ранееold_field
только нарушало ABI, но не API.Это означает, что если бы мы перекомпилировали нашу
main.c
программу для библиотеки, она работала бы независимо.Однако мы бы также нарушили API, если бы изменили, например, сигнатуру функции:
так как в этом случае
main.c
перестанет компилироваться вообще.Семантический API против API программирования
Мы также можем классифицировать изменения API по третьему типу: семантические изменения.
Семантический API, как правило, представляет собой естественное описание того, что должен делать API, обычно включается в документацию API.
Поэтому возможно нарушить семантический API, не нарушая саму сборку программы.
Например, если мы изменили
чтобы:
тогда это не нарушило бы ни API программирования, ни ABI, но
main.c
семантический API сломался бы.Существует два способа программной проверки API контракта:
формальная проверка . Сложнее сделать, но производит математическое доказательство правильности, по существу объединяя документацию и тесты в «человеческий» / машинно проверяемый способ! Пока, конечно, в вашем официальном описании нет ошибки ;-)
Эта концепция тесно связана с формализацией самой математики: /math/53969/what-does-formal-mean/3297537#3297537
Список всего, что нарушает C / C ++ разделяемые библиотеки ABI
TODO: найти / создать окончательный список:
Пример минимального запуска Java
Что такое двоичная совместимость в Java?
Протестировано в Ubuntu 18.10, GCC 8.2.0.
источник
ABI должен быть согласованным между вызывающим абонентом и вызываемым абонентом, чтобы быть уверенным, что вызов успешен. Использование стека, использование регистра, всплывающее окно в конце процедуры. Все это самые важные части ABI.
источник
Резюме
Существуют различные толкования и точные мнения о точном слое, которые определяют ABI (двоичный интерфейс приложения).
На мой взгляд, ABI - это субъективное соглашение о том, что считать данной платформой для конкретного API. ABI - это «остальная часть» соглашений, которые «не изменятся» для конкретного API или будут решаться средой выполнения: исполнителями, инструментами, компоновщиками, компиляторами, jvm и ОС.
Определение интерфейса : ABI, API
Если вы хотите использовать библиотеку типа joda-time, вы должны объявить зависимость от
joda-time-<major>.<minor>.<patch>.jar
. Библиотека следует передовым методам и использует семантическое управление версиями . Это определяет совместимость API на трех уровнях:Чтобы вы могли использовать новый основной выпуск той же библиотеки, нужно соблюдать множество других соглашений:
Примеры
Пример использования Java
Например, Java стандартизировал все эти соглашения не в инструменте, а в формальной спецификации JVM. Спецификация позволила другим поставщикам предоставить другой набор инструментов, которые могут выводить совместимые библиотеки.
Java предоставляет два других интересных примера для ABI: версии Scala и виртуальная машина Dalvik .
Виртуальная машина Dalvik сломала ABI
Виртуальная машина Dalvik нуждается в байт-коде другого типа, чем байт-код Java. Библиотеки Dalvik получены путем преобразования байт-кода Java (с тем же API) для Dalvik. Таким образом, вы можете получить две версии одного и того же API: определенные оригиналом
joda-time-1.7.2.jar
. Мы могли бы назвать меняjoda-time-1.7.2.jar
иjoda-time-1.7.2-dalvik.jar
. Они используют другой ABI, один для стекового ориентированного стандартного Java vms: Oracle, IBM, open Java или любой другой; и второй ABI - тот, что вокруг Dalvik.Последовательные выпуски Scala несовместимы
Scala не имеет двоичной совместимости между второстепенными версиями Scala: 2.X. По этой причине один и тот же API "io.reactivex" %% "rxscala"% "0.26.5" имеет три версии (в будущем больше): для Scala 2.10, 2.11 и 2.12. Что изменилось? Пока не знаю , но двоичные файлы не совместимы. Вероятно, в последних версиях добавлены вещи, которые делают библиотеки непригодными для использования на старых виртуальных машинах, возможно, вещи, связанные с соглашениями о связывании / именовании / параметрах.
Последовательные выпуски Java несовместимы
У Java также есть проблемы с основными выпусками JVM: 4,5,6,7,8,9. Они предлагают только обратную совместимость. Jvm9 знает, как запускать код, скомпилированный / нацеленный (
-target
опция javac ) для всех других версий, в то время как JVM 4 не знает, как запускать код, нацеленный на JVM 5. Все это, пока у вас есть одна библиотека joda. Эта несовместимость вылетает из радара благодаря различным решениям:Почему я начал с определения API?
API и ABI - это просто соглашения о том, как вы определяете совместимость. Нижние уровни являются общими для множества семантики высокого уровня. Вот почему легко сделать некоторые соглашения. Первый тип соглашений касается выравнивания памяти, байтового кодирования, соглашений о вызовах, кодировок с прямым и прямым порядком байтов и т. Д. Помимо них вы получаете исполняемые соглашения, подобные описанным выше, соглашения о связывании, промежуточный байт-код, такой как тот, который используется Java или LLVM IR используется GCC. В-третьих, вы получаете соглашения о том, как найти библиотеки, как их загрузить (см. Загрузчики классов Java). По мере того, как вы будете подниматься выше и выше в концепциях, у вас появляются новые соглашения, которые вы рассматриваете как данность. Вот почему они не добрались до семантического контроля версий .версия. Мы могли бы изменить семантическое управление версиями с помощью
<major>-<minor>-<patch>-<platform/ABI>
. Это то , что на самом деле происходит уже: платформа ужеrpm
,dll
,jar
(JVM байт - код),war
(JVM + веб - сервер),apk
,2.11
(специфическая Scala версия) и так далее. Когда вы говорите APK, вы уже говорите об определенной части ABI вашего API.API можно портировать на разные ABI
Верхний уровень абстракции (источники, написанные на основе самого высокого API, могут быть перекомпилированы / перенесены на любую другую низкоуровневую абстракцию.
Допустим, у меня есть несколько источников для rxscala. Если инструменты Scala будут изменены, я могу перекомпилировать их. Если JVM изменится, у меня могут быть автоматические преобразования из старой машины в новую, не заботясь о концепциях высокого уровня. Хотя портировать может быть сложно, поможет любой другой клиент. Если новая операционная система создается с использованием совершенно другого ассемблерного кода, можно создать переводчик.
API перенесены на разные языки
Существуют API, которые портированы на несколько языков, таких как реактивные потоки . В целом они определяют сопоставления с конкретными языками / платформами. Я бы сказал, что API - это основная спецификация, формально определенная на человеческом языке или даже на конкретном языке программирования. Все остальные «отображения» в некотором смысле являются ABI, иначе API, чем обычный ABI. То же самое происходит с интерфейсами REST.
источник
Короче говоря, и в философии, только вещи вроде могут хорошо ладить, и ABI можно рассматривать как вид программного обеспечения, работающего вместе.
источник
Я также пытался понять ABI, и ответ JesperE был очень полезным.
С очень простой точки зрения, мы можем попытаться понять ABI, рассматривая двоичную совместимость.
Вики KDE определяет библиотеку как двоичную, совместимую «если программа, динамически связанная с предыдущей версией библиотеки, продолжает работать с более новыми версиями библиотеки без необходимости перекомпиляции». Для получения дополнительной информации о динамическом связывании см. Статическое связывание против динамического связывания.
Теперь давайте попробуем взглянуть только на самые основные аспекты, необходимые для двоичной совместимости библиотеки (при условии, что в библиотеке нет изменений исходного кода):
Конечно, есть много других деталей, но это в основном то, что ABI также охватывает.
Более конкретно, чтобы ответить на ваш вопрос, из вышесказанного можно сделать вывод:
Надеюсь это поможет!
источник
Двоичный интерфейс приложения (ABI)
Функциональные возможности:
Существующие объекты:
потребитель:
Они нужны всем, кто должен обеспечить, чтобы цепочки инструментов сборки работали в целом. Если вы пишете один модуль на ассемблере, другой на Python и вместо собственного загрузчика хотите использовать операционную систему, тогда ваши «прикладные» модули работают через «двоичные» границы и требуют согласования такого «интерфейса».
Искаженное имя в C ++, потому что в вашем приложении могут потребоваться ссылки на объектные файлы из разных языков высокого уровня. Рассмотрите возможность использования стандартной библиотеки GCC для выполнения системных вызовов Windows, созданных с помощью Visual C ++.
ELF - одно из возможных ожиданий компоновщика от объектного файла для интерпретации, хотя у JVM может быть другая идея.
Для приложения Windows RT Store попробуйте поискать ARM ABI, если вы действительно хотите, чтобы какая-то сборка инструментов работала вместе.
источник
Термин ABI используется для обозначения двух разных, но связанных понятий.
Говоря о компиляторах, это относится к правилам, используемым для перевода из конструкций исходного уровня в двоичные конструкции. Насколько велики типы данных? как работает стек? как передать параметры в функции? какие регистры должны быть сохранены вызывающим абонентом против вызываемого абонента?
Когда речь идет о библиотеках, это относится к двоичному интерфейсу, представленному скомпилированной библиотекой. Этот интерфейс является результатом ряда факторов, включая исходный код библиотеки, правила, используемые компилятором, а в некоторых случаях определения, взятые из других библиотек.
Изменения в библиотеке могут нарушить ABI, не нарушая API. Рассмотрим, например, библиотеку с интерфейсом вроде.
и прикладной программист пишет код как
Программист приложения не заботится о размере или структуре FOO, но двоичный файл приложения заканчивается жестко заданным размером foo. Если программист библиотеки добавляет дополнительное поле в foo, и кто-то использует новый двоичный файл библиотеки со старым двоичным файлом приложения, то библиотека может получить доступ к памяти за пределами границ.
OTOH, если автор библиотеки разработал свой API как.
и прикладной программист пишет код как
Тогда бинарному приложению не нужно ничего знать о структуре FOO, которая может быть скрыта внутри библиотеки. Однако цена, которую вы платите за это, заключается в том, что в этом участвует куча операций.
источник
ABI
-Application Binary Interface
об обмене машинным кодом во время выполнения между двумя частями двоичной программы, такими как: приложение, библиотека, ОС ...ABI
описывает, как объекты сохраняются в памяти и как вызываются функции (calling convention
)Хорошим примером API и ABI является экосистема iOS с языком Swift .
Application
- При создании приложения на разных языках. Например , вы можете создать приложение , используяSwift
иObjective-C
[Mixing Swift и Objective-C]Application - OS
- runtime -Swift runtime
иstandard libraries
являются частями ОС, и их не следует включать в каждый пакет (например, приложение, инфраструктуру). Это то же самое, что и в Objective-CLibrary
-Module Stability
case - время компиляции - вы сможете импортировать фреймворк, который был собран с другой версией компилятора Swift. Это означает, что безопасно создавать двоичный файл с закрытым исходным кодом (перед сборкой), который будет использоваться другой версией компилятора (.swiftinterface
используется с.swiftmodule
), и вы не получитеLibrary
-Library Evolution
чехол[API против ABI]
источник