Работа процедур со стеком
В данном разделе описаны правила, которых следует придерживаться при составлении внешних подпрограмм, ориентированных на работу со стеком.
Распределение пространства стека. Общий случай распределения пространства стека при выполнении процедуры показан в табл. В.2.
Таблица В.2. Распределение пространства стека в порядке увеличения адресов.
Общедоступная область стека |
Промежуточные переменные подпрограммы |
Исходное содержимое регистра bр или ebp |
Адрес возврата из подпрограммы |
Параметры подпрограммы |
Недоступная часть стека |
Общедоступная область расположена в начале стекового сегмента, ее минимальный адрес (смещение) равен нулю, а максимальный хранится в указателе стека (в регистре sp). Обычно она используется для хранения содержимого регистров и передачи параметров вызываемым подпрограммам.
Место для промежуточных переменных резервирует подпрограмма, если в этом есть необходимость. Она же сохраняет в стеке исходное содержимое регистра bp или ebp при работе в 32-разрядном режиме. Во время выполнения подпрограммы адрес, в котором сохранено исходное значение регистра bp (или ebp), используется в качестве базы для доступа команд к параметрам или промежуточным переменным.
Адрес возврата и параметры размещает в стеке основная задача, вызывающая данную подпрограмму. При входе в подпрограмму указатель стека содержит адрес первого свободного слова, в которое обычно помещается исходное значение регистра bp или ebp.
Недоступная часть стека названа так не потому, что она физически недоступна, а потому, что подпрограмма не должна изменять хранящиеся там данные. Если перед размещением параметров стек был полностью очищен, то недоступной области просто не существует.
Промежуточные переменные
B зависимости от конкретных особенностей подпрограммы при ее выполнении может возникнуть необходимость в использовании переменных для хранения промежуточных результатов вычислений в оперативной памяти. Назовем такие переменные "промежуточными".
До сих пор, в приводимых примерах переменные располагались в разделе данных задачи. Только в примере В.5 переменная dten хранится в сегменте кодов. Как правило, у внешних подпрограмм нет собственного сегмента данных, исключения возможны, но они встречаются редко. Размещать же промежуточные результаты в сегменте данных основной задачи не целесообразно, поскольку они используются только во время выполнения подпрограммы и не нужны в других случаях.
Пространство для размещения промежуточных переменных лучше всего выделять в стеке при входе в подпрограмму и освобождать его перед выходом из нее. Для резервирования требуемого пространства после сохранения содержимого регистра bp надо просто уменьшить текущее значение указателя стека на суммарный размер промежуточных переменных, выраженный в байтах. В примере В.6 показано, как это обычно делается.
Пример В.6. Варианты оформления начала подпрограммы.
; Вариант 1 – использование трех команд push bp; сохранение содержимого bp mov bp, sp; запись в bp адреса верхушки стека sub sp, N; резервирование N байтов в стеке
; Вариант 2 – специальная команда enter enter N, 0; заменяет три команды варианта 1