Assembler для начинающих

EXTRN и PUBLIC


    Редактор связей не может, однако, выполнить все, о чем говорилось
    выше, самостоятельно.  Ассемблер должен получить от программиста
    информацию о подпрограммах, относящихся к другому программному
    модулю.  Это ввполняется с помощью оператора 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/89  16:06:36
            Фиг. 5.13 Основная программа                      Page         1-1
 
 
                                          PAGE    ,132
                                          TITLE   Фиг. 5.13 Основная программа
 
             0000                   STACK   SEGMENT STACK
             0000  0040[                        DW      64 DUP (?)            ; Резервирование места для стека
                   ????


                               ]
 
             0080                   STACK   ENDS
 
             0000                   CODE    SEGMENT PUBLIC
 
                                          EXTRN   OUTPUT_ROUTINE:NEAR, OUTPUT_CHARACTER:BYTE
 
                                          ASSUME  CS:CODE
 
             0000                   START   PROC    FAR
 
             0000  1E                     PUSH    DS              ; Сегмент адреса возврата
             0001  B8 0000                      MOV     AX, 0
             0004  50                     PUSH    AX              ; Смещение адреса возврата
             0005  FC                     CLD                     ; Установка направления
             0006  8C C8                        MOV     AX, CS                ; Установка сегментного регистра
             0008  8E D8                        MOV     DS, AX
                                          ASSUME  DS:CODE               ; Индикация состояния регистра
             000A  8D 36 001D R                 LEA     SI, MESSAGE           ; Адрес строки сообщения
             000E                   CLOOP:
             000E  AC                     LODSB                   ; Выборка следующего байта сообщения
             000F  A2 0000 E                    MOV     OUTPUT_CHARACTER, AL    ; Сохранение в памяти символа
             0012  E8 0000 E                    CALL    OUTPUT_ROUTINE        ; Вывод символа
             0015  80 3E 0000 E 0A              CMP     OUTPUT_CHARACTER, 10    ; Проверка на символ конца сообщения
             001A  75 F2                        JNE     CLOOP                 ; Обработка следующего символа
 
             001C  CB                     RET                     ; Возврат в ДОС
 
             001D  9D E2 A0 20 AF E0 AE     MESSAGE DB      'Эта программа - тест', 13, 10
                 A3 E0 A0 AC AC A0 20
                 2D 20 E2 A5 E1 E2 0D
                 0A
             0033                   START   ENDP


             0033                   CODE    ENDS
                                          END     START
 
            Фиг. 5.13 Главная процедура
            Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:02:28
            Фиг. 5.14 Подпрограмма вывода                     Page         1-1
 
 
                                          PAGE    ,132
                                          TITLE   Фиг. 5.14 Подпрограмма вывода
 
             0000                   CODE    SEGMENT PUBLIC
                                          ASSUME  CS:CODE,DS:CODE       ; Это должно быть так при вызове
 
                                          PUBLIC  OUTPUT_CHARACTER, OUTPUT_ROUTINE
 
             0000  ??               OUTPUT_CHARACTER        DB      ?
 
             0001                   OUTPUT_ROUTINE  PROC    NEAR
             0001  A0 0000 R                    MOV     AL, OUTPUT_CHARACTER    ; Выборка выводимого символа
             0004  B4 0E                        MOV     AH, 14                ; Функция вывода в BIOS
             0006  BB 0000                      MOV     BX, 0                 ; Установка номера страницы
             0009  BA 0000                      MOV     DX, 0
             000C  CD 10                        INT     10H             ; Вызов подпрограммы вывода на экран
             000E  C3                     RET                     ; Возврат в вызывающую программу
 
             000F                   OUTPUT_ROUTINE  ENDP
             000F                   CODE    ENDS
                                          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 говорят о том, что это
    область памяти предназначена для стека. Редактор связей, кроме
    того, проверяет, правильно ли установлен указатель стека в момент,
    когда управление передается программе.

Содержание раздела