Почему Mac ABI требует выравнивания стека по 16 байт для x86-32?

Я могу понять это требование для старых систем PPC RISC и даже для x86-64, но для старого проверенного x86? В этом случае стек необходимо выровнять только по 4-байтовым границам. Да, некоторые инструкции MMX / SSE требуют 16-байтового выравнивания, но если это требование вызываемого объекта, то оно должно гарантировать правильное выравнивание. Зачем обременять каждого вызывающего абонента этим дополнительным требованием? На самом деле это может вызвать некоторое снижение производительности, потому что каждый сайт вызова должен выполнять это требование. Я что-то упускаю?

Обновление. После дополнительного расследования этого и некоторых консультаций с некоторыми внутренними коллегами у меня появилось несколько теорий на этот счет:

  1. Согласованность между версиями ОС для PPC, x86 и x64
  2. Кажется, что кодогенератор GCC теперь последовательно выполняет sub esp, xxx, а затем перемещает данные в стек, а не просто выполняет инструкцию push. Это могло бы быть быстрее на некотором оборудовании.
  3. Хотя это немного усложняет сайты вызовов, при использовании соглашения cdecl по умолчанию, когда вызывающий объект очищает стек, возникает очень мало дополнительных накладных расходов.

Проблема, с которой я столкнулся с последним элементом, заключается в том, что для соглашений о вызовах, которые полагаются на вызываемый объект, очищающий стек, приведенные выше требования действительно искажают кодогенерацию. Например, какой компилятор решил реализовать более быстрый стиль вызова на основе регистров для собственного внутреннего использования (т.е. любой код, который не предназначен для вызова из других языков или источников)? Эта штука с выравниванием стека может свести на нет некоторые приросты производительности, достигнутые за счет передачи некоторых параметров в регистры.

Обновление. Пока что единственными реальными ответами была последовательность, но для меня это слишком простой ответ. У меня более 20 лет опыта работы с архитектурой x86, и если согласованность, а не производительность или что-то конкретное, действительно является причиной, то я с уважением полагаю, что разработчикам было бы немного наивно требовать этого. Они игнорируют почти три десятилетия инструментов и поддержки. Особенно, если они ожидают, что поставщики инструментов быстро и легко адаптируют свои инструменты для своей платформы (возможно, нет ... это это Apple ...) без необходимости перепрыгивать через несколько, казалось бы, ненужных обручей.

Я отдам эту тему еще на день или около того, а потом закрою ее ...

Связанный


person Allen Bauer    schedule 04.03.2009    source источник
comment
Не API. ABI (приложение двоичный интерфейс.   -  person Allen Bauer    schedule 07.03.2009
comment
По теме: Почему System V / AMD64 ABI требует выравнивания стека 16 байт? - современные версии i386 System V ABI требуют того же вещь.   -  person Peter Cordes    schedule 07.06.2020


Ответы (10)


Из «Справочного руководства по оптимизации архитектур Intel®64 и IA-32», раздел 4.4.2:

«Для лучшей производительности Streaming SIMD Extensions и Streaming SIMD Extensions 2 требуют, чтобы их операнды памяти были выровнены по 16-байтовым границам. Невыровненные данные могут привести к значительному снижению производительности по сравнению с выровненными данными».

Из Приложения D:

«Важно убедиться, что кадр стека выровнен по 16-байтовой границе при входе в функцию, чтобы локальные данные __m128, параметры и места разлива регистров XMM были выровнены на протяжении всего вызова функции».

http://www.intel.com/Assets/PDF/manual/248966.pdf

person rob mayoff    schedule 22.05.2009

Я не уверен, так как у меня нет доказательств из первых рук, но я считаю, что причина в SSE. SSE намного быстрее, если ваши буферы уже выровнены по границе 16 байтов (movps vs movups), а любой x86 имеет как минимум sse2 для mac os x. Пользователь приложения может позаботиться об этом, но затраты будут довольно значительными. Если общие затраты на то, чтобы сделать это обязательным в ABI, не слишком значительны, оно того стоит. SSE широко используется в mac os X: фреймворк для ускорения и т. Д.

person David Cournapeau    schedule 07.05.2009
comment
Это лучшая причина, которую я могу придумать ... однако требование состоит в том, чтобы стек был выровнен перед вызовом. Как только вызываемый получает контроль, стек больше не выравнивается! (адрес возврата теперь находится на вершине стека). - person Allen Bauer; 07.05.2009
comment
Не имеет большого значения, что указатель стека не выровнен в этой точке, потому что вы хотите, чтобы аргументы были выровнены в памяти. Таким образом, с вашим типичным фреймом стека вам гарантировано, что вы выровнены по 16 байт по 8 (% ebp), что является началом ваших аргументов. - person Lara Dougan; 06.11.2009

Я считаю, что он должен соответствовать x86-64 ABI.

person Andrew Grant    schedule 07.03.2009
comment
В этом есть смысл ... до некоторой степени. Какая в этом ценность на самом деле? Только создатели инструментов действительно заботятся об этом, поскольку большинство разработчиков просто полагаются на инструмент, чтобы делать правильные вещи. - person Allen Bauer; 07.03.2009
comment
Может быть, из-за (относительно) короткого срока службы x86-32 на Mac? - person Andrew Grant; 07.03.2009

Во-первых, обратите внимание, что выравнивание по 16 байтам является исключением, введенным Apple в System V IA-32 ABI.

Выравнивание стека необходимо только при вызове системных функций, поскольку многие системные библиотеки используют расширения SSE или Altivec, которые требуют выравнивания по 16 байтам. Я нашел явную ссылку в libgmalloc Страница MAN.

Вы можете идеально обрабатывать кадр стека так, как хотите, но если вы попытаетесь вызвать системную функцию с неверно выровненным стеком, вы получите сообщение misaligned_stack_error.

Изменить: для записи, вы можете избавиться от проблем с выравниванием при компиляции с GCC, используя mstack-realign.

person Laurent Etiemble    schedule 15.01.2010
comment
Проблема в том, что компилятор на самом деле не знает, является ли данный вызов системной функцией или нет. Это означает, что единственная безопасная вещь, которую нужно сделать, - это убедиться, что стек остается выровненным по всей цепочке вызовов. Мы уже пользуемся этим фактом при работе с написанными вручную низкоуровневыми функциями ассемблера, которые, как известно, никогда не вызывают системные функции. - person Allen Bauer; 15.01.2010
comment
О, еще одна вещь, это как-то сложно перекомпилировать с GCC, так как мы находимся в процессе модификации нашего существующего компилятора Delphi для нацеливания на Mac ... GCC не участвует, так как у нас есть собственный интерфейс и генератор кода / бэкэнд вот почему это проблема. - person Allen Bauer; 15.01.2010

Это вопрос эффективности.

Обеспечение выравнивания стека по 16 байт в каждой функции, использующей новые инструкции SSE, увеличивает накладные расходы на использование этих инструкций, что существенно снижает производительность.

С другой стороны, постоянное выравнивание стека по 16 байтов гарантирует, что вы можете свободно использовать инструкции SSE без потери производительности. Для этого нет никаких затрат (по крайней мере, стоимость измеряется в инструкциях). Это связано только с изменением константы в прологе функции.

Рациональное использование пространства стека обходится недорого, вероятно, это самая горячая часть кеша.

person user239558    schedule 08.01.2010
comment
Я считаю, что это очень поверхностное объяснение. Почему каждая функция в цепочке вызовов должна выполнять эту работу на случай, если может использоваться инструкция SSE? Если эти накладные расходы не представляют особого труда, тогда нет ничего страшного в том, чтобы делать это в точке, где используются инструкции SSE! Я не требую, чтобы мои соседи сохраняли мой дом чистый. - person Allen Bauer; 08.01.2010
comment
Ваш вывод неверен. Обратите внимание на разницу между изготовлением и хранением. Выравнивание стека по 16 байт не требует никакой работы. Это просто связано с изменением константы в прологе, чтобы обеспечить выравнивание стека. Я обновил свой исходный ответ, чтобы подчеркнуть это. OTOH, выравнивание стека по 16 байт требует работы и требует затрат, измеряемых инструкциями. - person user239558; 22.01.2010
comment
Это только при условии, что генератор кода вашего компилятора работает как GCC. Мир намного больше, чем GCC. Если компилятор зарезервировал пространство стека для всех локальных переменных и всех параметров для всех функций, которые вызывает текущая функция, это действительно. Однако многие компиляторы могут работать иначе, и на самом деле попытки заставить их работать таким образом могут оказаться слишком дорогостоящими. Другое дело, что не все инструкции SSE требуют выравнивания, только инструкции MOVxxA. Таким образом, даже в этом случае набор потенциальных инструкций, на которые настраивается система, относительно невелик. Приложение не может никогда использовать SSE прямо или косвенно. - person Allen Bauer; 22.01.2010
comment
Анализ затрат одинаков, независимо от того, зарезервировано ли пространство стека для всех локальных переменных прологом или нет. Всякий раз, когда пространство стека выделяется под $ xx,% esp - это способ сделать это. Выравнивание стека по 16 байтов означает, что xx является кратным 16. Все, что нужно сделать компилятору, - это округлить. Может быть, вы могли бы привести пример, где это болит? - person user239558; 30.01.2010

Я предполагаю, что Apple считает, что все просто используют XCode (gcc), который выравнивает стек за вас. Поэтому требование, чтобы стек был выровнен так, чтобы этого не требовалось ядру, - это просто микрооптимизация.

person Mike    schedule 25.01.2010

Хотя я не могу ответить на ваш вопрос, ПОЧЕМУ, вы можете найти руководства на следующем сайте:

http://www.agner.org/optimize/

Что касается ABI, обратите внимание на:

http://www.agner.org/optimize/calling_conventions.pdf

Надеюсь, это полезно.

person PhiS    schedule 22.05.2009

Хм, а разве OS X ABI не выполняла забавные RISC-функции вроде передачи небольших структур в регистры?

Так что это указывает на согласованность с теорией других платформ.

Если подумать, API системных вызовов FreeBSD также выравнивает 64-битные значения. (например, lseek и mmap)

person Marco van de Voort    schedule 22.05.2009

Чтобы сохранить последовательность в ядре. Это позволяет загружать одно и то же ядро ​​на нескольких архитектурах без каких-либо изменений.

person PixelSmack    schedule 07.03.2009
comment
Кажется, это единственное, что говорят люди, однако для языков более высокого уровня это деталь, которая (должна быть) скрыта. Любое скомпилированное приложение x86-32 ObjC, C или C ++ не будет заботиться о нем, поскольку это непрозрачная деталь. - person Allen Bauer; 08.03.2009
comment
Ядро должно быть совместимо со стеком вызовов пользовательских процессов, потому что ему нужно будет время от времени использовать его для рабочего пространства для обработки определенных системных вызовов или прерываний. - person SingleNegationElimination; 07.05.2009
comment
Несогласованность, похоже, не повредит ядрам Windows и Linux. Что такого особенного в MacOS на x86? - person Allen Bauer; 07.05.2009

Не знаете, почему никто не рассмотрел возможность легкой переносимости с устаревшей платформы на базе PowerPC?

Прочитай это:

http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/100-32-bit_PowerPC_Function_Calling_Conventions/32bitPowerPC.html#//apple_ref/doc/uid/TP4202438-Srel=

А затем увеличил масштаб до «32-битных соглашений о вызове функций PowerPC» и, наконец, вот что:

"В 32-битной среде PowerPC доступны следующие режимы встраивания выравнивания:

Режим выравнивания мощности основан на правилах выравнивания, используемых компилятором IBM XLC для операционной системы AIX. Это режим выравнивания по умолчанию для версии GCC с архитектурой PowerPC, используемой в AIX и Mac OS X. Поскольку этот режим, скорее всего, будет совместим между компиляторами архитектуры PowerPC от разных поставщиков, он обычно используется со структурами данных, которые используются совместно разные программы ".

Принимая во внимание унаследованную основу OSX на основе PowerPC, переносимость является основным соображением - она ​​требует соблюдения соглашения вплоть до компилятора AIX XLC. Когда вы думаете о необходимости убедиться, что все инструменты и приложения будут работать вместе с минимальной доработкой, я думаю, что важно придерживаться того же устаревшего ABI, насколько это возможно.

Это дает философию, и дальнейшее чтение является явно упомянутым правилом («Пролог и эпилог»):

Вызываемая функция отвечает за выделение своего собственного кадра стека, следя за сохранением 16-байтового выравнивания в стеке. Эта операция выполняется частью кода, называемым прологом, который компилятор помещает перед телом подпрограммы. После тела подпрограммы компилятор помещает эпилог, чтобы восстановить процессор в состояние, в котором он находился до вызова подпрограммы.

person Peter Teoh    schedule 12.07.2011