Комментарии 26
Иосиф Крейнин раскрыл тему с полным отсутствием совместимости по ABI даже между разными компиляторами C++ пятнадцать лет назад. С тех пор не изменилось ничего...
Был случай с компилятором от microsoft так получилось, что встретились два модуля один компилировался одной версией компилятора, а второй следующей в линейке. Я уже волосы на себе рвать начал, почему у меня в рантайме все рушится и работает не пойми как, а отладчик показывает какую то невообразимую дичь. И только в дизасемблере заметил, что порядок передачи параметров поменялся на обратный.
Т.е. формально оба компилятора использовали одно соглашение вызова (какое именно не помню), а во факту два разных! И это компилятор от одной компании, просто двух разных поколений.
"Общепринятым соглашением считается передача всех параметров именно через стек." - я бы сказал "считалась". Например в x64-мире принято передавать параметры через регистры. У MS - 4 параметра в RCX, RDX, R8, R9, у System V - больше.
И сходу могу вспомнить про интерфейс к ядру Windows, где все еще чуть более иначе
Еще есть подстава с ABI в которых предполагается что некоторые регистры не изменяются. И в разных ABI это разные регистры.
https://habr.com/ru/articles/703894/
По умолчанию для компиляторов Microsoft и для ABI x64 — да. Но тут речь не про частности, а про общий случай - чтоб и MSVC "переварил" и MinGW и прочие Clang'и. А для этого нужно использовать __cdecl соглашение о вызовах
Последнее, что стоит упомянуть — типы данных. Естественно, речь идет о встроенных типах. В С и С++ размеры типов могут варьироваться в зависимости от платформы. Думаю, не стоит объяснять, что несовместимость по размерам типов делает ABI несовместимым для таких платформ. Классический пример: попробуйте запустить 64-разрядную программу, написанную под Windows x64, в 32-разрядной версии операционки. Вряд ли у вас что-то получится.
Мне кажется вы тут путаете теплое с мягким, 64 битные параметры возможны и в 32-x разрядных приложениях. Также как 32-x разрядные и 64-x разрядные были возможны в 16-и битных. Но сравнивать их в бинарном плане (передается по разному) это как сравнивать два разных процессора с разным набором команд. Понятное дело что нет общего ABI для всех процессоров и каждый процессор устанавливает свои порядки в меньшей степени, а за ним уже операционная система делает это более жестко.
Я так под msvc 32 бита компилировал. Было забавно узнать, что long long тоже превратился в 32 бита, а не заполифилился в два инта. Так что если вы не писали их, то по-умолчанию выше 32 бит на 32-битной платформе не получишь.
Я пишу с 92 года и почему-то таких вот поворотов не встречал. Вы случайно число с указателем не путаете?

В С++ действительно есть типы которые меняют свой размер в зависимости от разрядности приложения, к примеру int и long, это связанно с размерностью регистров по умолчанию и прочими нюансами. Но это также управляемо.
Сейчас уже деталей не помню, но знаю, что определенно сталкивался. Опять же компилятор на godbolt относительно свежий. Тогда это была наверное версия, которая шла с VS Express 2015, или 2017. Там было помимо этого ещё несколько багов компилятора, и кусков 11 стандарта вроде всех не было. Но у нас 32 битный таргет в итоге не использовался, только 64.
Тут речь не про приложения, а про целевую платформу. Цитата Microsoft (https://learn.microsoft.com/ru-ru/windows/win32/winprog64/running-32-bit-applications) отсюда: "Обратите внимание, что 64-разрядная версия Windows не поддерживает запуск 16-разрядных приложений windows. Основная причина заключается в том, что дескриптор имеет 32 значимых бита в 64-разрядной версии Windows. Таким образом, дескрипторы не могут быть усечены и переданы в 16-разрядные приложения без потери данных. Попытки запуска 16-разрядных приложений завершаются сбоем со следующей ошибкой: ERROR_BAD_EXE_FORMAT."
Основная причина заключается в том, что дескриптор имеет 32 значимых бита в 64-разрядной версии Windows.
Отмазки, для 16битных приложений можно было сделать таблицы трансляции. Основная причина сбросить груз ответственности за поддержку этой подсистемы.
Вероятнее всего, реализация возможности запуска 16-битных приложений в новейших версиях Windows слишком трудозатратна и бесперспективна с коммерческой точки зрения. Ресурсов требуется море, а профит оценят только небольшое число энтузиастов. Все-таки Microsoft — коммерческая организация, а Windows — это не open-source проект, поддерживаемый сообществом.
Проблема в процессоре. Процессор, работая в 32-х разрядном режиме может выполнять 16-ти битные инструкции. Процессор, работая в 64-х разрядном режиме может выполнять 32-х битные инструкции, но уже не может выполнять 16-ти битные.
Поэтому во всех 32-х разрядных Windows работают 16-ти битные программы, а в 64-х битных уже нет.
16битные приложение очень скромные по ресурсам и спокойно эмулируются даже на сотовом телефоне.
http://www.columbia.edu/~em36/ntvdmx64.html
https://github.com/leecher1337/ntvdmx64
https://www.vdos.info
https://www.dosbox.com
Суперклей ABI, или Как применять C++ где угодно
Экспортировать только функции с припиской extern "C"
Как раз 30 лет назад для решения проблемы с разными компиляторами и языками придумали COM (Component Object Model).
Это ABI для совместного использования кода плюс инструменты (например, язык для описания интерфейсов).
Статья - полное читерство.
Обычно на руках есть готовая плюсовая либа. В этой либе есть классы и у этих классов есть методы, которые и надо вызывать.
А тут что? Сначала пошли от обратного и условно говоря изменили код "плюсовой" библиотеки. А потом и вовсе extetrn C.
Как использовать C++ библиотеку в других языках? Через боль, страдания и обертки.
Через боль, страдания и обертки.
А когда было легко?
Речь идет не о готовой плюсовой либе, а о расширении функциональности через готовое решение, написанное на С++. Берем этот код, если нужно — вносим необходимые изменения, собираем из него динамическую библиотеку и подключаем к нужному нам проекту. В статье мы пошагово расписали, как это сделать применительно к Java и Python. Про боль и страдания — вопрос субъективный ?
А там внезапно есть FFI
Конечно, есть — он и используется. Ведь механизм FFI (Foreign function interface) и создан для интеграции между языками https://ps-group.github.io/compilers/backend_ffi
В статье получилось не расширить функционал, а изменить с java на python, совсем не универсально, и грустно, что пришлось оба раза что-то дописывать в саму dll... но extern C действительно снимает часть головной боли
Вероятно, для кого-то статья познавательна, однако я не считаю целесообразным делать из готового решения C++ динамическую библиотеку, поскольку вносимые "необходимые изменения" в большинстве случаев могут быть весьма значительными. Упоминание же термина "плагин" не совсем уместно https://ru.wikipedia.org/wiki/Плагин. В любом случае хочу похвалить автора за желание освоить низкоуровневый интерфейс, что неизбежно ведет к повышению качества кода на любом языке
Суперклей ABI, или Как применять C++ где угодно