или автоматические переменные. Листинг 2-8 представляет типичную
последовательность событий, происходящих на входе типичных прог-
рамм на языке высокого уровня. Процедура устанавливает новый блок
данных (сохранение регистра BP и установка регистра BP в текущем
SP), распределяет локальную память (вычитает из SP) и сохраняет
регистры, которые она может разрушить.
Рис. 2-1 представляет структуру стека, как она выглядит внут-
ри программы Example (пример), и показывает как шаблон Stackframe
(блок данных стека) выравнивается вместе со стеком. Заметим, что
выравнивание выполняется благодаря описанию базы как
"[BP-offset XamplBP]". Т.к. XamplBP выровнен с ячейки сохраненно-
го BP в стеке, то выбранное описание base.XamplBP эквивалентно
[BP - offset XamplBP + offset XamplBP], а последнее есть то же
самое, что [BP + 0]. Другим важным моментом является то, что
структура шаблона стека должна начинаться с объявления таких эле-
ментов, которые будут размещаться в нижней памяти.
Инструкции ENTER и LEAVE для локальной памяти стека
В более старших моделях семейства микропроцессоров 8086 фирмы
"Интел" обеспечены две новые инструкции для помощи при использо-
вании локальной памяти в стеке. Все процессоры iAPX186, iAPX188 и
iAPX286 поддерживают инструкции ENTER (вход) и LEAVE (выход). Ин-
струкция ENTER используется для установки локальной памяти в сте-
ке, когда программа вводится впервые, а инструкция LEAVE освобож-
дает эту локальную память, когда программа осуществляет выход.
Дополнительные инструкции ENTER и LEAVE имеют возможность под-
держки указателей блоков, которые используются определенным бло-
ком структурированного языка высокого уровня, например, такого,
как язык программирования Паскаль.
В связи со сложностью этих инструкций, здесь представлены их
макросы, эквивалентные листингу 2-9. Это позволит пользователям
микропроцессоров 8086/8088 прочувствовать преимущество этих инс-
- 2-28 -
трукций при переходе к более современному микропроцессору. Обра-
тите внимание на то, что макросы enter и leave отклоняются от не-
официального стандарта отсутствием в качестве префикса знака @,
потому что они предназначены для замены инструкций ENTER и LEAVE
при использовании микропроцессоров 8086/8088.
При выполнении инструкция ENTER осуществляет в стеке три
действия. Она всегда помещает значение регистра BP в стек. Если
значение level (уровень) больше или равно 1, то инструкция копи-
рует предыдущие значения регистра BP в стек. Если значение local
(локальный) больше или равно 1, то инструкция открывает прост-
ранство для локальной памяти в стеке путем вычитания значения
local из старого BP в стеке (первая инструкция push).
Старшие адреса .----------------------------------.-----
| Предыдущие структуры Stackframe | ^
|----------------------------------| |
| Param3 | |
[BP+8] |----------------------------------| |
| Param2 | |
[BP+6] |----------------------------------| |
| Param1 | |
[BP+4] |----------------------------------| |
| | |
[BP+2] |----------------------------------| |
| XamplBP |Stackframe
[BP+0] |----------------------------------| |
| LocIndx | |
[BP-2] |----------------------------------| |
| LocChar | |
[BP-4] |----------------------------------| |
|/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\| |
|
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ |
[BP-16]|----------------------------------| |
| LocWord | v
[BP-18]|----------------------------------|-----
| Сохраненное значение SI |
|----------------------------------|
| Сохраненное значение DI |
Вершина стека |----------------------------------|
| Доступная память |
Младшие адреса ----------------------------------
Рис.2-1. Локальная память стека и доступ к параметрам
Инструкция LEAVE выполняет действия, обратные действиям инс-
трукции ENTER, пока регистр BP оставлен в, или сброшен в первона-
чальное значение, установленное инструкцией ENTER.
Наиболее запутанной фазой этой операции является ее связь с
указателем блока данных. На рис.2-2 показано состояние (и содер-
жимое) стека для ряда операций, которые состоят из четырех после-
довательных инструкций ENTER.
Каждый элемент стека на рис.2-2 отображает в символической
форме 2 байта (по этой причине все значения параметров local (ло-
кальный) для инструкции ENTER умножаются на 2 байта. Это не явля-
ется ограничением инструкции ENTER). Стрелки на рис. 2-2 в симво-
лической форме отображают ссылку одного элемента на другой
- 2-29 -
элемент (т.е. элемент содержит адрес другого элемента).
ENTER 4,1 ENTER 2,2 ENTER 4,3
xxxxxxxx xxxxxxxx xxxxxxxx
.-->[старое BP]<---BP#1 [старое BP] [старое BP]
----[FP # 1 ] ^ [FP # 1 ] [FP # 1 ]
[local ] | [local ] [local ]
SP-->[local ] | [local ] [local ]
| .-->[BP # 1 ]<---BP#2 [старое BP]
--|---[FP # 1 ] ^ [FP # 1 ]
---[FP # 2 ] | [FP # 2 ]
SP--->[local ] | [local ]
| .-->[BP # 2 ]<--BP#3
| | [FP # 1 ]
--|---[FP # 2 ]
---[FP # 3 ]
[local ]
SP-->[local ]
Рис.2-2. Действие инструкции ENTER в стеке
Первая инструкция ENTER (уровень 1) устанавливает единствен-
ный указатель блока данных, указывающий на свой собственный блок
данных, и открывает верхнее пространство в стеке для 4 байтов па-
мяти. Вторая инструкция ENTER (уровень 2) не только создает свой
собственный указатель блока (FP#2), но и копирует указатель блока
данных из предыдущего блока данных (FP#1). Вторая инструкция
ENTER создает только 2 байта локальной памяти. Последняя инструк-
ция ENTER (уровень 3) переносит шаг 1 операции дальше, копируя
указатели блока предыдущих двух уровней (FP#1 и FP#2).
Почему выполнение примера последовательно начинается с уровня
1 инструкции ENTER, а не с инструкции ENTER уровня 0? Уровень 0
инструкции ENTER просто помещает содержимое регистра BP в стек и
вычитает значение local (локальный) из указателя стека, устанав-
ливая регистр BP для указания на только что помещенное значение
регистра BP. Указатели блока данных не копируются. Уровень 0 инс-
трукции ENTER является идеальным для создания локальной памяти в
стеке. При использовании инструкции ENTER вместе с директивой
STRUC, инструкция ENTER может почти автоматически создавать ло-
кальную память стека, которая легко доступна.
Листинг 2-9. Эквиваленты макросов для инструкций
ENTER и LEAVE
-----------------------------------------------------------------
;; МАКРООПРЕДЕЛЕНИЯ ДЛЯ ИНСТРУКЦИЙ ENTER И LEAVE
;;
;; Описания базовой адресации для использования при доступе
;; к элементам в блоке стека, созданном инструкцией ENTER
;;
pbase equ [BP + 4] ;; доступ к параметрам
lbase equ [BP - ??tsize] ;; доступ к локальным данным
fbase equ [BP - ??fsize] ;; доступ к указателю блока
;; Form ENTER local , level
;;
;; ENTER-- Создание блока стека и распределение локальной памяти
;; Копирование указателя блока стека из предыдущей программы в
;; новый блок стека для этой программы и открытие пространства
- 2-30 -
;; в стеке для новой локальной памяти
;;
enter MACRO local,level
??tsize = local + level * 2
??fsize = level * 2
push bp
IF (level NE 0)
IF (level GT 1)
REPT level - 1
sub bp,2
push [bp]
ENDM
ENDIF
mov bp,sp
IF (level GT 1)
add bp,(level - 1) * 2
ENDIF
push bp
ELSE
mov bp,sp
ENDIF
sub sp,local
ENDM
;; Form LEAVE
;;
;; LEAVE-- Выполнение процедуры возврата, удаляющей блок стека
;; и локальной памяти, установленной по инструкции ENTER
;;
leave MACRO
mov sp,bp
pop bp
ENDM
-----------------------------------------------------------------
На листинге 2-10 показан фрагмент программы создания локаль-
ной памяти в стеке с использованием инструкции ENTER. Этот фраг-
мент программы определяет, распределяет и использует локальную
память из стека. Инструкция ENTER способствует обучению резерви-
рования необходимого количества памяти благодаря оператору MASM
SIZE. Знак процента (%) требуется только с реализацией макроса
инструкции ENTER. При использовании версии машинной программы
(поддерживаемой макроассемблером MASM 2.0 и выше путем указания
переключателя .286С) знак процента(%) должен быть опущен.
Листинг 2-10. Создание и ссылка к локальной памяти стека
по инструкции ENTER
-----------------------------------------------------------------
?data_1 STRUC
my_var dw ?
?data_1 ENDS
test PROC NEAR
ENTER %(size ?data_1),0 ; распределение локальной памяти
mov lbase.my_var,10 ; запоминание значения в л.п.