Сборка х86 - Инструкция по "уходу"
Говорят, что инструкция "отпуск" похожа на:
movl %ebp, %esp
popl %ebp
Я понимаю movl %ebp, %esp
часть, и что это действует, чтобы выпустить сохраненную память (как обсуждено в этом вопросе).
Но какова цель popl %ebp
код?
2 ответа
LEAVE
является аналогом ENTER
, ENTER
инструкция устанавливает кадр стека, сначала нажав EBP
в стек, а затем копирует ESP
в EBP
, так LEAVE
должен сделать наоборот, т.е. EBP
в ESP
а затем восстановить старое EBP
из стека.
Если вы хотите узнать больше о том, как это сделать, обратитесь к разделу " ПРОЦЕДУРА ВЫЗЫВАЕТ БЛОКСТРУКТУРИРОВАННЫЕ ЯЗЫКИ" в Руководстве разработчика программного обеспечения Intel, том 1. ENTER
а также LEAVE
Работа.
enter n,0
в точности эквивалентно (и должно быть заменено на)
push %ebp
mov %esp, %ebp # ebp = esp, mov ebp,esp in Intel syntax
sub $n, %esp # allocate space on the stack. Omit if n=0
leave
в точности эквивалентно
mov %ebp, %esp # esp = ebp, mov esp,ebp in Intel syntax
pop %ebp
enter
очень медленно и компиляторы не используют его, но leave
Это хорошо. ( http://agner.org/optimize). Компиляторы используют leave
если они вообще создают кадр стека (по крайней мере, это делает gcc). Но если esp
уже равен ebp
наиболее эффективно просто pop ebp
,
popl
инструкция восстанавливает базовый указатель, а movl
Инструкция восстанавливает указатель стека. Базовый указатель является нижней частью стека, а указатель стека является верхней. Перед инструкцией выхода стек выглядит так:
----Bottom of Caller's stack----
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack/Bottom of Callee's stack---- (%ebp)
...
Callee's
Variables
...
---Bottom of Callee's stack---- (%esp)
После movl %ebp %esp
, который освобождает стек вызываемого, стек выглядит так:
----Bottom of Caller's stack----
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack/Bottom of Callee's stack---- (%ebp) and (%esp)
После popl %ebp
, который восстанавливает стек вызывающей стороны, стек выглядит так:
----Bottom of Caller's stack---- (%ebp)
...
Caller's
Variables
...
Function Parameters
----Top of Caller's Stack---- (%esp)
enter
Инструкция сохраняет нижнюю часть стека вызывающего и устанавливает базовый указатель, чтобы вызываемый мог выделить свой стек.
Также обратите внимание, что, хотя большинство компиляторов C выделяют стек таким образом (по крайней мере, с выключенной оптимизацией), если вы пишете функцию на языке ассемблера, вы можете просто использовать тот же самый кадр стека, если хотите, но вы должны обязательно pop
все из стека, что вы push
на этом или вы будете переходить на нежелательный адрес, когда вы вернетесь (это потому, что call <somewhere>
средства push <ret address>
[или же push %eip
], jmp <somewhere>
, а также ret
означает переход на адрес в верхней части стека [или pop %eip
]. %eip
регистр, который содержит адрес текущей инструкции).