|
|
|
|
Инструкции ENTER и LEAVE для локальной памяти стека
В более старших моделях семейства микропроцессоров 8086 фирмы "Интел" обеспечены две новые инструкции для помощи при использовании локальной памяти
в стеке. Все процессоры iAPX186, iAPX188 и iAPX286 поддерживают инструкции ENTER (вход) и LEAVE (выход). Инструкция ENTER используется для установки
локальной памяти в стеке, когда программа вводится впервые, а инструкция LEAVE освобождает эту локальную память, когда программа осуществляет выход.
Дополнительные инструкции ENTER и LEAVE имеют возможность поддержки указателей блоков, которые используются определенным блоком структурированного
языка высокого уровня, например, такого, как язык программирования Паскаль.
В связи со сложностью этих инструкций, здесь представлены их макросы, эквивалентные листингу 2-9. Это позволит пользователям микропроцессоров
8086/8088 прочувствовать преимущество этих инструкций при переходе к более современному микропроцессору. Обратите внимание на то, что макросы 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 в символической форме отображают ссылку одного элемента
на другой элемент (т.е. элемент содержит адрес другого элемента).
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-- Создание блока стека и распределение локальной памяти
;; Копирование указателя блока стека из предыдущей программы в
;; новый блок стека для этой программы и открытие пространства
;; в стеке для новой локальной памяти
;;
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 ; запоминание значения в л.п.
-----------------------------------------------------------------
|
Символ lbase в листинге 2-9 определен как базовый адрес для доступа ко всем локальным переменным. Действительной ссылкой, создаваемой в
инструкции MOV, является:
mov [BP - ??tsize].my_var,10
|
Символ ??tsize устанавливается реализацией макроса инструкции ENTER в количества байтов, добавляемых в стек по инструкции ENTER, не включая
значение регистра BP. Значение этого символа вычисляется как local + level * 2. При вычитании значения символа ??tsize из содержимого регистра BP,
результатом является адрес верхней части стека. Таким образом, все ссылки структуры имеют положительное смещение от символа lbase. Даже если
используется версия машинного кода инструкции ENTER, можно легко написать макрос, который вычисляет значение символа ??tsize и создает инструкцию
ENTER таким образом, что этот механизм может быть с успехом использован на процессорах 186/188/286.
Другим символом, определенным в листинге 2-9, является символ pbase - базовый адрес для доступа ко всем переменным, переданным в стек. Значение
символа pbase равно [BP + 4], чтобы охватить 2 байта, помещенные в стек как часть near (близкий) инструкции CALL (вызвать процедуру) и 2 байта,
требующиеся для регистра BP, помещенного в стек по инструкции ENTER. После того, как определена структура параметров стека, символ pbase можно
использовать по имени его поля для символического доступа к данным, например, pbase.my_param.
Получив описание простого использования инструкции ENTER, вернемся к вопросу об указателях блока данных. Что это такое? Каждый указатель блока данных
указывает на начало блоков данных предыдущей программы стека. Путем загрузки регистра BP содержимым одного из указателей блока данных, размещенного в
текущем блоке, может быть получен доступ к локальным переменным предыдущего уровня. Первоначально это было спроектировано для реализации языков
программирования высокого уровня таких как, например, Паскаль, где программа имеет автоматический доступ к переменным порождающей программы. Если
читатель недостаточно созрел в отношении высокого уровня структурного программирования на языке Ассемблер, то он вероятно пропустит использование
возможностей указателя блока инструкции ENTER. Во всяком случае, если читатель решил испробовать использование инструкции ENTER с указателем блока,
то незначительные эксперименты дадут ему возможность прочувствовать ее функционирование.
|
|