Организация ЭВМ и систем: Курс лекций (Позиционные системы счисления. Процессоры семейства IA-32. Лазерные принтеры), страница 25

2)  копирует в регистр BP или EBP значение указателя стека, которое становится базовым адресом стекового кадра;

3)  уменьшает значение указателя стека на значение первого операнда команды, чем резервирует место под локальные переменные.

Перечисленные действия эквивалентны такой последовательности команд:

                PUSH    EBP
                MOV     EBP, ESP
                SUB     ESP, размер

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

Пример. Пусть процедура A имеет уровень вложенности 0. Тогда после выполнения команды

                ENTER   1024, 0

стек будет иметь следующий вид:

старое значение EBP

←EBP

место

для локальных данных

процедуры A (1 Кб)

←ESP

Пусть, далее, процедура B имеет уровень вложенности 1 и вызывается из процедуры A. Тогда после выполнения в процедуре B команды

                ENTER   16, 1

стек будет иметь следующий вид:

старое значение EBP

место

для локальных данных

процедуры A (1 Кб)

значение EBP до вызова команды ENTER

←EBP

EBP для процедуры A

место

для локальных данных

процедуры B (16 б)

←ESP

LEAVE                                                   выход из процедуры                  80186

Выполняет действия, противоположные команде ENTER. Фактически, команда выполняет следующие действия:

1)  копирует содержимое EBP в ESP, тем самым выбрасывая из стека весь кадр, созданный последней выполненной командой ENTER, кроме значения EBP до вызова команды ENTER;

2)  загружает из стека EBP для предыдущей процедуры, что одновременно восстанавливает значение регистра ESP, который последний имел до последнего вызова команды ENTER.

Перечисленные действия эквивалентны следующей последовательности команд:

                MOV     ESP, EBP
                POP     EBP

Примечание. Стековые кадры ненулевого уровня редко используются непосредственно при программировании на языке ассемблера из-за сложности вручную отслеживать уровни вложенности процедур. Они используются, во-первых, трансляторами языков высокого уровня, а во-вторых, ассемблерами при использовании встроенных макросов для вызова процедур.

8. Организация программы

8.1. Сегменты

8.2. Процедуры

8.1.  Сегменты

Каждая программа, на каком бы языке она ни была написана, состоит из одного или нескольких сегментов. Сегмент суть непрерывная область памяти определённого назначения.

Как уже говорилось, в типичной программе бывают сегменты трёх типов:

—  кода, содержащие команды;

—  данных, содержащие данные;

—  стека, содержащие стек.

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

Сегмент программы описывается директивами SEGMENT и ENDS:

имя_сегмента               SEGMENT [READONLY] выравнивание тип \ разрядность класс
;               содержимое сегмента
имя_сегмента               ENDS

Имя сегмента — идентификатор, который используется для получения адреса сегмента, а также для объединения сегментов в группы, если это необходимо.

READONLY — необязательное ключевое слово. Если оно присутствует, MASM выдаёт сообщение об ошибке на все команды, непосредственно выполняющие запись в данный сегмент. Другие ассемблеры этот операнд игнорируют.

Выравнивание указывает транслятору и компоновщику, с какого адреса может начинаться сегмент. Ассемблеры MASM, TASM и WASM допускают следующие значения данного операнда:

BYTE — с любого адреса;

WORD — с адреса, кратного 2;

DWORD — с адреса, кратного 4;

PARA — с адреса, кратного 16