Pushl %esp обновляет ESP до или после сохранения?
pushl
Инструкция Y86 уменьшает указатель стека на 4 и записывает значение регистра в память. Так что не понятно, что должен делать процессор при выполнении инструкции pushl %esp
, поскольку передаваемый регистр изменяется той же инструкцией. Возможны два возможных события:
(1) толкнуть первоначальное значение %esp
или (2) нажмите уменьшенное значение %esp
,
В свете этого, как мы можем изменить этот код-эквивалент pushl REG
чтобы учесть и учесть эти неоднозначности (поскольку REG может быть%esp, как и любой другой регистр)?:
subl $4,%esp Decrement stack pointer
movl REG,(%esp) Store REG on stack
Точно так же инструкция popl %esp
может установить %esp
к значению, считанному из памяти, или к увеличенному указателю стека. Как можно изменить этот код, чтобы учесть эти двусмысленности?:
movl (%esp),REG Read REG from stack
addl $4,%esp Increment stack pointer
1 ответ
y86 основан на x86. Запись справочного руководства по набору команд x86 дляpush
говорит (правильно):
Инструкция PUSH ESP выдвигает значение регистра ESP в том виде, в каком оно существовало до выполнения инструкции.
А такжеpop
:
Инструкция POP ESP увеличивает указатель стека (ESP) до того, как данные в старой вершине стека будут записаны в место назначения.
Так что в pop %esp
В этом случае приращение теряется. Эта последовательность имеет тот же эффект, хотя большинство реальных процессоров, вероятно, загружаются во временную внутреннюю память вместо того, чтобы фактически использовать обновленное значение ESP в режиме адресации.
add $4, %esp
movl -4(%esp), %esp
Но pop %esp
делает это без обновления FLAGS и без возможности обработки прерываний или сигналов между add и mov. (Отдельная последовательность добавления / перемещения не безопасна в тех случаях, когда что-либо ниже текущего %esp
может быть асинхронно перезаписан обработчиком прерываний.)
Предположительно y86 делает то же самое, что и x86. Вы можете легко (и должны) проверить с помощью отладчика, как ваш любимый симулятор y86 справится с этим угловым делом. push %esp
легко проверить, посмотрев на память (или добавив pop %eax
после этого).
Одновременное тестирование обоих может привести к путанице, и если всплывающее значение совпадает со старым указателем стека, вы не сможете увидеть разницу. Вероятно, нажмите 0
(или хранить 0
в (%esp)
), затем pop %esp
и посмотреть, какое значение есть в реестре с помощью отладчика. (Не имеет значения, если ваш код после этого падает, вы просто используете отладчик.)
Я не проверял, поддерживает ли y86 push $0
или же movl $0, (%esp)
как х86. Я думаю, это будет immovl $0, (%esp)
если это поддерживается (немедленно к памяти). Если нет, то обнулите регистр и нажмите его.