Сохранение реестра msvc 2017 x64

Согласно https://docs.microsoft.com/ru-ru/cpp/build/x64-software-conventions?view=vs-2017 — xmm6:xmm15 энергонезависимы. Но моя программа не падает, если я не сохраняю xmm6, xmm7. Я не вызываю ОС из сборки. Нужно ли сохранять регистры в этом случае? Я работаю под Windows 7.


person Andrey    schedule 18.11.2019    source источник
comment
Ваша программа не рухнет сегодня, но никаких гарантий на завтра. (Он также может вести себя неправильно, не вызывая сбоев.)   -  person Raymond Chen    schedule 18.11.2019
comment
Если вы никогда не возвращаетесь из функции, то этой функции не нужно сохранять какие-либо регистры, потому что вам никогда не нужно их восстанавливать. В противном случае, если вы вернетесь и энергонезависимые регистры изменились, вы нарушили обещание, данное вызывающей стороне, и все может случиться.   -  person Ross Ridge    schedule 18.11.2019
comment
Я понимаю, но моя программа достаточно большая. Странно, что никаких сбоев не произошло - похоже компилятор не использует xmm6-xmm7. Было бы здорово не сохранять эти регистры, потому что это влияет на производительность (не сильно, но все же).   -  person Andrey    schedule 18.11.2019
comment
Компилятор не обещает не использовать XMM6 или XMM7 и будет использовать эти регистры всякий раз, когда сочтет это выгодным. Из-за автовекторизации и других оптимизаций они могут использоваться в функциях, которые, как вы думаете, компилятор не будет вызывать. использовать их. Также помните, что компилятор, который вы используете сегодня, может отличаться от того, который вы будете использовать завтра. Наконец, сбой - не единственный возможный плохой результат, скорее всего, ваша программа не падает, но, как сказал Рэймонд Чен, ведет себя неправильно. Это может быть очень трудно отследить ошибку, если вы не знаете причину.   -  person Ross Ridge    schedule 18.11.2019
comment
ОС, которая вызывает вашу функцию, ожидает, что регистры будут сохранены. Если вы вернетесь с другими значениями в этих регистрах, ОС может вести себя хаотично, непредсказуемым образом (и это может измениться при любом обновлении безопасности).   -  person Raymond Chen    schedule 18.11.2019
comment
Моя функция - приложение Windows. Могу ли я просто сохранить эти регистры в начале моего приложения и восстановить их в конце?   -  person Andrey    schedule 18.11.2019
comment
Только если все ваше приложение для Windows написано на ассемблере, вы можете следовать любому соглашению о вызовах, которое хотите, при вызове собственных функций ассемблера из ваших собственных функций ассемблера. В противном случае, если вы вызываете свою собственную функцию сборки из функции C++, вам нужно следовать стандартному соглашению о вызовах, иначе вы нарушаете обещание компилятору, и в результате может произойти что угодно.   -  person Ross Ridge    schedule 18.11.2019


Ответы (1)


Взлом ABI не гарантирует ошибки, точно так же, как UB в C может сработать. например возможно, вызывающий абонент сохраняет/восстанавливает (при входе/выходе) регистр XMM, который вы уничтожаете, но не заботится об их значениях при вызове вашей функции. например возможно, он хотел сохранить значение FP в регистре при вызове printf, а не при вызове вашей функции.

Или, возможно, их никто не использует, и main и коду запуска CRT все равно.


Способ, которым ABI гарантирует работу, заключается в том, что если вы следуете им, вы гарантируете отсутствие проблем, а не наоборот.

IDK, если есть функция-оболочка "проверки" соглашения о вызовах, которая проверяет, правильно ли сохранены все регистры, сохраненные при вызове, и что вы не наступили на какое-либо пространство стека за пределами теневого пространства и (если есть) ваши аргументы стека. Наверное, кто-то писал что-то подобное. например Написание переходника для проверки соответствия SysV ABI


Было бы здорово не сохранять эти регистры, потому что это влияет на производительность (не сильно, но все же).

Если вы компилируете свой C с помощью GCC или clang, вы можете объявить прототип вашей ассемблерной функции как использующий x86-64 System V ABI, где все xmm0..15 затираются вызовами (и передача аргументов использует разные регистры), используя атрибут функции GCC

__attribute__((sysv_abi))
extern "C" int myfunc(void);

Затем вызывающая сторона должна будет сохранить/восстановить все из xmm6..15, поскольку предполагается, что вызывающая сторона уничтожила их все.

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

(Или лучше используйте встроенные функции, чтобы использование регистров XMM можно было встроить и оптимизировать накладные расходы на вызов/возврат, а также накладные расходы на сохранение/восстановление регистра XMM. Если накладные расходы на сохранение/восстановление или вызов имеют значение, решение более встроенное, поэтому функции не такие маленькие.)

См. Обход соглашения о вызовах Windows с сохранением регистров xmm? для этого . Имейте в виду, что ICC глючит и не может сохранить/восстановить XMM6..15 вокруг вызова функции System V ABI, а GCC не поддерживает должным образом AVX в Windows (проблемы выравнивания стека).

person Peter Cordes    schedule 18.11.2019