.seh_stackalloc и выравнивание стека

Я пишу некоторую сборку x64 для ассемблера GNU. Я пытался прочитать о директивах.seh_*, но я не нахожу много информации о них. gas документы не упоминают их вообще.

Но, насколько я понимаю, если мой код может находиться в стеке во время операции размотки SEH, я должен использовать их. И поскольку мой код выполняет манипуляции со стеком и вызывает другие функции, SEH возможен, поэтому я должен их использовать.

В основном я думаю, что я правильно понял:

.seh_proc FCT
FCT:

push %rbp
.seh_pushreg    %rbp

mov  %rsp, %rbp
.seh_setframe   %rbp, 0

push %r14
.seh_pushreg %r14

lea -(iOffset + iBytes)(%rsp), %rsp
.seh_stackalloc iOffset + iBytes

andq $-16, %rsp <---- But what about this?

.seh_endprologue

etc...

Но есть один момент, который не ясен. У меня есть эта инструкция:

andq $-16, %rsp

Как же мне сказать SEH, что я выполняю выравнивание стека? Это может изменить размер стека от 15 байтов (очень маловероятно) до 8 байтов (очень вероятно) до 0 байтов (безусловно, возможно). Поскольку фактическая сумма может быть не определена до времени выполнения, я застрял.

Я полагаю, что могу пропустить инструкцию.seh, но если там зарезервировано 8 байт стека, я, вероятно, уничтожил раскрутку, не так ли? Разве это не разрушает всю цель здесь?

Поочередно я могу опустить выравнивание. Но если я вызываю другие функции (например, memcpy), разве я не должен выравнивать стек? По данным МС:

Стек всегда будет поддерживаться 16-байтовым, кроме как внутри пролога

Может быть, я могу "объяснить" свой путь через это? Если парень, который позвонил мне, сделал все правильно (если...), то стек выровнялся, когда он сделал call, так что теперь у меня 8 байтов (обратный адрес) плюс все, что я делаю в своем прологе. Могу ли я зависеть от этого? Кажется хрупким.

Я пытался посмотреть на другой код, но я не уверен, что доверяю тому, что вижу. Я сомневаюсь gas сообщает об ошибках неправильного использования.seh_*. Вы, вероятно, когда-либо увидите проблему только во время реального исключения (и, возможно, не всегда даже тогда).

Если я собираюсь сделать это, я хотел бы сделать это правильно. Кажется, что выравнивание стека было бы обычным делом, поэтому кто-то должен иметь решение здесь. Я просто не вижу этого.

1 ответ

Решение

Глядя на некоторый вывод кода от gcc, я думаю, что знаю ответ. Я был на правильном пути с моим подходом "разум".

Когда вызывается функция, стек временно становится невыровненным (из-за call), но почти сразу же перестраивается через pushq %rbp, После этого корректировки стека (для локальных переменных или пространства стека для параметров вызываемых функций и т. Д.) Всегда делаются с использованием кратных 16. Таким образом, к концу пролога стек всегда снова корректно выравнивается и остается таким же образом. до следующего call,

Что означает, что в то время как andq $-16, %rsp может использоваться для выравнивания стека, мне не нужно, если я правильно пишу свой пролог.

ПРЕДУПРЕЖДЕНИЕ. Листовым функциям (то есть функциям, которые не вызывают другие функции) не требуется выравнивать стек ( https://msdn.microsoft.com/en-us/library/67fa79wz.aspx).

Другие вопросы по тегам