ebp
используется в качестве указателя кадра в процессорах Intel (при условии, что вы используете соглашение о вызовах, использующее кадры).
Он обеспечивает известную точку отсчета для поиска переданных параметров (с одной стороны) и локальных переменных (с другой) независимо от того, что вы делаете с указателем стека, когда ваша функция активна.
Последовательность:
push %ebp ; save callers frame pointer
mov %esp,%ebp ; create a new frame pointer
sub $N,%esp ; make space for locals
сохраняет указатель кадра для предыдущего кадра стека (вызывающего), загружает новый указатель кадра, а затем настраивает стек для хранения данных для текущего "уровня стека".
Поскольку параметры были бы переданы до настройки кадра, к ним можно получить доступ с помощью [bp+N]
, где N
- подходящее смещение.
Аналогичным образом, поскольку локальные элементы создаются «под» указателем кадра, к ним можно получить доступ с помощью [bp-N]
.
Инструкция leave
является единственной, которая отменяет этот кадр стека. Раньше вам приходилось делать это вручную, но Intel представила более быстрый способ сделать это. Это функционально эквивалентно:
mov %ebp, %esp ; restore the old stack pointer
pop %ebp ; and frame pointer
(старый, ручной способ).
Отвечая на вопросы один за другим, если я что-то пропустил:
Для начала нового кадра. Смотри выше.
Это не так. esp
копируется в ebp
. Это нотация AT & T (%reg
- мертвая раздача), где (среди прочего) операнды источника и назначения меняются местами относительно нотации Intel.
См. Ответ на (2) выше. Вы вычитаете 4 из esp
, а не наоборот.
Это параметр, передаваемый функции в 0x80482f0
. Он загружается не в esp
, а в память, указанную esp
. Другими словами, он помещается в стек. Поскольку вызываемая функция puts
(см. (5) ниже), это будет адрес нужной вам строки puts
ed.
Имя функции в <>
после адреса. Он вызывает функцию puts
(вероятно, в стандартной библиотеке, хотя это не гарантировано). Описание того, что такое PLT, см. здесь .
Я уже объяснил leave
выше как разматывание текущего кадра стека перед выходом. ret
просто возвращает текущую функцию. Если текущая функция main
, она возвращается к коду запуска C.