Материал: 775

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

4. СВЕДЕНИЯ, НЕОБХОДИМЫЕ ДЛЯ ВЫПОЛНЕНИЯ ЛАБОРАТОРНОЙ РАБОТЫ

4.1. Программы, состоящие из нескольких модулей

Использование для исходного кода программы одного файла подходит для небольших программ, но даже программы среднего размера приходится разбивать на несколько файлов или модулей, которые ассемблируются отдельно и компонуются вместе. Основное преимущество программ, состоящих из нескольких модулей, состоит в том, что после того, как вы отредактируете исходный код, вам потребуется переассемблировать только те модули, которые вы изменили, не затрагивая остальных модулей программы.

Для создания программы, состоящей из нескольких модулей, ассемблер предусматривает три директивы: public, extrn и global.

Пример программы, состоящей из двух модулей (см. пример 2.1). Основная программа l_1a#.asm имеет следующий вид:

;-------

;EXE-программа. Модуль 1-й "Вызов процедуры умножения" (l_1a#.asm) extrn submul:far

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

stacksg segment para Stack 'Stack' dw 64 dup (?)

stacksg ends ;-----------------------------------------------

datasg segment para 'Data'

qty

dw 0002h

;количество

price dw 0004h

;стоимость

msg

db '0',0dh,0ah,'$'

 

datasg ends

 

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

 

 

codesg segment para 'Code'

 

assume cs:codesg,ds:datasg,ss:stacksg

begin proc far

 

 

push ds

 

 

xor ax,ax

 

 

push ax

 

 

mov ax,datasg

 

 

mov ds,ax

 

 

mov ax,price

;ax:= стоимость (price)

 

mov bx,qty

;bx:= количество (qty)

 

 

16

call submul

;вызвать подпрограмму submul (внешнюю)

;результат возвращается в регистрах (dx:ax)

;в частном случае (для заданных данных), т.е. когда получается однораз-

;рядное десятичное число, предусмотрен вывод результата на экран

or al,30h

; преобразование в код ASCII

mov msg,al

 

mov ah,09h

; вывод на экран полученного значения

lea dx,msg

 

int 21h

 

ret

; возврат в DOS

begin endp codesg ends

end begin

;------- Модуль 2-й "Процедура умножения" (l_1b#.asm) codesg segment para 'Code'

submul proc far assume cs:codesg public submul

; параметры процедуре передаются в регистрах ax и bx

mul bx ; результат (произведение) возвращается в (dx:ax) ret

submul endp codesg ends

end ;-------

Эти два модуля ассемблируются отдельно с помощью команд: tasm l_1a#.asm

и

tasm l_1b#.asm

а затем компонуются в программу l_1a#.exe с помощью команды: tlink l_1a#.obj+ l_1b#.obj

При запуске программы l_1a#.exe на экран выводится результат совместной работы двух модулей, т.е. произведение price и qty: 8.

Теперь, когда вы увидели программу, состоящую из нескольких модулей, в действии, рассмотрим три директивы, обеспечивающие такое программирование.

4.2. Директива public

Она указывает ассемблеру, что соответствующую метку или метки нужно сделать доступными для других модулей. Здесь можно использовать практически любые метки, включая имена процедур и

17

переменных памяти, а также приравненные метки. Директива public обеспечивает доступность этих меток другим модулям. Например:

datasg segment para ‘Data’

 

public

MemVar, Array1, array_length

array_length equ

100

MemVar

dw

10

Array1

db

array_length dup (?)

datasg.ends

 

codesg segment para ‘Code’

 

public

NearProc, FarProc

NearProc

proc near

 

...

 

 

NearProc

endp

; ближняя процедура

...

 

 

FarProc

label proc ; дальняя процедура

codesg ends end

Здесь имена приравненной метки, переменной размером в слово, массива и процедуры с ближним типом обращения доступны другому модулю, который будет компоноваться с данным модулем.

Однако имеется один тип меток, которые нельзя сделать общедоступными. Это приравненные метки, которые равны значениямконстантам с размерами, отличными от 1 или 2 байтов. Например, следующие метки общедоступными сделать нельзя:

long_value equ 1000h text_symbol equ <TextString>

Ассемблер обычно игнорирует регистр буквы, поэтому все общедоступные метки преобразуются в прописные символы (верхний регистр). Если требуется, чтобы в общедоступных метках различались буквы верхнего и нижнего регистров, то при ассемблировании всех модулей, содержащих ссылки на такие метки, нужно использовать в командной строке Турбоассемблера параметр /ml или /mx.

Например, без параметра /mx или /ml в других модулях следующие две метки будут эквивалентными:

public Symbol1, symbol1

При использовании для обеспечения различимости строчных и прописных букв в общедоступных и внешних идентификаторах параметра командной строки /mx нужно внимательно указывать буквы верхнего или нижнего регистра в директивах public или extrn. Ассемблер делает доступным для других модулей тот идентификатор, который указывает в

18

директиве public или extrn, а не тот, на который делается ссылка или который переопределяется внутри модуля. Например, директива:

public Abc abC dw

приводит к тому, что общедоступным будет имя Abc, а не abC.

Для каждого идентификатора в директиве public можно также задать язык: C, FORTRAN, PASCAL, BASIC, PROLOG и notlanguage (нет языка). Это приводит к тому, что к имени идентификатора до того, как одно в объектном файле станет общедоступным, автоматически применяются правила конкретного языка. Например, если вы описали:

public C myprog

то идентификатор myprog в исходном файле станет общедоступным, как _myprog, поскольку по соглашениям языка Си перед именами идентификаторов следует символ подчеркивания. Использование идентификатора языка в директиве public временно отменяет текущее задание языка (используемое по умолчанию или заданное в директиве

.model).

4.3.Директива extrn

Впоследнем разделе, чтобы сделать метки MemVar, Array1, array_length, NearProc и FarProc доступными для других модулей, мы использовали директиву public. Но далее возникает вопрос, каким образом другие модули могут ссылаться на эти метки?

Для того, чтобы сделать метки из другого модуля доступными в данном модуле, используется директива extrn. После того, как директива extrn будет использована, чтобы сделать доступным в данном модуле метку из другого модуля, эту метку можно использовать так же, как если бы она была определена в текущем модуле. Приведем пример другого модуля, в котором директива extern используется для ссылок на общедоступные метки, описанные в последнем разделе:

datasg segment para ‘Data’

extrn MemVar:word,Array1:byte,array_length:abs datasg.ends

codesg segment para ‘Code’

extrn NearProc:near,FarProc:far

...

mov ax,[MemVar] mov bx,offset Array1 mov cx,array_length

...

call NearProc

19

...

call FarProc codesg ends

Заметим, что все пять меток используются, как обычно. Единственным отличием от программы на ассемблере, состоящей из одного модуля, является директива extrn.

За каждой меткой, объявленной в директиве extrn, следует двоеточие и тип. Тип необходимо указывать, иначе ассемблер не будет знать, какую именно метку вы объявляете с помощью директивы extrn. Допустимы следующие типы:

abs– абсолютное значение;

byte – переменная (данные) размером в байт;

dword – переменная (данные) размером в двойное слово (4 байта); dataptr – указатель на данные ближнего или дальнего типа (зависит от

модели памяти);

far – метка кода с дальним типом обращения (переход – загрузкой регистров cs:ip);

fword – 6-байтовая переменная (данные);

near – метка кода с ближним типом обращения (переход – загрузкой регистра ip);

proc – метка процедуры (near или far, в соответствии с директивой

.model);

qword – переменная (данные) размером в четверное слово (8 байтов); Имя структуры – имя определенного пользователем типа struc;

tbyte – 10-байтовая переменная (данные); unknown – неизвестный тип;

word – переменная (данные) размером в слово (2 байта).

Тип внешних данных abs используется для объявления метки, определенной в ее исходном модуле с помощью директивы equ или =. Другими словами, это метка, которая просто представляет собой имя константы и не связана с адресами кода или данных.

Очень важно, чтобы для внешних меток вы задавали корректный тип данных, так как ассемблер будет генерировать код на основе заданных типов данных и у него нет другого способа определить, что ваша спецификация некорректна. Например, если вы случайно ввели:

codesg segment para ‘Code’

extrn

FarProc:near

. . .

 

call

FarProc

. . .

 

 

20

Источник: https://studfile.net/preview/16406832/