adimetrius писал(а):
А как вы представляете себе "парзер GNU/Linux"? Анализатор в СР2 платформо-независимый.
ровно так, как я у себя и сделал: универсальная опция по замене в компиляторе, и детект хоста в DevCompiler, который при необходимости ставит опцию (и позволяет override).
adimetrius писал(а):
На 32-разрядной Линукс вроде тоже ничего не меняется.
я же написал: сломан
x86 ABI, а не x86_64. именно в этом и проблема. у меня, если что, 32-битная система. не гибрид. и этот поломаный ABI в своё время мне хорошо попортил жизнь, пока я не разобрался, что происходит.
adimetrius писал(а):
И там, где нужно, стоят в интерфейсных модулях ccall16.
вы
не знаете, где нужно. и
никто не знает. вот в этом-то и дело! это зависит исключительно от конкретных опций сборки конкретных сторонних библиотек на конкретной машине. более того: упасть может даже не то, что вызываете вы, а вызов одной стронней библиотеки другой сторонней библиотекой, так что вообще ничего понятно не будет. вспомните, пожалуйста, ещё раз хейзенбаги с SDL. это может возникнуть где угодно, с любой библиотекой, с любым вызовом, и совершенно спокойно проявляться только у нескольких человек, а у остальных работать. ну поверьте мне, пожалуйста, я смотрел на то, что делает GCC. у них даже баг в багтрекере пытались по этому поводу заводить, но они заявили, что поломаный ABI — это проблема всех остальных, а не GCC, и никто ничего чинить не собирается. простите, сейчас уже не вспомню ссылку, очень злой был, не схоронил. если найду опять — обязательно принесу.
adimetrius писал(а):
А если нужно поменять - то нужно ж поменять, в интерфейсных модулях для Линукс.
а теперь представим, что я делаю обёртку для SQLite, например. и у меня всё в ней отлично, имя .so/.dll выбирается селектором… и я вынужден вместо каждого `[ccall]` тоже ставить селектор. выполняя ровно ту механическую работу, с которой прекрасно справляется транслятор вообще без моего участия.
adimetrius писал(а):
Флажком для процедурных переменных не обойтись
поэтому я и говорю, что всё на самом деле намного хуже, и авторы GCC конкретно подгадили всем. увы.
adimetrius писал(а):
я ведь могу создать безымянную, динамическую переменную-массив, или массив-в-записи, и его пытаться передать платформенной процедуре.
выравнивание динамики более-менее можно захачить средствами языка. захачить так же выравнивание локальных переменных — в общем случае операция опасная, потому что нигде в стандарте языка не гарантируется, что переменные на стеке идут строго в порядке объявления в VAR, что компилятор их не объединяет, и ещё есть множество нюансов. введение подобного флага позволит свести платформо-зависимые трюки до минимума.
adimetrius писал(а):
Возможно, следует дополнить проверками: если платформенная процедура требует 16-байтного выравнивания (в т.ч. для аргументов), то компилятор должен отказать в компиляции, если это требование заведомо нарушено.
если вы сможете придумать такую проверку, то поделитесь, пожалуйста, потом деньгами от результата. мне много не надо, несколько миллионов долларов хватит: для вас это всё равно будут незначительные карманные расходы. ;-)
а если серьёзно — то я выше написал, что это никак невозможно проверить на стадии компиляции. а на стадии исполнения надо дизассемблировать каждую вызываемую функцию (то есть, абсолютно каждую функцию из сторонних библиотек, потому что одна там может вызывать другую; и не только из той библиотеки, что мы вызываем, а из всей цепочки связаных), и проверять, не используется ли там SSE-код, не обращается ли он к локалу, не нарушается ли правило выравнивания…
adimetrius писал(а):
Но, опять же, неясно, в контексте какой задачи? Это сейчас уже есть 32-битные библиотеки, которые нужно вызывать, и которые требуют такого выравнивания? Это libgit2?
да, см выше. это может быть любая библиотека. совершенно любая. не просто «может быть», а на регулярной основе происходило. один из языков, которые я использую — D. официальный компилятор dmd там тоже не делает таких выравниваний на 32-х битах, и вот оттуда я и знаю про этот баг в GCC. потому что совершенно легальный дишный код, взятый копипастой из си — в си работал, в ди падал. пришлось смотреть дизасм сишных либ, а потом кодоген GCC. и обнаружилось, что GCC выравнивает стек один раз в начале исполнения программы, и потом везде поддерживает инвариант «выравнено на 16 байт». и ожидает того же самого от всех остальных.
проблема, повторюсь, в кодогенераторе GCC, который обожает генерировать SSE-команды для пересылки данных. простое присваивание структур (а это используется в си довольно часто) может быть сделано через загрузку и запись SSE-регистров, потому что так быстрее получается на машинном уровне. копирование массивов. и ещё масса неочевидных ситуаций, где встречается необходимость копировать данные в памяти, и они больше машинного слова. достаточно собрать какую-нибудь сишную библиотеку с `-march=native` (даже какого-нибудь древнего `-march=pentium4` уже достаточно!) — и всё, мы только что заложили недетектируемую во время компиляции CP-кода мину.
поэтому на данный момент — к сожалению — можно сказать, что как минимум для GNU/Linux использовать `[ccall]` нельзя в принципе, только `[ccall16]`. однако для других систем это излишне (`[ccall16]` добавляет пролог и эпилог к каждому вызову, который на других системах совершенно не нужен). и если поправить код, входящий в системные модули, несложно, то заставлять программиста править все его личные/сторонние модули-импорты, и поддерживать две версии модуля для разных систем вместо того, чтобы починить компилятор — мне кажется не самым лучшим решением.
а это будет именно починка компилятора, потому что технически флаг `[ccall]` обозначает не конкретную реализацию, а намерение программиста: «я хочу вызвать внешнюю функцию, написаную на си, и чтобы оно Просто Работало». заставлять программиста зачем-то думать, где какие стандарты вызова внешних функций — лишает этот флаг смысла. тогда с таким же успехом мы можем заставить программиста каждый раз явно прописывать, как и какие параметры передавать, что на стеке, что на FPU, и прочая. гибко? да. удобно? нет. `[ccall]` и был придуман, чтобы скрыть эти детали. а `[ccall16]` — это платформо-зависимый хак, который вообще не должен был быть показан программисту. но на то время, когда его сделали, было не очень ясно, что происходит. теперь ясно: изменился ABI. поэтому надо привести стандарный флаг `[ccall]` в соответствие с новым ABI, который уже стандарт де-факто.