Как стать автором
Обновить

Комментарии 26

Иосиф Крейнин раскрыл тему с полным отсутствием совместимости по ABI даже между разными компиляторами C++ пятнадцать лет назад. С тех пор не изменилось ничего...

Был случай с компилятором от microsoft так получилось, что встретились два модуля один компилировался одной версией компилятора, а второй следующей в линейке. Я уже волосы на себе рвать начал, почему у меня в рантайме все рушится и работает не пойми как, а отладчик показывает какую то невообразимую дичь. И только в дизасемблере заметил, что порядок передачи параметров поменялся на обратный.

Т.е. формально оба компилятора использовали одно соглашение вызова (какое именно не помню), а во факту два разных! И это компилятор от одной компании, просто двух разных поколений.

"Общепринятым соглашением считается передача всех параметров именно через стек." - я бы сказал "считалась". Например в x64-мире принято передавать параметры через регистры. У MS - 4 параметра в RCX, RDX, R8, R9, у System V - больше.

И сходу могу вспомнить про интерфейс к ядру Windows, где все еще чуть более иначе

Еще есть подстава с ABI в которых предполагается что некоторые регистры не изменяются. И в разных ABI это разные регистры.
https://habr.com/ru/articles/703894/

Наверное, я не обращал внимания на XMM-регистры. Или и правда не встречал функций, которые бы сильно расчитывали на сохранность XMM-регистров

По умолчанию для компиляторов 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

Да — но данная конструкция всего лишь отключает искажение имен (Name Mangling) для С++ кода (в С, напомню, ничего подобного нет). Но ничего не говорит о Calling Convention, то есть о технических особенностях вызова (cdecl это или скажем stdcall)

Как раз 30 лет назад для решения проблемы с разными компиляторами и языками придумали COM (Component Object Model).
Это ABI для совместного использования кода плюс инструменты (например, язык для описания интерфейсов).

Статья - полное читерство.

Обычно на руках есть готовая плюсовая либа. В этой либе есть классы и у этих классов есть методы, которые и надо вызывать.

А тут что? Сначала пошли от обратного и условно говоря изменили код "плюсовой" библиотеки. А потом и вовсе extetrn C.

Как использовать C++ библиотеку в других языках? Через боль, страдания и обертки.

Через боль, страдания и обертки.

А когда было легко?

Легко вызывать методы 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/Плагин. В любом случае хочу похвалить автора за желание освоить низкоуровневый интерфейс, что неизбежно ведет к повышению качества кода на любом языке

Зарегистрируйтесь на Хабре, чтобы оставить комментарий