На этом шаге мы рассмотрим организацию передачи аргументов через общую область памяти.
Этот вариант передачи аргументов предполагает, что вызывающая и вызываемая программы условились использовать некоторую область памяти как общую. Транслятор предоставляет специальное средство для организации такой области памяти. На шаге 18 мы разбирали директивы сегментации и их атрибуты. Один из них - атрибут комбинирования сегментов ("комбинация"). Наличие этого атрибута указывает компоновщику как нужно комбинировать сегменты, имеющие одно имя. Значение COMMON означает, что все сегменты, имеющие одинаковое имя в объединяемых модулях, будут располагаться компоновщиком, начиная с одного адреса оперативной памяти. Это значит, что они будут просто перекрываться в памяти и, следовательно, совместно использовать выделенную память.
Недостатком этого способа в реальном режиме работы микропроцессора является отсутствие средств защиты данных от разрушения, так как нельзя проконтролировать соблюдение правил доступа к этим данным. В защищенном режиме ситуация выглядит лучше.
Рассмотрим листинги 37.1 и 37.2 с примером использования общей области памяти для обмена данными между модулями. На этот раз программа состоит уже из двух независимых модулей, находящихся в разных файлах, и поэтому они представляют собой отдельные единицы трансляции. Функционально эти модули реализуют несложную задачу, которая заключается в том, что вызываемые процедуры формируют строку символов и передают ее через общую область, а вызывающая их процедура Begin выводит строку на экран.
TITLE Передача аргументов через общую область памяти
;Программа сделана как EXE-файл.
;-------------------------------
EXTRN PutChar: FAR, PutCharEnd: FAR ;Внешние процедуры.
;----- Сегмент стека
StackSg SEGMENT PARA STACK 'Stack'
DW 256 DUP(?)
StackSg ENDS
;----- Сегмент данных.
DataSg SEGMENT PARA COMMON 'Data'
;----- Начало общей области памяти.
Buf DB 15 DUP (" ") ;Буфер для хранения строки.
temp DW 0 ;Длина текущей строки.
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 PutChar
CALL PutCharEnd
;Вывод строки на экран:
MOV AH,09H
LEA DX,Buf
INT 21H
RET
Begin ENDP
CodeSg ENDS
END Begin
TITLE Передача аргументов через общую область памяти
;Модуль, где находится описание внешних процедур.
;-------------------------------
PUBLIC PutChar, PutCharEnd ;Возвращаемые процедуры.
;----- Сегмент стека
StackSg SEGMENT PARA STACK 'Stack'
DW 256 DUP(?)
StackSg ENDS
;----- Сегмент данных.
DataSg SEGMENT PARA COMMON 'Data'
;----- Начало общей области памяти.
Buffer DB 15 DUP(" ") ;Буфер для хранения строки.
tmpSI DW 0 ;Длина текущей строки.
DataSg ENDS
;----- Сегмент кодов.
CodeSg SEGMENT PARA
ASSUME CS: CodeSg, DS: DataSg, SS: StackSg
PutChar PROC FAR
MOV SI,0
MOV Buffer[SI],'Р'
INC SI
MOV Buffer[SI],'а'
INC SI
MOV Buffer[SI],'б'
INC SI
MOV Buffer[SI],'о'
INC SI
MOV Buffer[SI],'т'
INC SI
MOV Buffer[SI],'а'
INC SI
MOV Buffer[SI],'е'
INC SI
MOV Buffer[SI],'т'
INC SI
MOV Buffer[SI],'!'
INC SI
MOV tmpSI,SI
RET
PutChar ENDP
PutCharEnd PROC FAR
MOV SI,tmpSI
MOV Buffer[SI],'$'
RET
PutCharEnd ENDP
CodeSg ENDS
END
Обратите внимание, что совсем не обязательно, чтобы данные в сегментах COMMON имели одинаковые имена. Главное, и за этим нужно следить с особой тщательностью, - структура общих сегментов. Она должна быть абсолютно идентична во всех модулях данной программы, использующих обмен данными через общую память.
Так как в данном примере программа состоит уже из двух модулей, то у читателя наверняка возник вопрос, как собрать ее в один исполняемый модуль. Можно предложить следующую последовательность шагов:
link.exe pr37_1.obj + pr37_2.obj
На следующем шаге мы рассмотрим использование директив EXTRN и PUBLIC для передачи данных в процедуру.