Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС_лаб3_6_Полн.doc
Скачиваний:
7
Добавлен:
06.05.2019
Размер:
334.34 Кб
Скачать

3.2.2. Подпрограммы (процедуры)

Довольно часто в программах, особенно больших, приходится несколько раз решать одну и ту же подзадачу и потому приходится многократно выписывать одинаковую группу команд, решающих эту подзадачу. Чтобы избежать повторного выписывания такой группы команд, ее обычно выписывают один раз и оформляют соответствующим образом, а затем в нужных местах программы просто передают управление на эти команды, которые, проработав, возвращают управление обратно. Такая группа команд, которая решает некоторую подзадачу и которая организована таким образом, что ее можно использовать любое число раз и из любых мест, называется подпрограммой. По отношению к подпрограмме остальную часть программы принято называть основной программой. Аналог подпрограмм на языках высокого уровня называется процедурой.

Размещение подпрограммы

Обычно подпрограммы (п/п) размещают либо в конце сегмента команд за командой FINISH (см. рисунок а), либо в самом начале этого сегмента - перед той командой, с которой должно начинаться выполнение программы (см. рисунок б). В больших программах подпрограммы нередко размещают в отдельном сегменте команд (см. рисунок в).

Варианты размещения подпрограммы в тексте программы

Оформление подпрограммы

Описание подпрограммы в виде процедуры выглядит так:

<имя процедуры> PROC <параметр>

<тело процедуры>

<имя процедуры> ENDP

Перед телом процедуры (ее командами) ставится директива PROC (procedure), а за ним - директива ENDP (end of procedure). В обеих этих директивах указывается одно и то же имя - имя, присвоенное процедуре.

У директивы PROC есть параметр - это либо NEAR (близкий), либо FAR (дальний). Параметр может и отсутствовать, тогда считается, что он равен NEAR (в связи с этим параметр NEAR обычно не указывается). При параметре NEAR или при отсутствии параметра процедура называется "близкой", при параметре FAR - "дальней". К близкой процедуре можно обращаться только из того сегмента команд, где она описана, и нельзя обращаться из других сегментов, а к дальней процедуре можно обращаться из любых сегментов команд (в том числе и из того, где она описана). В этом и только в этом различие между близкими и дальними процедурами.

Вызов процедур и возврат из них

Существуют специальные команды, упрощающие реализацию вызова процедуры и возврат из нее.

Команда вызова процедуры записывается следующим образом:

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 ;Конец программы.

Сохранение регистров

Процедура, используя регистры для своих целей, портит значения, которые, возможно, нужны вызывающей программе. Поэтому в начале процедуры необходимо сохранить в стеке значения всех используемых процедурой регистров, а в конце – восстановить их. Кроме, естественно, тех регистров, через которые возвращается результат работы процедуры.

Передача параметров через стек

Существует еще один способ передачи параметров: вызывающая программа должна перед вызовом процедуры записать параметры в стек.

Различают передачу параметра по значению (в стек записывается значение параметра) и по ссылке (в стек записывается адрес переменной-параметра). Чтобы потом можно было обратиться к параметрам процедуры, следует воспользоваться регистром BP (сначала передать в BP адрес вершины стека, а затем использовать выражения вида [BP+i] для доступа к параметрам процедуры). Но сначала надо сохранить значение регистра BP в стеке, чтобы после окончания работы процедуры восстановить его обратно.

В конце работы процедура должна удалить параметры из стека. Для этого в команду RET добавляется числовой параметр, указывающий, сколько байтов надо удалить из стека (если параметр не указывается, то команда воспринимается как RET 0, т.е. возврат из процедуры без очистки стека).

RET 2*k ;удаление k параметров

Пример. Создать процедуру обнуления n байтов памяти по адресу X. Параметры передаются через стек.

S SEGMENT STACK ; Сегмент стека

DB 200 DUP(0ABh)

S ENDS

D SEGMENT ; Сегмент данных

X DB 20 DUP (1)

Y DB 10 DUP (2)

D ENDS

CODE SEGMENT ; Сегмент кода

ASSUME SS:S,CS:Code, DS:D

; Процедура обнуления n байтов памяти по заданному

; адресу. Параметры передаются через стек.

NUL PROC

PUSH BP; ; Сохранение значения

; регистра BP

MOV BP, SP ; Установка в BP

;адреса вершины стека

PUSH BX ; Сохранение текущих значений

PUSH CX ; регистров BX и CX

; Извлечение из стека параметров процедуры

; в обратном порядке

MOV CX, [BP+4] ; CX:=N (второй параметр – число

; байтов – в счетчик цикла)

MOV BX, [BP+6] ; (первый параметр – адрес массива

; байтов – в регистр-модификатор

; для косвенной адресации)

L1: MOV BYTE PTR [BX], 0 ; обнуление байта

;по адресу из BX (т.е. обнуление текущего

;элемента массива)

INC BX

LOOP L1 ; Окончание тела цикла

POP CX ; Восстановление значений

POP BX ; регистров BX и CX,

POP BP ; а также регистра BP

RET 4 ; Возврат из процедуры с

; очищением стека от параметров

NUL ENDP ; Окончание процедуры

; Основная программа

MMM PROC FAR

; Выполнение на входе соглашений DOS

PUSH DS ; Запись содержимого DS в стек

SUB AX,AX ; Запись ноля

PUSH AX ; в стек

; Установка верного значения в регистре DS.

; Регистры CS и SS устанавливаются системой.

MOV AX,D ; Занесение адреса

MOV DS,AX ; D в DS

; Обнуление 20 байт по адресу X

LEA AX, X

PUSH AX ; Передача в стек 1-го параметра

; процедуры – адреса памяти,

; которую нужно очистить

MOV AX, 20

PUSH AX ; Передача в стек 2-го параметра

; процедуры – размера очищаемой

; области памяти в байтах

CALL NUL ; вызов

; Обнуление 10 байт по адресу Y

LEA AX, Y

PUSH AX ; Передача в стек 1-го параметра

; процедуры

MOV AX, 10

PUSH AX ; Передача в стек 2-го параметра

; процедуры

CALL NUL

RET ;Возврат в DOS

MMM ENDP

CODE ENDS ;Конец сегмента кода

END MMM ;Конец программы