Иллюстрированный самоучитель по Assembler

Вызовы подпрограмм

Прямой дальний вызов

Этот вызов позволяет обратиться к подпрограмме из другого сегмента. В код команды, кроме кода операции 9Ah, входит полный адрес (сегмент плюс смещение) вызываемой подпрограммы. Обычно в исходном тексте программы с помощью описателя far ptr указывается, что вызов является дальним, хотя, если транслятор настроен на трансляцию в два прохода, этот описатель не обязателен. Структура программного комплекса, содержащая дальний вызов подпрограммы, может выглядеть следующим образом:

code1 segment
assume CS:code1
main proc; Основная программа
call far ptr subr; Код 9А dddd ssss
…
main endp
code1 ends
code2 segment
assume CS:code2
subr proc far; Объявляем подпрограмму дальней
…
ret; Код СВ – дальний возврат
subr endp
code2 ends

Процедура-подпрограмма находится в другом сегменте команд той же программы. В коде команды dddd обозначает относительный адрес точки входа в подпрограмму в ее сегменте команд, a ssss – се сегментный адрес. При выполнении команды call процессор помещает в стек сначала сегментный адрес вызывающей программы, а затем относительный адрес возврата (рис. 2.17). Далее в сегментный регистр CS заносится 5555 (у нас это значение code2), а в IP – dddd (у нас это значение subr).

Поскольку процедура-подпрограмма атрибутом far объявлена дальней, команда ret имеет код, отличный от кода аналогичной команды ближней процедуры и выполняется по-другому: из стека извлекаются два верхних слова и переносятся в IP и CS, чем и осуществляется возврат в вызывающую программу, находящуюся в другом сегменте команд. В языке ассемблера существует и явное мнемоническое обозначение команды дальнего возврата – retf.

Иллюстрированный самоучитель по Assembler › Основы программирования › Вызовы подпрограмм
Рис. 2.17. Участие стека в механизме вызова дальней подпрограммы.

Косвенный ближний вызов

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

code segment
main proc; Основная программа
…
call DS:subadr; Код FF 16 dddd
main endp
subr proc near; Подпрограмма
…
ret; Код С3
subr endp
code ends
data segment
…
subadr dw subr; Ячейка с адресом подпрограммы
data ends

Процедура-программа с атрибутом near находится в том же сегменте, что и вызывающая программа, а ее относительный адрес в ячейке subadr в сегменте данных. В коде команды dddd обозначает относительный адрес слова subadr в сегменте данных. Второй байт кода команды (16h в данном примере) зависит от способа адресации. Косвенный вызов позволяет использовать разнообразные способы адресации подпрограммы:

call BX; В ВХ адрес подпрограммы
call[BX]; В ВХ адрес ячейки с адресом подпрограммы
call[BX][SI];В ВХ адрес таблицы адресов подпрограмм,
;в SI индекс в этой таблице.
tbl[SI];tbl – адрес таблицы адресов подпрограмм,
;в SI индекс в этой таблице

Косвенный дальний вызов

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

code1 segment
main proc; Основная программа
call dword ptr subadr; Код FF IE dddd
…
main endp
code1 ends
code2 segment
subr proc far; Подпрограмма
…
ret; Код СВ
subr endp
code2 ends
data segment
…
subadr dd subr; Двухсловная ячейка с
;адресом подпрограммы
data ends

Процедура-подпрограмма с атрибутом far находится в другом сегменте команд той же программы, а ее полный двухсловный адрес – в ячейке subadr в сегменте данных. Второй байт кода команды (IE в данном примере) зависит от способа адресации. Косвенный дальний вызов, как и косвенный ближний, позволяет использовать различные способы адресации.

Если Вы заметили ошибку, выделите, пожалуйста, необходимый текст и нажмите CTRL + Enter, чтобы сообщить об этом редактору.