На этом шаге мы рассмотрим организацию передачи аргументов через общую область памяти.
Этот вариант передачи аргументов предполагает, что вызывающая и вызываемая программы условились использовать некоторую область памяти как общую. Транслятор предоставляет специальное средство для организации такой области памяти. На шаге 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 для передачи данных в процедуру.