Шаг 38.
Использование директив EXTRN и PUBLIC
На этом шаге мы рассмотрим передачу параметров с посощью директив EXTRN и PUBLIC.
Эти директивы мы уже упоминали выше, когда рассматривали варианты взаимного расположения вызывающей программы
и вызываемой процедуры, Ко всему сказанному добавим, что директивы EXTRN и PUBLIC также можно
использовать для обмена информацией между модулями. Назначение и форматы этих директив уже были рассмотрены,
поэтому сейчас опишем только порядок их использования для обмена данными. Можно выделить несколько вариантов их применения:
Рассмотрим эти варианты на примере программы, которая определяет в сегменте данных две символьные строки и
вызывает процедуру, выводящую эти символы на экран.
Вариант 1. Два модуля используют только сегмент данных вызывающей программы (листинги 38.1 и 38.2).
В этом случае не требуется переопределения сегмента данных в вызываемой процедуре. В листинге 38.1 в вызывающей программе
определены две переменные, вывод на экран которых осуществляет вызываемая программа (листинг 38.2).
Листинг 38.1:
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
Текст этой программы можно взять
здесь.
Листинг 38.2:
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. У каждого из модулей есть свой собственный сегмент данных.
В этом случае для доступа к переменным из своего модуля требуется переопределение сегмента данных
в вызываемой процедуре.
Листинг 38.3:
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).
Данное значение атрибута комбинирования заставляет компоновщик объединить последовательно сегменты с одинаковыми
именами. Все адреса и смещения будут вычисляться относительно начала этого нового сегмента. В этом случае не понадобится
производить дополнительной настройки сегментных регистров (как было в предыдущих случаях).
Листинг 38.4:
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
Текст этой программы можно взять
здесь.
Листинг 38.5:
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
Текст этого модуля можно взять
здесь.
Мы разобрали способы передачи параметров в процедуру. Рассмотрим теперь механизм возврата результатов из
процедуры.
На следующем шаге мы рассмотрим организацию возврата данных из процедуры.
Предыдущий шаг
Содержание
Следующий шаг