.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).