На главную Назад
Добро пожаловать, уважаемый посетитель!

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

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

информацию о подпрограммах, относящихся к другому программному

модулю.Это ввполняется с помощью оператора PUBLIC, извещающего

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

программам.Кроме того, программист указывает ассмеблеру, какие из

символических имен является внешними для данного программного

модуля.В языке ассемблера это реализуется оператором EXTRN,

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

ассемблирования, чтобы оно могло быть правильно обработано.

Ассемблер помечает данную команду таким образом, чтобы редактор

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

значение адреса.

 

Оператор EXTRN выполняет две фуекции. Во-первых, он сообщает

ассемблеру, что указанное символическое имя является внешним для

текущего ассемблирования. Конечно, на этом этапе ассемблер мог бы

считать, что любое имя, не идентифицированное им в процессе

ассемблирования, является внешним. Однако, если когда-нибудь вы

ошиблись в указании имен, то ассемблер решит, что имеется в виду

внешнее имя, и не выдает сообщения об ошибке. Это отложит индикацию

ошибки до этапа редактирования связей. Для большинства

программистов это слишком поздно, особенно, если речь идет о чем-то

простом, вроде описки. Таким образом, ассемблер индицирует ошибку в

случае любого не определенного им символического имени.

 

Вторая функция оператора EXTRN состоит в том, что он указывает

ассемблеру тип соответствующего символического имени. Так как

ассемблирование является очень формальной процедурой, то ассемблер

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

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

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

Тип имени подпрограммы или другой программной метки может быть либо

NEAR, либо FAR, в зависимости от того, в каком сегменте она

находится. От программиста требуется указать в операторе EXTRN тип

символического имени. Так как кроме того ассемблером осуществляется

посегментная адресация программы, то оператор EXTERN указывает на

сегмент, в котором появляется данный идентификатор. Это не входит в

синтаксис оператора EXTRN, а определяется местоположением этого

оператора в программе. Ассемблер считает, что внешнее имя относится

к тому же сегменту, в котором появляется оператор EXTERN для этого

символического имени.

 

На Фиг. 5.13 приведен пример ассемблерной программы,

иллюстрирующей использование оператора EXTRN. Здесь имеются два

имени, являющиеся внешними для данной программы. OUTPUT_CHARACTER

обозначает однобайтовую переменную. Соответствующий этой переменной

атрибут ":BYTE" указывается после имени переменной. Указатель NEAR

программной метки OUTPUT_ROUTINE говорит о том, что она находится в

том же сегменте. Хотя приведенная на Фиг. 5.13 прогграмма содержит

ссылки на эти символические имена, при трансляции ассемблер знает,

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

отсутствовал в программе, то в этом случае ассемблер

инициализировал бы ошибки. Из ассемблерного листинга видно, что

после поля адреса в командах, ссылающихся на внешние имена, стоит

символ E.

icrosoft (R) Macro Assembler Version 5.00 4/2/8916:06:36

Фиг. 5.13 Основная программаPage1-1

 

 

PAGE,132

TITLEФиг. 5.13 Основная программа

 

0000STACKSEGMENT STACK

00000040[DW64 DUP (?); Резервирование места для стека

????

]

 

0080STACKENDS

 

0000CODESEGMENT PUBLIC

 

EXTRNOUTPUT_ROUTINE:NEAR, OUTPUT_CHARACTER:BYTE

 

ASSUMECS:CODE

 

0000STARTPROCFAR

 

00001E PUSHDS; Сегмент адреса возврата

0001B8 0000MOVAX, 0

000450 PUSHAX; Смещение адреса возврата

0005FC CLD; Установка направления

00068C C8MOVAX, CS; Установка сегментного регистра

00088E D8MOVDS, AX

ASSUMEDS:CODE; Индикация состояния регистра

000A8D 36 001D RLEASI, MESSAGE; Адрес строки сообщения

000ECLOOP:

000EAC LODSB; Выборка следующего байта сообщения

000FA2 0000 EMOVOUTPUT_CHARACTER, AL; Сохранение в памяти символа

0012E8 0000 ECALLOUTPUT_ROUTINE; Вывод символа

001580 3E 0000 E 0ACMPOUTPUT_CHARACTER, 10; Проверка на символ конца сообщения

001A75 F2JNECLOOP; Обработка следующего символа

 

001CCB RET; Возврат в ДОС

 

001D9D E2 A0 20 AF E0 AEMESSAGE DB'Эта программа - тест', 13, 10

A3 E0 A0 AC AC A0 20

2D 20 E2 A5 E1 E2 0D

0A

0033STARTENDP

0033CODEENDS

ENDSTART

 

Фиг. 5.13 Главная процедура

Microsoft (R) Macro Assembler Version 5.001/1/80 04:02:28

Фиг. 5.14 Подпрограмма выводаPage1-1

 

 

PAGE,132

TITLEФиг. 5.14 Подпрограмма вывода

 

0000CODESEGMENT PUBLIC

ASSUMECS:CODE,DS:CODE; Это должно быть так при вызове

 

PUBLICOUTPUT_CHARACTER, OUTPUT_ROUTINE

 

0000?? OUTPUT_CHARACTERDB?

 

0001OUTPUT_ROUTINEPROCNEAR

0001A0 0000 RMOVAL, OUTPUT_CHARACTER; Выборка выводимого символа

0004B4 0EMOVAH, 14; Функция вывода в BIOS

0006BB 0000MOVBX, 0; Установка номера страницы

0009BA 0000MOVDX, 0

000CCD 10INT10H; Вызов подпрограммы вывода на экран

000EC3 RET; Возврат в вызывающую программу

 

000FOUTPUT_ROUTINEENDP

000FCODEENDS

END

 

Фиг. 5.14 Процедура вывода

 

Рассмотрим эту же задачу с другой стороны. Каким образом

редактор связей узнает о местоположении внешних имен? На Фиг. 5.14

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

относящаяся к Фиг. 5.13. Переменные и программные метки, на которые

имеются ссылки в программе, на Фиг. 5.13, объявлены в подпрограмме

с помощью оператора PUBLIC. Это означает, что их имена доступны для

другого программного модуля. Ни на какие другие переменные или

программные метки в этой программе, не указанные в операторе

PUBLIC, ссылки в других программах невозможны. Хотя это может

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

PUBLIC, то возникла бы другая трудность. Это означало бы, что

каждое имя в любом из модулей, которые вы могли бы связать между

собой, должны быть уникальными, т.е. вы никогда бы не смогли

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

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

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

возможно и через несколько лет, а помнить все символические имена и

следить за тем, чтобы ни одно из них не повторялось дважды довольно

сложно. Заметьте, что в операторе PUBLIC не требуется указывать

атрибуты имен: об этом заботятся обычные операторы языка

ассемблера.

Программа LINK устанавливает соответствие между всеми внешними

именами и соответствующими операторами PUBLIC, которые их

объявляют. После этого редактор связей записывает правильные

значения адресов в команды, гдк есть ссылки на внешние имена.

Обрабатываются те поля в командах, рядом с которыми в ассемблерном

листинге стоял символ "E".

 

Кроме того, ассемблер осуществляет объединение любых сегментов

с одними тем же именем. В случае программ на Фиг. 5.13 и П5.14

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

сегменту с именем CODE. Так как в операторе EXTRN основной

программы для программы OUTPUT_ROUTINE указан атрибут NEAR, то

желательно, чтобы эта программа была в том же сегменте. Атрибут

PUBLIC в операторе SEGMENT указывает редактору связей объединить

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

 

В программе на Фиг. 5.13 есть еще один сегмент, который следует

рассмотреть. Данная программа выполняется как программа типа .EXE.

При передаче управления программе типа .EXE система DOS организует

для этой программы стек. Информация для стека поступает от

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

.EXE. Подготовить все для стека обязан программист. Если он этого

не сделает, то редактор связей выдает соответствующее сообщение. В

обычной ситуации это не может служить препятствием для выполнения

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

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

оказаться неподходящими. За подготовку стека отвечает сегмент

STACK, входящий в программу на Фиг.5.13. Его имя STACK и задание

соответствующего атрибута равным STACK говорят о том, что это

область памяти предназначена для стека. Редактор связей, кроме

того, проверяет, правильно ли установлен указатель стека в момент,

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


 

Mail.ru