Всегда ли стек Microsoft выровнен по 16 байтам? - PullRequest
0 голосов
/ 02 октября 2018

In Язык ассемблера, седьмое издание для процессоров x86 от Кипа Ирвина , на стр. 211 говорится в 5.53 Соглашение о вызовах x86 , касающееся Microsoftx64 Calling Convention,

При вызове подпрограммы указатель стека (RSP) должен быть выровнен по 16-байтовой границе (кратно 16).Инструкция CALL помещает 8-байтовый адрес возврата в стек, поэтому вызывающая программа должна вычесть 8 из указателя стека , в дополнение к 32 она уже вычитает теневое пространство.

Далее будет показана некоторая сборка с sub rsp, 8 прямо перед sub rsp, 20h (для 32-байтового теневого пространства).

Это безопасное соглашение, хотя?Гарантируется ли выравнивание стека Microsoft по 16-байтной перед инструкцией CALL?Или книга ошибочна, если предположить, что стек был

  1. выровнен по 16 байтам до того, как CALL
  2. имел 8-байтовые адреса возврата, помещенные в стек сCALL
  3. требуется дополнительный sub rsp, 8; для возврата к 16-байтовому выравниванию?

1 Ответ

0 голосов
/ 02 октября 2018

Я спрашиваю о соответствии требованиям ABI x64.Безопасно ли настраивать стек вслепую, увеличивая его на 8 байт для 16-байтового выравнивания после каждого вызова.

Да, в этом весь смысл ABI, требующий / гарантирующий 16-байтовое выравнивание до a call.


Вы можете делать что угодно внутри функции, например, 3x 16-битные нажатия и затем sub rsp, (24 - 3*2) для восстановления 16-байтное выравнивание стека после входа в функцию.

или movq xmm0, rsp, а затем используйте rsp в качестве дополнительного регистра с нулями, чтобы получить 16 полных целочисленных регистров, пока вы не восстановите его перед выполнением другого call или ret. 1

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

Это похоже на концепцию rbx, сохраняющую вызов.Не имеет значения, сохраните ли вы его / восстановите в стеке, в xmm0, в статическом хранилище, если вы отрицаете его, а затем снова отрицаете, или если вы вообще не трогаете его.Все, что имеет значение, это то, что оно имеет то же значение при возврате к вызывающей стороне, что и при вызове вашей функции.


Сноска 1: Работает, пока у вас нет асинхронных обратных вызовов /Обработчики SEH, которые могут работать в стеке пользовательского пространства.На самом деле это не гарантированно безопасно, но может работать как хак.

Допустимо ли писать ниже ESP? имеет отношение: как указывает Ped7g, если что-то может асинхронно использовать пространствониже указателя стека, он, вероятно, сломается, если RSP вообще не будет указывать на память стека.

Я видел 32-битный пример видеофильтра avisynth (я думаю), который использовал это, чтобы получить 8 tmpregs (когда MMX не был доступен), с большими предупреждающими комментариями в коде, которые необходимо отладить перед использованием этого трюка.

...