Каковы регистры ESP и EBP?

Я обнаружил, что регистр ESP - это текущий указатель стека, а EBP - базовый указатель для текущего кадра стека. Однако я не понимаю этих определений (я только начинаю изучать, как писать код на ассемблере).

Я понимаю, что ESP указывает на сам стек, а EBP указывает на то, что находится на вершине стека 1. Но это только мои догадки, и они, скорее всего, неверны. В противном случае, что бы означало следующее утверждение?

MOV EBP, ESP    

Сноска 1: Примечание редактора. Да, это неверно. В стандартной терминологии "вершина стека" - это то, на что указывает ESP, даже если это самый низкий адрес в кадре стека. По аналогии со структурой данных стека, которая растет вверх, хотя callstack на x86 (как и большинство ISA) растет вниз.

Ответ 1

esp - указатель стека, ebp is/был для фрейма стека, так что, когда вы ввели функцию, ebp мог получить копию esp в этой точке, все в стеке до этого произойдет, обратный адрес, переданный параметрами, и т.д., а также то, что является глобальным для этой функции (локальные переменные), теперь будет статическим расстоянием от указателя кадра стека на длительность функции. esp теперь свободно блуждает по желанию компилятора и может быть использован при вложенности в другие функции (каждый должен сохранить ebp естественно).

это ленивый способ управления стеком. упрощает отладку компилятора, облегчает понимание кода, сгенерированного компилятором, но записывает реестр, который мог быть иным способом общего назначения.

Ответ 2

Обычно EBP используется для резервного копирования ESP, поэтому, если ESP изменяется кодом в функции, все, что требуется для восстановления ESP, это mov ESP, EBP. Кроме того, поскольку EBP обычно остается неизменным по коду в функции, его можно использовать для доступа к переданным параметрам или локальным переменным без необходимости корректировки смещений.

Для использования "стекового фрейма" EBP вставляется в стек в начале любой функции, поэтому значение EBP, введенного в стек, представляет собой значение EBP из функции, называемой текущей функцией. Это позволяет коду или отладчику "возвращать трассировку" через все экземпляры, в которые EBP был перенесен в стек, и каждый экземпляр значения EBP в стеке можно рассматривать как базовый указатель кадра стека.

Обратите внимание, что некоторые компиляторы имеют опцию "omit frame pointers", и в этом случае EBP не используется для сохранения ESP или указателя кадра стека. Вместо этого компилятор отслеживает ESP, и все локальные смещения являются смещениями от текущего значения ESP.

Ответ 3

EBP и ESP - это пережитки эпохи, когда компиляторы не делали, например, иметь статический анализ, чтобы определить, сколько байтов стека необходимо для вызова функции. Кроме того, стек должен был динамически увеличиваться и уменьшаться во время выполнения функции, прерывания позволили бы очистить весь стек от 0 до SP, а код спагетти был стандартом де-факто. Фактически прерывания (и передача параметров только через регистры) были разработанным методом для вызова функций ядра.

В этих условиях нужно иметь фиксированную точку стека, где всегда найден адрес возврата вызывающей стороне, локальные переменные и аргументы функции. Таким образом, регистр bp был оправдан. В этой архитектуре bp было разрешено индексироваться ([bp - 300h]), но sp не было. Эти коды операций/инструкции, которые могли быть интерпретированы как mov ax, [sp + 1111h], были повторно использованы для других целей.

В 386+ и благодаря введению 'E' ESP приобрел свойство смещения. В это время EBP был освобожден от единственной цели, поскольку esp смог справиться с обеими задачами.

Обратите внимание, что даже сейчас EBP указывает на память через сегмент стека (SS), как и ESP. Другие режимы адресации (без ESP/EBP в качестве базы) по умолчанию для сегмента DS. (абсолютный, DI, SI и/или BX в 16-битном режиме и в 32-битных режимах адресации любой регистр может быть базой в режиме адресации).