Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Абель.docx
Скачиваний:
13
Добавлен:
26.11.2018
Размер:
569.84 Кб
Скачать

04Af в регистр cs. Комбинация этих адресов указывает на первую выполняемую

команду в вызываемой подпрограмме:

Кодовый сегмент 04AF0

Смещение в IP 0200

Действительный адрес 04CF0

При выходе из вызванной процедуры межсегментная команда возврата REP

восстанавливает оба адреса в регистрах CS и IP и таким образом передает

управление на следующую после CALL команду.

АТРИБУТЫ EXTRN и PUBLIC

________________________________________________________________

Рассмотрим основную программу (MAINPROG), которая вызывает

подпрограмму (SUBPROG) с помощью межсегментного CALL, как показано на

рис.21.2.

Команда CALL в MAINPROG должна "знать", что SUBPROG существует вне

данного сегмента (иначе ассемблер выдаст сообщение о том, что

идентификатор SUBPROG не определен). С помощью директивы EXTRN можно

указать ассемблеру, что ссылка на SUBPROG имеет атрибут FAR,

т.е.определена в другом ассемблерном модуле. Так как сам ассемблер не

имеет возможности точно определить такие ссылки, он генерирует "пустой"

объектный код для последующего заполнения его при компановке:

9A 0000 ---- E

Подпрограмма SUBPROG содержит директиву PUBLIC, которая указывает

ассемблеру и компоновщику, что другой модуль должен "знать" адрес SUBPROG.

В последнем шаге, когда оба модуля MAINPROG и SUBPROG будут успешно

ассемблированы в объектные модули, они могут быть скомпонованы следующим

образом:

Запрос компоновщика LINK: Ответ:

Object Modules [.OBJ]: B:MAINPROG+B:SUBPROG

Run File [filespec.EXE]: B:COMBPROG (или другое имя)

List File [NUL.MAP]: CON

Libraries [.LIB]: [return]

Компоновщик устанавливает соответствия между адресами EXTRN в одном

объектном модуле с адресами PUBLIC в другом и заносит необходимые

относительные адреса. Затем он объединяет два объектных модуля в один

выполняемый. При невозможности разрешить ссылки компоновщик выдает

сообщения об ошибках. Следите за этими сообщениями прежде чем пытаться

выполнить программу.

__________________________________________________________________________

ЪДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДД¬

¦ EXTRN SUBPROG:FAR ¦

¦ MAINPROG: . ¦

¦ . ¦

¦ CALL SUBPROG ¦

¦ . ¦

¦ . ¦

ГДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДґ

¦ PUBLIC SUBPROG ¦

¦ SUBPROG: . ¦

¦ . ¦

¦ . ¦

¦ RET ¦

АДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДДЩ

__________________________________________________________________________

Рис.21.2. Межсегментный вызов.

Директива EXTRN

-----------------

Директива EXTRN имеет следующий формат:

EXTRN имя:тип [, ... ]

Можно определить более одного имени (до конца строки) или закодировать

дополнительные директивы EXTRN. В другом ассемблерном модуле

соответствующее имя должно быть определено и идентифицировано как PUBLIC.

Тип элемента может быть ABS, BYTE, DWORD, FAR, NEAR, WORD. Имя может быть

определено через EQU и должно удовлетворять реальному определению имени.

Директива PUBLIC

------------------

Директива PUBLIC указывает ассемблеру и компоновщику, что адрес

указанного идентификатора доступен из других программ. Директива имеет

следующий формат:

PUBLIC идентификатор [, ... ]

Можно определить более одного идентификатора (до конца строки) или

закодировать дополнительные директивы PUBLIC. Идентификаторы могут быть

метками (включая PROC-метки), переменными или числами. Неправильными

идентификаторами являются имена регистров и EQU-идентификаторы,

определяющие значения более двух байт.

Рассмотрим три различных способа компановки программ.

ПРОГРАММА: ИСПОЛЬЗОВАНИЕ ДИРЕКТИВ EXTRN и PUBLIC ДЛЯ МЕТОК

_______________________________________________________________

__________________________________________________________________________

page 60,132

TITLE CALLMULL1 (EXE) Вызов подпрограммы умнож.

EXTRN SUBMUL:FAR

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

0000 STACKSG SEGMENT PARA STACK 'Stack'

0000 40 [ ???? ] DW 64 DUP(?)

0080 STACKSG ENDS

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

0000 DATASG SEGMENT PARA 'Data'

0000 0140 QTY DW 0140H

0002 2500 PRICE DW 2500H

0004 DATASG ENDS

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

0000 CODESG SEGMENT PARA 'Code'

0000 BEGIN PROC FAR

ASSUME CS:CODESG,DS:DATASG,SS:STACKSG

0000 1E PUSH DS

0001 2B C0 SUB AX,AX

0003 50 PUSH AX

0004 B8 ---- R MOV AX,DATASG

0007 8E D8 MOV DS,AX

0009 A1 0002 R MOV AX,PRICE ;Загрузить стоимость

000C 8B 1E 0000 R MOV BX,QTY ; и количество

0010 9A 0000 ---- E CALL SUBMUL ;Вызвать подпрограмму

0015 CB RET

0016 BEGIN ENDP

0016 CODESG ENDS

END BEGIN

Segments and Groups:

N a m e Size Align Combine Class

CODESG . . . . . . . . . . . . 0016 PARA NONE 'CODE'

DATASG . . . . . . . . . . . . 0004 PARA NONE 'DATA'

STACKSG. . . . . . . . . . . . 0080 PARA STACK 'STACK'

Symbols:

N a m e Type Value Attr

BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0016

PRICE. . . . . . . . . . . . . L WORD 0002 DATASG

QTY. . . . . . . . . . . . . . L WORD 0000 DATASG

SUBMUL . . . . . . . . . . . . L FAR 0000 External

page 60,132

TITLE SUBMUL Подпрограмма для умножения

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

0000 CODESG SEGMENT PARA 'Code'

0000 SUBMUL PROC FAR

ASSUME CS:CODESG

PUBLIC SUBMUL

0000 F7 E3 MUL BX ;AX-стоимость, BX-количество

0002 CB RET ;Произведение в DX:AX

0003 SUBMUL ENDP

0003 CODESG ENDS

END SUBMUL

Segments and groups:

N a m e Size Align Combine Class

CODESG . . . . . . . . . . . . 0003 PARA NONE 'CODE'

Symbols:

N a m e Type Value Attr

SUBMUL . . . . . . . . . . . . F PROC 0000 CODESG Clobal Length=0003

__________________________________________________________________________

LINK

IBM Personal Computer Linker

Version 2.30 (C) Copyright IBM Corp 1981, 1985

Object Modules: B:CALLMUL1+B:SUBMUL1

Run File: [B:CALLMUL1.EXE]: <return>

List File:[NUL.MAP]: CON

Libraries [.LIB]: <return>

Start Stop Length Name Class

00000H 00015H 0016H CODESG CODE <--Примечание: 2 кодовых

00020H 00022H 0003H CODESG CODE <-- сегмента

00030H 00033H 0004H DATASG DATA

00040H 000BFH 0080H STACKSG STACK

Program entry point at 0000:0000

__________________________________________________________________________

Рис. 21.3. Использование директив EXTRN и PUBLIC.

Программа на рис.21.3 состоит из основной программы CALLMUL1 и

подпрограммы SUBMUL1. В основной программе определены сегменты для стека,

данных и кода. В сегменте данных определены поля QTY и PRICE. В кодовом

сегменте регистр AX загружается значением PRICE, а регистр BX - значением

QTY, после чего происходит вызов подпрограммы. Директива EXTRN в основной

программе определяет SUBMUL как точку входа в подпрограмму.

Подпрограмма содержит директиву PUBLIC (после ASSUME), которая

указывает компоновщику, что точкой входа для выполнения является метка

SUBMUL. Подпрограмма выполняет умножение содержимого регистра AX (цена) на

содержимое регистра BX (количество). Результат умножения вырабатывается в

регистровой паре DX:AX в виде шест.002E 4000.

Так как подпрограмма не определяет каких-либо данных, то ей не

требуется сегмент данных. Если бы подпрограмма имела сегмент данных, то

только она одна использовала бы свои данные.

Также в подпрограмме не определен стековый сегмент, так как она

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

стек определенный в основной программе является доступным и в

подпрограмме. Для компоновщика необходимо обнаружить по крайней мере один

стек и определение стека в основной программе является достаточным.

Рассмотрим теперь таблицы идентификаторов, вырабатываемые после

каждого ассемблирования. Обратите внимание, что SUBMUL в таблице

идентификаторов для основной программы имеет атрибуты FAR и External

(внешний), а для подпрограммы - F (для FAR) и Global (глобальный). Этот

последний атрибут указывает, что данное имя доступно из вне подпрограммы,

т.е. глобально.

Карта компановки (в конце листинга) отражает организацию программы в

памяти. Заметьте, что здесь имеются два кодовых сегмента (для каждого

ассемблирования) с разными стартовыми адресами. Последовательность

расположения кодовых сегментов соответствует последовательности указанных

для компановки объектных модулей (обычно основная программа указывается

первой). Таким образом, относительный адрес начала основной программы -

шест.00000, а подпрограммы - шест.00020.

При трассировке выполнения программы можно обнаружить, что команда

CALL SUBMUL имеет объектный код

9A 0000 D413

Машинный код для межсегментного CALL - шест.9A. Эта команда сохраняет в

стеке регистр IP и загружает в него значение 0000, сохраняет в стеке

значение шест.13D2 из регистра CS и загружает в него шест.D413. Следующая

выполняемая команда находится по адресу в регистровой паре CS:IP т.е.