Вызов процедур и возврат из них
Существуют специальные команды, упрощающие реализацию вызова процедуры и возврат из нее.
Команда вызова процедуры записывается следующим образом:
CALL < имя процедуры>
Команда записывает в стек адрес следующей за ней команды и осуществляет переход на заданную операндом процедуру.
Команда возврата из процедуры записывается следующим образом:
RET
Команда считывает адрес с вершины стека и переходит по нему. На момент ее выполнения стек должен быть точно в том состоянии, в каком он был в момент входа в процедуру (иначе адрес возврата не сможет быть считан). Существует также команда RET с параметром, которая сначала удаляет из стека указанное количество байтов, а затем уже считывает адрес возврата.
Если процедура расположена в другом сегменте команд, тогда переход на нее и возврат из нее должны быть дальними. При выполнении программы ассемблер сам выбирает, какой надо сделать переход – дальний или ближний. Но есть одна тонкость: если дальняя процедура описана позже команды ее вызова, то в команде CALL следует с помощью оператора PTR явно указать, что процедура дальняя:
CALL FAR PTR P
Передача параметров и результата через регистры
Простейшим способом передачи параметров является их передача через регистры: перед вызовом процедуры вызывающая программа записывает параметры в регистры, а процедура «знает», какой параметр в каком регистре искать.
Различают передачу параметра по значению (в регистр записывается значение параметра) и по ссылке (в регистр записывается адрес переменной-параметра). Как правило, по значению передают простые переменные, а по ссылке – данные сложных типов (массивы, структуры и т.п.).
Для загрузки адреса переменной в регистр используется команда LEA, например:
LEA AX, X
Данная команда очень похожа на команду MOV, но между ними имеется принципиальное различие: если MOV записывает в регистр содержимое ячейки памяти, адрес которой указан вторым операндом, то команда LEA записывает в регистр адрес, указанный во втором операнде.
Результат работы процедуры, как правило, возвращается через регистр (регистры).
Пример. Найти сумму максимальных элементов двух массивов байтов, рассматриваемых как целые без знака.
S SEGMENT STACK ;Сегмент стека
DB 200 DUP(0ABh)
S ENDS
D SEGMENT ; Сегмент данных
A DB 1, 100, 20, 40, 23
B DB 200, 100, 20
SUM DB ?
D ENDS
CODE SEGMENT
ASSUME SS:S, CS:Code, DS:D
; Процедура поиска максимума. Параметры передаются
; через BX (адрес массива) и CX (число элементов)
MAX PROC
PUSH BX ;Сохранение значений BX и CX в ; стек, так как они будут изменяться
; В BX будет записываться адрес текущего элемента
; массива, а в CX – счетчик цикла
PUSH CX
MOV AL,0 ; В AL будет храниться максимум
L1: CMP [BX], AL ; Начало цикла поиска максимума
JBE L2
MOV AL, [BX] ;Если новый максимум найден,
;то записываем его в AL
L2: INC BX ;Переход к следующему элементу
;массива
LOOP L1 ;Окончание тела цикла
POP CX ; Восстановление значений
POP BX ; регистров BX и CX
RET
MAX ENDP ; Окончание процедуры
MMM PROC FAR
; Основная программа
; Выполнение соглашений DOS
PUSH DS ;Запись содержимого DS в стек
SUB AX, AX ;Запись ноля
PUSH AX ;в стек
; Установка верного значения в регистре DS.
; Регистры CS и SS устанавливаются системой.
MOV AX, D ;Занести адрес
MOV DS, AX ; D в DS
LEA BX, A ; Для передачи параметра-ссылки
; используется регистр-модификатор bx
MOV CX, 5 ; В CX заносится счетчик цикла
CALL MAX ; Вызов подпрограммы
MOV SUM, AL ; В переменную SUM заносится
; max элемент 1-го массива
LEA BX, B ; Для передачи параметра-ссылки
; используется регистр-модификатор bx
MOV CX, 3 ; В CX заносится счетчик цикла
CALL MAX ; Вызов подпрограммы
ADD SUM, AL ; К переменной SUM добавляется
; max элемент 1-го массива,
;т.е. получается итоговый результат
RET ;Возврат в DOS
MMM ENDP
CODE ENDS ;Конец сегмента
END MMM ;Конец программы.
Сохранение регистров
Процедура, используя регистры для своих целей, портит значения, которые, возможно, нужны вызывающей программе. Поэтому в начале процедуры необходимо сохранить в стеке значения всех используемых процедурой регистров, а в конце – восстановить их. Кроме, естественно, тех регистров, через которые возвращается результат работы процедуры.