|
|
СтекПродолжение. Начало см. “В мир информатики” № 102–104, 106 (“Информатика” № 2–4, 6/2008)Пример 3. Использование стека для передачи параметров подпрограммеИзвестно, что процедуры или функции языков программирования высокого уровня, как правило, имеют параметры. Поставим перед собой вопрос, как можно передавать параметры подпрограмме при ее вызове? В простейшем случае — через регистры, подобно тому, как вы это делали в ходе самостоятельных упражнений к предыдущему примеру. Но такой способ подходит не всегда (например, представьте себе, что параметром служит строка из 32 символов — тут уж никаких регистров не хватит!). Существует другой, более универсальный метод передачи параметров подпрограммам. Его логика вполне естественна: поскольку для обеспечения возврата из подпрограмм, как мы уже убедились, активно используется стек, можно воспользоваться этой же самой областью памяти и для передачи параметров. Рассмотрим пример, приведенный в протоколе 3. В нем простой демонстрационной подпрограмме 1 передаются два параметра, которые она помещает в регистры DX и CX. Организуем передачу параметров в стеке согласно следующему рисунку. Учитывая, что стек заполняется в сторону уменьшения адресов (вниз по рисунку), видим, что сначала в него должны заноситься параметры, а затем адрес возврата, автоматически образующийся при вызове подпрограммы. Протокол 3
Проанализируем подпрограмму повнимательнее. Она начинается инструкцией MOV BX,SP, которая копирует содержимое указателя стека в регистр BX. Сравнив с рисунком, убедимся, что BX указывает на адрес возврата, BX + 2 — на второй параметр (для CX), а BX + 4 — на первый (для DX). Если учесть, что в квадратных скобках в ассемблере принято указывать содержимое памяти, адрес которого определяется при помощи регистра, то становится понятным назначение двух следующих команд: они заносят значения параметров из стека в соответствующие регистры. Подчеркнем, что поскольку доступ к стековой области мы ведем не “стековыми”, а “обычными” методами, указатель SP при этом не смещается. Данный прием лишний раз подтверждает тот факт, что стековая память не есть что-то самостоятельное, напротив, она часть обычного ОЗУ. Подпрограмма завершается инструкцией RET 4, которая помимо возврата дополнительно обеспечивает очистку четырех байт памяти (два параметра). Технически данная константа 4 просто прибавляется к SP: 16C + 4 = 170, т.е. указатель стека возвращается в начальное положение SP0. Разобравшись с основными идеями приема параметров, обратимся к последовательности действий, описываемых в протоколе 3. Сначала обычным образом вводится программа, корректируется переход на начало и проверяется правильность набора. Значение SP традиционно устанавливается на 170. Далее по директиве t6 выполняется шесть первых команд программы. В результате в стек командой PUSH заносятся два параметра, и вызывается подпрограмма 102. Анализ содержимого стека показывает, что оно соответствует приведенному выше рисунку, т.е. пока все работает правильно. Директива t4 выполняет следующие четыре команды, которые образуют подпрограмму. Здесь тоже все проходит “в штатном режиме”: параметры помещаются в регистры и при возврате из подпрограммы SP восстанавливается. Таким образом, эксперимент полностью подтверждает теоретические принципы передачи параметров подпрограмме, описанные выше. Задания для самостоятельной работы1. Рассмотренный пример описывает случай, когда в подпрограмму передается значение переменной (в языках программирования высокого уровня даже есть специальный термин — передача параметра по значению). Более общий случай (передача параметра по ссылке) состоит в том, что передается не значение переменной, а ее адрес в памяти. Нетрудно понять, что только последний механизм способен обеспечить возврат из подпрограммы выходных параметров. Возможный алгоритм занесения ответа в “выходную” переменную может выглядеть, например, так: MOV BX,SP MOV SI,[BX+4] MOV [SI],AX Здесь для временного хранения адреса переменной использован дополнительный регистр процессора SI. Продумайте, как можно с помощью стека организовать выдачу результата подпрограммы. Проверьте свои идеи на практике. 2. Попробуйте написать и реализовать в отладчике Debug машинный аналог следующей несложной процедуры на языке Паскаль: Procedure Test(x: integer; Var y: integer); Begin y := x + 1 End; Занесите в ячейку, выбранную под переменную x, некоторое начальное значение, организуйте вызов процедуры и добейтесь, чтобы в y появился требуемый ответ. Окончание — 1 Напомним, что все программы выполняются с помощью отладчика Debug. — Прим. ред.
Е.. А.. Еремин,
| |