Передача параметров

4.1. Записать в текстовом редакторе следующую программу в ЕХЕ-формате:

.286

TITLE CALLMUL4 (EXE) Передача параметров в подпрогр.

;-------------------------------------------------------

EXTRN SUBMUL4:FAR

;-------------------------------------------------------

STACKSG SEGMENT PARA STACK 'Stack'

DW 64 DUP(?)

STACKSG ENDS

;-------------------------------------------------------

DATASG SEGMENT PARA 'Data'

QTY DW 0140H

PRICE DW 2500H

DATASG ENDS

;--------------------------------------------------------

CODESG SEGMENT PARA PUBLIC 'Code'

BEGIN PROC FAR

ASSUME CS:CODESG,DS:DATASG,SS:STACKSG

PUSH DS

SUB AX,AX

PUSH AX

MOV AX,DATASG

MOV DS,AX

PUSH PRICE

PUSH QTY

CALL SUBMUL4 ;Вызвать подпрограмму

RET ;Вернуться в DOS

BEGIN ENDP

CODESG ENDS

END BEGIN

Записать эту программу на диск под именем callmul4.asm.

4.2. Записать в текстовом редакторе следующую подпрограмму:

.286

TITLE SUBMUL4 Вызываемая подпрограмма умножения

;------------------------------------------------------

CODESG SEGMENT PARA PUBLIC 'Code'

SUBMUL4 PROC FAR

ASSUME CS:CODESG

PUBLIC SUBMUL4

PUSH BP

MOV BP,SP

MOV AX,[BP+8] ;Стоимость

MOV BX,[BP+6] ;Количество

MUL BX ;Произведение в DX:AX

POP BP

RET 4 ;Вернуться в DOS

SUBMUL4 ENDP

CODESG ENDS

END

Записать эту подпрограмму на диск под именем submul4.asm.

4.3. Выполнить ассемблирование основной программы и подпрограммы.

Просмотреть листинги основной программы и подпрограммы и записать их в отчет.

В этом примере вызывающая программа физически передает данные через стек. Каждая команда PUSH должна записывать в стек данные размером в одно слово из памяти или из регистра.

Программа, прежде чем вызывать подпрограмму submul4, заносит в стек значения полей PRICE и QTY.

При выполнении программы в стек заносится следующая информация:

- Инициализирующая команда PUSH DS заносит адрес сегмента в стек. Этот адрес может отличаться в разных версиях DOS.

- Команда PUSH AX заносит в стек нулевой адрес.

- Команда PUSH PRICE заносит в стек слово (2500).

- Команда PUSH QTY заносит в стек слово (0140).

- Команда CALL заносит в стек содержимое регистра CS.

- Так как команда CALL представляет здесь межсегментный вызов, то в стек заносится также содержимое регистра IP.

Вызываемая программа использует регистр BP для доступа к параметрам в стеке, но прежде она запоминает содержимое регистра BP, записывая его в стек.

Затем программа помещает в регистр BP содержимое из регистра SP, так как в качестве индексного регистра может использоваться регистр BP, но не SP. Первоначально регистр SP содержал размер пустого стека. Запись каждого слова в стек уменьшает содержимое SP на 2.

Так как в стек было произведено 6 записей, то содержимое SP уменьшилось на 12. Цена (PRICE) является 3-й записью, следовательно для доступа к 3-й записи число в регистре BP нужно увеличить на 8, что соответствует перемещению в стеке на 4 записи назад. Количество (QTY) является 4-й записью, следовательно для доступа к 4-й записи число в регистре BP нужно увеличить на 6, что соответствует перемещению в стеке на 3 записи назад. Так формируются адреса полей для пересылки содержимого этих полей из стека в регистры АХ и ВХ, содержимое самого регистра BP при этом не изменяется. Далее происходит перемножение данных регистров АХ и ВХ.

Перед возвратом в вызывающую программу в регистре BP восстанавливается первоначальное значение, а содержимое в регистре SP увеличивается на 2.

Последняя команда RET представляет собой "длинный" возврат в вызывающую программу. По этой команде выполняются следующие действия:

- Из вершины стека восстанавливается значение регистра IP.

- Содержимое регистра SP увеличивается на 2.

- Из новой вершины стека восстанавливается значение регистра CS.

- Содержимое регистра SP увеличивается на 2.

Команда RET закодирована как:

RET 4

Параметр 4 представляет собой количество байтов в стеке, использованных при передаче параметров (два слова в данном примере). Команда RET прибавит этот параметр к содержимому регистра SP. Таким образом, из стека исключаются не нужные больше параметры. Необходимо быть особенно внимательным при восстановлении регистра SP - ошибки могут привести к непредсказуемым результатам.

4.4. Выполнить компоновку программы. Выполнить трассировку программы с помощью отладчика DEBUG. Внимательно проследить за изменением регистров CS, IP, SP, BP а также содержимого сегмента стека, начальный адрес которого указывается в регистре SS. Выводы о работе программы записать в отчет.

СОДЕРЖАНИЕ ОТЧЕТА:

1. Листинги программ и подпрограмм.

2. Выводы о работе программ.

КОНТРОЛЬНЫЕ ВОПРОСЫ:

1. Предположим, что программа MAINPRO должна вызывать подпрограмму SUBPRO. а) Какая директива в программе MAINPRO указывает ассемблеру, что имя SUBPRO определено вне ее собственного кода?

б) Какая директива в программе SUBPRO необходима для того, чтобы имя точки входа было доступно в основной программе MAINPRO?

2. Предположим, что в программе MAINPRO определены переменные QTY как DB, VALUE как DW и PRICE как DW. Подпрограмма SUBPRO должна разделить VALUE на QTY и записать частное в PRICE. а) Каким образом программа MAINPRO указывает ассемблеру, что три переменные должны быть доступны извне основной программы? б) Каким образом подпрограмма SUBPRO указывает ассемблеру, что три переменные определены в другом модуле?

ОТВЕТЫ:

1. а) EXTRN SUBPRO:FAR б) PUBLIC SUBPRO

2. а) PUBLIC QTY,VALUE,PRICE б) EXTRN QTY:WORD,VALUE:WORD,PRI-

CE:WORD

Наши рекомендации