На этом шаге мы рассмотрим передачу параметров с посощью директив EXTRN и PUBLIC.
Эти директивы мы уже упоминали выше, когда рассматривали варианты взаимного расположения вызывающей программы и вызываемой процедуры, Ко всему сказанному добавим, что директивы EXTRN и PUBLIC также можно использовать для обмена информацией между модулями. Назначение и форматы этих директив уже были рассмотрены, поэтому сейчас опишем только порядок их использования для обмена данными. Можно выделить несколько вариантов их применения:
Рассмотрим эти варианты на примере программы, которая определяет в сегменте данных две символьные строки и вызывает процедуру, выводящую эти символы на экран.
Вариант 1. Два модуля используют только сегмент данных вызывающей программы (листинги 38.1 и 38.2). В этом случае не требуется переопределения сегмента данных в вызываемой процедуре. В листинге 38.1 в вызывающей программе определены две переменные, вывод на экран которых осуществляет вызываемая программа (листинг 38.2).
TITLE Первый вариант использования директив EXTRN и PUBLIC ;Программа сделана как EXE-файл. ;------------------------------- EXTRN My_Proc2: FAR ;Внешняя процедура. PUBLIC Per1, Per2 ;Экспортируемые переменные. ;----- Сегмент стека StackSg SEGMENT PARA STACK 'Stack' DW 256 DUP(?) StackSg ENDS ;----- Сегмент данных. DataSg SEGMENT PARA Per1 DB "1$" ;Первая переменная. Per2 DB "2$" ;Вторая переменная. DataSg ENDS ;----- Сегмент кодов. CodeSg SEGMENT PARA ASSUME CS: CodeSg, DS: DataSg, SS: StackSg Begin PROC FAR ;Пролог EXE-файла. PUSH DS XOR AX,AX PUSH AX MOV AX, DataSg MOV DS,AX ;Конец пролога ;Вызов внешней процедуры: CALL My_Proc2 RET Begin ENDP CodeSg ENDS END Begin
TITLE Вызываемый модуль ;Он подключается на этапе компоновки. ;------------------------------- EXTRN Per1: BYTE, Per2: BYTE ;Внешние переменные. PUBLIC My_Proc2 ;Экспортируемая процедура. CodeSg SEGMENT PARA ASSUME CS: CodeSg My_Proc2 PROC FAR MOV AH,09H LEA DX, Per1 INT 21H MOV AH,09H LEA DX, Per2 INT 21H RET My_Proc2 ENDP CodeSg ENDS END
Вариант 2. У каждого из модулей есть свой собственный сегмент данных. В этом случае для доступа к переменным из своего модуля требуется переопределение сегмента данных в вызываемой процедуре.
TITLE Вызываемый модуль ;Он подключается на этапе компоновки. ;Вызывающий модуль - тот же. ;------------------------------- EXTRN Per1: BYTE, Per2: BYTE ;Внешние переменные. PUBLIC My_Proc2 ;Экспортируемая процедура. ;----- Сегмент данных. DataSg SEGMENT PARA Per0 DB "0$" ;Еще одна переменная. DataSg ENDS ;----- Сегмент кодов. CodeSg SEGMENT PARA ASSUME CS: CodeSg, DS: DataSg My_Proc2 PROC FAR ;======================= ;На момент начала процедуры DS ;содержит адрес сегмента данных вызываемого модуля. ;Поэтому выводим значения переменных Per1 и Per2 ;======================= MOV AH,09H LEA DX, Per1 INT 21H MOV AH,09H LEA DX, Per2 INT 21H ;---------Переопределяем сегмент данных. PUSH DS ;Сохранили DS. MOV AX, SEG Per0 ;Сегментный адрес Per0 в DS. MOV DS,AX MOV AH,09H LEA DX, Per0 INT 21H POP DS ;Восстановили DS. ;---------- Еще раз вывели Per1 и Per2. MOV AH,09H LEA DX, Per1 INT 21H MOV AH,09H LEA DX, Per2 INT 21H RET My_Proc2 ENDP CodeSg ENDS END
Вариант З. Использование атрибута комбинирования (объединения) сегментов PUBLIC в директиве сегментации SEGMENT для сегментов данных модулей (листинги 38.4 и 38.5). Данное значение атрибута комбинирования заставляет компоновщик объединить последовательно сегменты с одинаковыми именами. Все адреса и смещения будут вычисляться относительно начала этого нового сегмента. В этом случае не понадобится производить дополнительной настройки сегментных регистров (как было в предыдущих случаях).
TITLE Третий вариант использования директив EXTRN и PUBLIC ;Программа сделана как EXE-файл. ;------------------------------- EXTRN My_Proc2: FAR, Per0: BYTE ;Внешняя процедура и переменная. PUBLIC Per1, Per2 ;Экспортируемые переменные. ;----- Сегмент стека StackSg SEGMENT PARA STACK 'Stack' DW 256 DUP(?) StackSg ENDS ;----- Сегмент данных. DataSg SEGMENT PARA PUBLIC 'Data' Per1 DB "1$" ;Первая переменная. Per2 DB "2$" ;Вторая переменная. DataSg ENDS ;----- Сегмент кодов. CodeSg SEGMENT PARA ASSUME CS: CodeSg, DS: DataSg, SS: StackSg Begin PROC FAR ;Пролог EXE-файла. PUSH DS XOR AX,AX PUSH AX MOV AX, DataSg MOV DS,AX ;Конец пролога. ;Вывод значения внешней переменной. MOV AH,09H LEA DX,Per0 INT 21H ;Вызов внешней процедуры: CALL My_Proc2 RET Begin ENDP CodeSg ENDS END Begin
TITLE Вызываемый модуль ;Он подключается на этапе компоновки. ;------------------------------- EXTRN Per1: BYTE, Per2: BYTE ;Внешние переменные. PUBLIC My_Proc2, Per0 ;Экспортируемая процедура и переменная. ;----- Сегмент данных. DataSg SEGMENT PARA PUBLIC 'Data' Per0 DB "0$" ;Еще одна переменная. DataSg ENDS ;----- Сегмент кодов. CodeSg SEGMENT PARA ASSUME CS: CodeSg, DS: DataSg My_Proc2 PROC FAR ;-------- Вывод переменных. MOV AH,09H LEA DX, Per0 INT 21H MOV AH,09H LEA DX, Per1 INT 21H MOV AH,09H LEA DX, Per2 INT 21H RET My_Proc2 ENDP CodeSg ENDS END
Мы разобрали способы передачи параметров в процедуру. Рассмотрим теперь механизм возврата результатов из процедуры.
На следующем шаге мы рассмотрим организацию возврата данных из процедуры.