C
CALL Вызов подпрограммы
Команда call передает управление подпрограмме, сохранив перед этим в стеке смещение к точке возврата. Команда ret, которой обычно заканчивается подпрограмма, забирает из стека адрес возврата и возвращает управление на команду, следующую за командой call. Команда не воздействует на флаги процессора.
Команда call имеет четыре модификации:
- вызов прямой ближний (в пределах текущего программного сегмента);
- вызов прямой дальний (вызов подпрограммы, расположенной в другом программном сегменте);
- вызов косвенный ближний;
- вызов косвенный дальний.
Все разновидности вызовов имеют одну и ту же мнемонику call, хотя и различающиеся коды операций. Во многих случаях транслятор может определить вид вызова по контексту, в тех же случаях, когда это невозможно, следует использовать атрибутные операторы:
- near ptr – прямой ближний вызов;
- far ptr – прямой дальний вызов;
- word ptr – косвенный ближний вызов;
- dword ptr – косвенный дальний вызов.
Команда call прямого ближнего вызова заносит в стек относительный адрес точки возврата в текущем программном сегменте и модифицирует IP так, чтобы в нем содержатся относительный адрес точки перехода в том же программном сегменте. Необходимая для вычисления этого адреса величина смещения от точки возврата до точки перехода содержится в коде команды, который занимает 3 байт (код операции E8h и смещение к точке перехода).
Команда call прямого дальнего вызова заносит в стек два слова – сначала сегментный адрес текущего программного сегмента, а затем (выше, в слово с меньшим адресом) относительный адрес точки возврата в текущем программном сегменте. Далее модифицируются регистры IP и CS: в IP помещается относительный адрес точки перехода в том сегменте, куда осуществляется переход, а в CS – сегментный адрес этого сегмента. Обе эти величины берутся из кода команды, который занимает 5 байтов (код операции 9А1г, относительный адрес вызываемой подпрограммы и ее сегментный адрес).
Косвенные вызовы отличаются тем, что адрес перехода извлекается не из кода команды, а из ячеек памяти; в коде команды содержится информация о том, где находится адрес вызова. Длина кода команды зависит от используемого способа адресации.
Примеры прямого ближнего вызова:
call near ptr subl; Вызов подпрограммы subl ;из того же сегмента call subl; To же самое
Косвенные ближние вызовы.
Пример 1:
mov BX,offset subl; ВХ=адрес подпрограммы call BX; Вызов подпрограммы
Пример 2:
; В полях данных: addr dw subl; Ячейка с адресом подпрограммы ;В программном сегменте: call DS:addr; Вызов подпрограммы call word ptr addr; To же самое
Пример 3:
;В полях данных: addr dw subl; Ячейка с адресом подпрограммы ;В программном сегменте: mov SI,offset addr; SI=адрес ячейки с адресом ;подпрограммы call [SI]; Вызов подпрограммы
Пример 4:
;В полях данных: tbl dw subl; Ячейка с адресом ;подпрограммы 1 dw sub2; Ячейка с адресом ;подпрограммы 2 dw sub3; Ячейка с адресом ;подпрограммы 3 ;В программном сегменте: mov BX,offset tbl; ВХ=адрес таблицы адресов подпрограмм mov SI, 2; SI=смещение к адресу sub2 call [BX] [SI]; Вызов подпрограммы 2