Каждый раз при вызове функции, в памяти должно быть создано новое окружение для локальных переменных и ее параметров(здесь под окружением подразумеваются все элементы, появляющиеся при выполнении функции: ее аргументы, ее локальные переменные, ее адрес возврата в стеке выполнения... это не окружение для переменных оболочки, о котором мы говорили в предыдущей статье). Регистр %esp (extended stack pointer - расширенный указатель стека) содержет адрес вершины стека(которая в нашем представлении находится внизу, но мы так и будем называть ее вершиной для полной аналогии со стеком реальных объектов) и указывает на последний элемент, добавленый в стек; в зависимости от архитектуры, этот регистр может иногда указывать на первое свободное место в стеке.
Адрес локальной переменной в стеке может быть представлен как смещение по отношению к %esp. Однако, элементы все время добавляются или удаляются в/из стека, и смещение каждой переменной должно будет корректироваться, а это очень неэффективно. Использование второго регистра позволяет исправить положение: %ebp (extended base pointer - расширенный указатель базы) содержит начальный адрес окружения текущей функции. Поэтому достаточно адрес представлять как смещение относительно этого регистра. Он остается постоянным, пока выполняется функция. Теперь легко найти параметры и локальные переменные в функции.
Стандартный элемент стека - слово: на процессорах i386 оно занимает 32 бита, то есть 4 байта. Этот параметр отличен для других архитектур. На процессорах Alpha слово занимает 64 бита. Стек работает только со словами, это значит, что каждая размещенная переменная использует один и тот же размер слова. Мы увидим это более подробно в описании пролога функции. Вывод содержимого переменной str при помощи gdb в предыдущем примере иллюстрирует это. Команда xgdb выводит полное 32-х битное слово (читайте его слева направо, т.к. оно представлено в прямом порядке байтов).
Стеком обычно управляют всего 2 инструкциями процессора:
push value : данная инструкция помещает value на вершину стека. Она уменьшает %esp на размер слова, чтобы получить адрес следующего доступного слова в стеке и сохраняет аргумент value на место этого слова;
pop dest : помещает элемент с вершины стека в 'dest'. Она помещает значение по адресу, на который указывает %esp, в dest и увеличивает регистр %esp. Чтобы быть точным, из стека ничего не удаляется. Просто меняется указатель на вершину стека.