|
|
|
|
Локальная память в стеке
Для локальной памяти в стеке может быть зарезервирован блок стека посредством уменьшения указателя стека. Любые прерывания или вызовы,
происходящие после этого, могут теперь обеспечить в этом блоке стека сохранение любых локальных данных, относящихся к прерванной программе. Это самый
удобный способ сохранения данных, но требующий, чтобы доступ ко всем локальным переменным выполнялся через регистр BP (для обсуждения этого смотри
предшествующий раздел, озаглавленный "Передача данных в стек"). Пример этого способа, снабженный примечаниями, содержится в листинге 2-8.
Листинг 2-8. Использование стека для локальной памяти
-----------------------------------------------------------------
; Вызывающая процедура
... ...
push ; передача 3-го аргумента
push ; передача 2-го аргумента
push
|
Т.к. структура Stackframe определяется в текущем сегменте, нет необходимости перекрывать сегмент. Если используется смещение из другого сегмента,
как например, при попытке использования шаблона из другого сегмента данных, то в ссылке необходимо использовать конструкцию SS: override (заместить).
Отказ от выполнения этого требования приводит к выдаче сообщения об ошибке в макроассемблере MASM "Can't reach with segment reg" (невозможно найти
регистр сегмента). Если когда-либо появится это сообщение, то оно означает, что для определения сегмента, к которому осуществляется доступ, текущий
сегмент не принят во внимание и нужно решать эту проблему.
Если в стеке распределяется локальная память, то перед возвратом управления из программы она должна быть освобождена. Это можно выполнить путем
добавления размера локальной памяти к стеку (возвращение к прежнему состоянию sub sp,offset bp или восстановление регистра BP из сохраненного значения
(mov sp,bp)). Память можно не освобождать с помощью инструкции RET N, т.к. текущая вершина стека не содержит адрес возврата!
В большинстве компиляторов с языков высокого уровня предпочтительным способом хранения локальных данных является использование этой "временной"
памяти в стеке. Переменные, помещаемые в этот тип памяти, иногда упоминаются как локальные, динамические или автоматические переменные. Листинг 2-8
представляет типичную последовательность событий, происходящих на входе типичных программ на языке высокого уровня. Процедура устанавливает новый блок
данных (сохранение регистра BP и установка регистра BP в текущем SP), распределяет локальную память (вычитает из SP) и сохраняет регистры, которые она
может разрушить.
Рис. 2-1 представляет структуру стека, как она выглядит внутри программы Example (пример), и показывает как шаблон Stackframe (блок данных стека)
выравнивается вместе со стеком. Заметим, что выравнивание выполняется благодаря описанию базы как "[BP-offset XamplBP]". Т.к. XamplBP выровнен с ячейки
сохраненного BP в стеке, то выбранное описание base.XamplBP эквивалентно [BP - offset XamplBP + offset XamplBP], а последнее есть то же самое, что
[BP + 0]. Другим важным моментом является то, что структура шаблона стека должна начинаться с объявления таких элементов, которые будут размещаться в
нижней памяти.
|
|