Память
можно не освобождать с помощью инструкции RET N, т.к. текущая
вершина стека не содержит адрес возврата!
В большинстве компиляторов с языков высокого уровня предпоч-
тительным способом хранения локальных данных является использова-
ние этой "временной" памяти в стеке.
Переменные, помещаемые в
этот тип памяти, иногда упоминаются как локальные, динамические
или автоматические переменные. Листинг 2-8 представляет типичную
последовательность событий, происходящих на входе типичных прог-
рамм на языке высокого уровня.
Процедура устанавливает новый блок
данных (сохранение регистра BP и установка регистра BP в текущем
SP), распределяет локальную память (вычитает из SP) и сохраняет
регистры, которые она может разрушить.
Рис. 2-1 представляет структуру стека, как она выглядит внут-
ри программы Example (пример), и показывает как шаблон Stackframe
(блок данных стека) выравнивается вместе со стеком.
...
; Вызываемая процедура
Stackframe STRUC ; определение шаблона структуры стека
LocWord dw ? ; локальная переменная Word (слово)
LocChar db 14 dup (?) ; локальный массив символов
LocIndx dw ? ; другая локальная переменная Word
XamplBP dw ? ; сохраняемое значение BP
dw ? ; адрес возврата (NEAR call)
Param1 dw ? ; 1-й параметр (передан последним)
Param2 dw ? ; 2-й параметр
Param3 dw ? ; 3-й параметр (передан первым)
Stackframe END ; конец определения шаблона
;
base EQU [bp - offset XamplBP] ; выравнивание BP с шаблоном
;
Example PROC NEAR ; начало процедуры
push bp ; сохранение старого указателя базы
mov bp,sp ; выравнивание Stackframe со стеком
sub sp,offset XamplBP ; резервирование памяти в стеке
push si ; сохранение используемых регистров
push di
... ... ...
mov si,base.Param1 ; доступ к 1-му параметру
mov al,base.LocWord ; доступ к локальным переменным
... ... ...
pop di ; восстановление сохраненных регистров
pop si ;
mov sp,bp ; удаление локальных переменных
pop bp ; восстановление первоначального BP
ret ; возврат без очистки
Example ENDP ; конец процедуры Example (пример)
- 2-27 -
Т.к. структура Stackframe определяется в текущем сегменте,
нет необходимости перекрывать сегмент. Если используется смещение
из другого сегмента, как например, при попытке использования шаб-
лона из другого сегмента данных, то в ссылке необходимо использо-
вать конструкцию SS: override (заместить). Отказ от выполнения
этого требования приводит к выдаче сообщения об ошибке в макроас-
семблере MASM "Can't reach with segment reg" (невозможно найти
регистр сегмента). Если когда-либо появится это сообщение, то оно
означает, что для определения сегмента, к которому осуществляется
доступ, текущий сегмент не принят во внимание и нужно решать эту
проблему.
Если в стеке распределяется локальная память, то перед воз-
вратом управления из программы она должна быть освобождена. Это
можно выполнить путем добавления размера локальной памяти к стеку
(возвращение к прежнему состоянию sub sp,offset bp или восстанов-
ление регистра BP из сохраненного значения (mov sp,bp)).