Часто в программах, особенно больших, приходится несколько раз решать одну и ту же подзадачу и при этом приходится многократно выписывать одинаковую группу команд, решающих эту подзадачу. чтобы избежать повторного выписывания такой группы команд, ее обычно записывают один раз и оформляют соответствующим образом, а затем в нужных местах программы просто передают управление на эти команды, которые, проработав, возвращают управление обратно. В языке ассемблера есть несколько средств, решающих проблему дублирования фрагментов программного кода. К ним относятся:
- процедуры;
- макроподстановки (макроассемблер);
- генерация и обработка программных прерываний.
Процедура (подпрограмма) - это основная функциональная единица декомпозиции (разделения на части) некоторой задачи. Процедура представляет собой группу команд для решения конкретной подзадачи и обладает средствами получения управления из точки вызова задачи более высокого уровня и возврата управления в эту точку.
|
|
Размещать подпрограмму можно где угодно. Но сама подпрограмма не должна выполняться, а может выполняться лишь тогда, когда к ней обратятся. Если имеется несколько подпрограмм, то их обычно размещают рядом. Обычно подпрограммы размещают либо в конце сегмента команд за командой FINISH (1), либо в самом начале этого сегмента - перед той командой, с которой должно начинаться выполнение программы (2). В больших программах подпрограммы часто размещают в отдельном сегменте команд (3). Главная цель таких вариантов размещения - не допустить несанкционированной передачи управления коду процедуры.
C SEGMENT
BEG: ….
….
FINISH
подпрограмма |
C ENDS
END BEG
C SEGMENT
подпрограмма |
BEG: ….
….
C ENDS
END BEG
C1 SEGMENT
подпрограмма |
C1 ENDS
C SEGMENT
BEG: …..
…..
C ENDS
END BEG
Подпрограммы принято оформлять специальным образом - в виде процедур.
Директива PROC
<имя-процедуры> PROC <параметр>
<тело процедуры>
<имя-процедуры> ENDP
Имя процедуры должно обязательно присутствовать. Параметр у директивы PROC может быть NEAR (близкий) и FAR (дальний). К близкой процедуре можно обращаться только из того сегмента команд, где она описана, и нельзя обращаться из других сегментов, а к дальней процедуре можно обращаться из любых сегментов команд. Имена и метки, описанные в процедуре, не локализуются внутри нее.
Обратиться к процедуре можно с помощью любой команды перехода.
Команда CALL осуществляет вызов процедуры (подпрограммы).
Команда RET осуществляет возврат из процедуры.
call имя_процедуры
Аналогично команде JMP передает управление по адресу, но при этом в стеке сохраняется адрес возврата (т. е. адрес команды, следующей после команды CALL).
|
|
При внутрисегментном вызове процедура находится в текущем сегменте кода, и в качестве адреса возврата команда CALL сохраняет только содержимое регистра IP.
При межсегментном вызове процедура находится в другом сегменте кода, и для осуществления возврата команда CALL должна запомнит содержимое обоих регистров CS и IP, при этом в стеке сначала запоминается содержимое регистра CS, затем - регистра IP.
Одна и та же процедура не может быть одновременно процедурой ближнего и дальнего типов.