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

         

Ассемблер и макроассемблер



Ассемблер и макроассемблер


    После того, как исходный файл уже создан, можно применить
    ассемблер.    Существуют две версии ассемблера:  полная версия,
    называемая Макроассемблером, которая на специальной, отведенной для
    программы ассемблера дискете, именуется MASM.EXE, и менее полная
    версия - Ассемблер, или ASM.EXE - без возможности работать с
    макроопределениями.  Если для эффективного использования программы
    MASM требуется объем памяти 96К, то для программы ASM достаточно
    64К.  Указанные значения никак не связаны с объемом памяти,
    занимаемой исходной программой.  Они относятся к объему памяти,
    необходимой для ассемблирования, а не выполнения уже
    оттранслированной программы.  Поэтому возможна ситуация, когда для
    разработки пользовательской программы, требующей для своего
    выполнения только 4К, необходима ЭВМ с объемом памяти не менее 64К.
      Входной информацией для ассемблера является исходный файл,
    созданный редактором EDLIN, либо аналогичным редактором. Исходный
    файл - это текстовый файл в кодах ASCII. В результате работы
    ассемблера может получиться до трех выводных файлов. Объектный файл
    представляет собой вариант исходной программы, записанной на
    машинном языке. Объектный файл - это еще не совсем готовая для


    выполнения программа, однако она близка к реальномй машинному
    языку. Листинговый файл является текстовым явйлом в кодах ASCII,
    включающим как исходную информацию, так и информацию, полученную в
    результате работы ассемблера. Приведенные в данной книге примеры
    являются ассемблерными листинговыми файлами. И наконец, ассемблер
    может сформировать файл перекрестных ссылок. Этот файл, не
    являющийся ни программой на машинном языке, ни текстовым файорм,
    содержит информацию об использовании символов и меток в
    ассемблерной программе. Как и в случае объектного файла, перед
    использованием файла перекрестных ссылок требуется его
    дополнительная обработка.
 
      Запуск ассемблера осуществляется командой DOS
      A> ASM
      или
      A>MASM
 
      Команда ASM запускает усеченный вариант ассемблера, а команда
    MASM - Макроассемблер. После того, как ассемблер начинает
    выполняться, он просит указать: какие файлы будут использованы при
    ассемблировании. На Фиг. 5.10 приводится последовательность команд
    для запуска ассемблера.
 
      После того, как команда ASM введена, DOS загружает в память
    ассемблер.    Ассемблер выводит на экран название версии и переходит
    к выдаче запросов к оператору.  Если в вашей системе имеется только
    один дисковод с гибким диском, то на этом этапе вы можете вынуть
    дискету с ассемблером и вставить дискету с данными.  Ассемблер
    запрашивает:  какой файл будет транслироваться, при этом достаточно
    ввести только имя этого файла без указания типа .ASM.  Кроме этого,
    ассемблер запрашивает имена выходных файлов.  Объектному файлу
    ассемблер присваивает то же имя, что и у исходного файла, но с
    расширением .OBJ, если только вы не захотите его изменить.    В
    данном примере ответ оператора "B:" является указанием ассемблеру,
    чтобы он записал объектный яайл на диск в дисковод B:.  Аналогичные
    ответы оператора на запросы по поводу листингового файла и файла
    перекрестных ссылок сообщают ассемблеру, чтобы эти файлы он также
    записал на диск в дисководе B:.  В справочнике диска,
    установленного в дисководе B:, можно увидеть все полученные в
    результате ассемблирования файлы.
      Для всех запросов имеются режимы, применяемые по умолчанию.
    Если в ответ на любой из этих запросов нажать клавишу возврата, то
    ассемблер использует режим по умолчанию. Для листингового файла и
    файла перекрестных ссылок по умолчанию принимается значение NUL.
    Для DOS файл типа NUL - это специальный файл: все, что записывается
    в     файл NUL не доступно и не может быть восстановлено. Файл
    NUL относится к файлам типа WOF (write=only file - файл только для
      -------------------------------------------------------
      A>ASM
      The IBM Personal Computer Assembler
      Version 1.00 (C)Copyright IBM Corp 1981
 
      Source filename [.ASM]: B:FIG5_10
      Object filename [FIG5_10.obj] B:
      Source lisying    [NUL.LST] B:
      Cross reference [NUL.CRF] B:
 
      Warning Severe
      Errors      Errors
      0     0
 
      A>DIR B:FIG5_10.*
      FIG5_10 ASM 44    1-01-83 12:00a
      FIG5_10 LST    426      1-01-83 12:00a
      FIG5_10 OBJ 40    1-01-83 12:00a
      FIG5_10 CRF 19    1-01-83 12:00a
 
      A>
      A>B:
      A>A:ASM FIG5_10,,,,
      The IBM Personal Computer Assembler
      Version 1.00 (C)Copyright IBM Corp 1981
 
      Warning Severe
      Errors      Errors
      0     0
 
      B>
      ----------------------------------------------------
 
            Фиг. 5.10 Выполнение ассемблирования
 
    записи).
 
      Если ассемблер во время ассемблирования обнаружит какие- нибудь
    ошибки, он записывает их в листинговый файл. Кроме того, он выводит
    их на дисплей, в результате чего можно непосредственно исправить
    любые из обнаруженных ощибок и нет необходимости выискивать их в
    листинговом файле. Если вы пользуетесь сокращенной версией
    ассемблера, ASM, то информация об ошибках содержит только их коды.
    В случае Макроассемблера, MSAM, выводится и код, и информация об
    ошибке. В уменьшенном варианте ассемблера не остается места для
    текстового сообщения об ошибке. В нижней части Фиг. 5.10 показан
    более простой способ запуска Макроассемблера. Этот метод удобен,
    когда в системе имеется два дисковода с гибкими дисками. В этом
    случае дискета с ассемблером устанавливается в дисковод A:, а
    дискета с информацией, содержащий исходный файл, - в дисковод B:.
    Устанавливается режим выбора по умолчанию дисковода B:. Ассемблер
    запускается с помощью команды A:ASM. В оставшейся части команды -
    FIG5=10,,,; - содержится вся информация для ассемблера, которая
    запрашивалась у оператора в предыдущем примере. FIG5=10 определяет
    имя файла, который нужно ассемблировать, а последовательность
    запятых служит указанием ассемблеру сгенерировать объектный,
    листинговый файл и файл перекрестных ссылок в соответствии со
    стандартным соглашением об именах файлов. При этом методе
    ассемблирования получаются точно такие же результаты, что и в
    первом случае.
 
      Существует много способов того, как указать ассемблеру имена
    файлов. Дап рассмотренных выше примера соответствуют крайним
    случаям. В первом примере в ответ на запрос указывалось имя каждого
    из файлов. Во втором случае не было необходимости ни в каких
    запросах. Более подробно различные варианты, возможные в команде
    ASM (или MASM), описываются в справочном руководстве по
    Макроассемблеру.
 
      После окончания ассемблирования можно воспользоваться
    полученными выходными файлами. Объектный файл является исходным для
    следующего этапа формирования выполняемой программы на машинном
    языке. Это - этап редактирования связей LINK, который описывается в
    следующем разделе.
 
      В листинговом файле соединяются исходный файл и читабельный
    вариант программы на машинном языке. Этот файл может быть выведен
    на дисплей с помощью команды дисковой операционной системы TYPE,
    например,
 
      A> TYPE B:FIG5=11.LST
 
      Команда TYPE загружает в память содержимое файла и выводит его
    на дисплей. Одновременно этот же файл может быть выведен на печать,
    если перед выполнением команды TYPE нажать клавиши Ctrl=PrtSc.
    Нажатие Ctrl=PrtSc предписывает DOS осуществлять вывод как на
    экран, так и на принтер. В результате листинг выводится и на
    дисплей, и на печать. Ширину листинга следует задать равной 132
    символам. Это выполняется с помощью команды ассемблера PAGE,
    которая, как вы могли заметить, присутствует почти во всех
    приводимых примерах программ. Команда
 
      PAGE ,132
 
      предписывает ассемблеру установить ширину листингового файла
    равной 132 символам. Кроме того, перед выводом на принтер нужно
    установить ширину печатаемой колонки. Это можно выполнить с помощью
    команды MODE дисковой операционной системы.
 
      A> MODE LPT1:132.
 
      Данная команда устанавливает режим, при котором на принтере
    фирмы IBM печатается 132 колонки. В этом случае листинговый файл
    распечатывается без смещения строк, которого нельзя избежать на
    дисплее.




Блок управления файлом (FCB)



Блок управления файлом (FCB)


    Прежде, чем перейти к упомянутому примеру, необходимо рассмотреть
    формируемую DOS структуру данных - блок управления файлом FCB (File
    Control Block), который является существенным элементом файловой
    системы и участвует во всех файловых операциях.
 
      Блок управления файлом обеспечивает связь пользовательской
    программы с функциями DOS. При любой файловой операции происходит
    обращение к блоку FCB. На Фиг.5.5 показан состав стандартного
    блока FCB. Имеется модификация блока FCB, называемая расширенным
    блоком FCB, которая применяется в специальных случаях, когда нужно
    "скрыть" файл. Скрытый файл защищен от записи. Это значит, что
    программа не может модифицировать содержимое этого файла, не
    изменив предварительно его блока FCB. Скрытый файл не фигурирует в
    листинге справочника. Скрыть файл - один из простейших способов
    защиты файла от неумелого пользователя. В приводимых примерах
    используются только стандартные блоки FCB.
 
      Поля данных блока FCB охватывают все атрибуты файла. Номер
    дисковода, имя и тип файла составляют идентификатор файла. Размер
    файла и дата яаляются атрибутами файла, которые приводятся в
    листинге справочника. Оставшиеся поля - текущий номер блока, длина
    записи и номер записи при произвольном доступе - служат для
    определения местоположения внутри файла при операциях чтения и
    записи. Длина записи указывает на число байтов в определяемой
    пользователем записи. Так как все операции чтения и записи в файл
    начинаются с границы записи, то длина записи определяет количество
    данных, обрабатываемых во время каждой из этих операций.
      Существуют два способа определения текущей записи при обращении
    к файлу. При первом, последовательном, способе записи
    обрабатываются по порядку. При этом текущий номер блока и
    относительный номер записи определяют запись, которая будет
    обрабатываться следующей. По мере того, как программа выполняет
    операции чтения или записи, DOS увеличивает на 1 относительный
    номер записи, чтобы он указывал на следующую запись. Выполнение

            ЪДДДДї
          0 і    і                                          Номер носителя
            ГДДДДЕДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДї
          1 і    і      і    і        і    і    і     і    і           Имя файла
            ГДДДДЕДДДДЕДДДДЕДДДДБДДДДБДДДДБДДДДБДДДДЩ
          9 і    і      і    і                                    Расширение
            ГДДДДЕДДДДЕДДДДЩ
         0С і    і      і                                   Текущий блок
            ГДДДДЕДДДДґ
         0E і    і      і                                   Размер записи
            ГДДДДЕДДДДЕДДДДВДДДДї
         10 і    і      і    і        і                           Размер файла
            ГДДДДЕДДДДЕДДДДБДДДДЩ
         14 і    і      і                                   Дата
            ГДДДДЕДДДДЕДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДВДДДДДї
         16 і    і      і    і        і    і    і     і    і    і      і    Зарезервировано
            ГДДДДЕДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДБДДДДДЩ
         20 і    і                                          Относительная запись
            ГДДДДЕДДДДВДДДДВДДДДї                            (нумерация в блоке)
         21 і    і      і    і        і                           Номер записи
            АДДДДБДДДДБДДДДБДДДДЩ                            прямого доступа

               Фиг. 5.5 Блок управления файлом
 
    последовательных операций идет в направлении от начала к концу
    файла. Примером последовательного файла служит программный файл на
    языке ассемблера. Ассемблер осуществляет чтение записей от начала
    до конца этого файла.
 
      Программа может обращаться к файлу, используя также и
    произвольный доступ. Произвольный в данном случае не означает, что
    запись выбирается случайным образом. Наоборот, это значит, что
    программа может выбрать в качестве следующей любую запись в файле.
    По-другому такой файл называют файлом с прямым доступом, так как у
    программы имеется непосредственный доступ к любой записи.
 
      Программа может обращаться к файлу любым из двух указанных
    способов. При последовательных операциях DOS автоматически изменяет
    в блоке FCB значение поля относительного номера записи. При
    произвольном доступе к файлу номер записи должен определяться
    программой. В файловой системе файл с произвольным доступом
    является аналогом вектора. Точно так же, как для обращения к любому
    элементу вектора программа должна задать значение соответствующего
    индекса, так и при обращение к записи в файле с произвольным
    доступом номер записи должен определяться программой.
 
      Теперь можно рассмотреть пример программы, использующей блок
    FCB и функции DOS. На Фиг. 5.6 приведена длинная программа, которая
    реально мало что делает. Ее цель - продемонстрировать использование
    блока FCB и функци DOS, связанных с прерыванием 21H. Однако
    содержащиеся в этой программе операции могут применяться в реальных
    задачах.
            Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:02:12
            Фиг. 5.6 Пример использования функций ДОС               Page         1-1
 
 
                                          PAGE    ,132
                                          TITLE   Фиг. 5.6 Пример использования функций ДОС
             0000                   CODE    SEGMENT
             005C                         ORG     05CH                        ; Положение первого поля FCB
             005C                   FCB               LABEL   BYTE            ; Метка всего поля FCB
             005C  ??               FCB_DRIVE         DB      ?         ; Номер устройства
             005D  0008[                  FCB_NAME                DB      8 DUP (?)       ; Имя файла
                    ??
                               ]
             0065  0003[                  FCB_EXT                 DB      3 DUP (?)       ; Тип файла
                    ??
                               ]
 
             0068  ????             FCB_BLOCK         DW      ?         ; Номер текущего блока
             006A  ????             FCB_RECORD_SIZE         DW      ?         ; Размер записи
             006C  ????????               FCB_FILE_SIZE           DD      ?         ; Размер файла
             0070  ????             FCB_DATE                DW      ?         ; Дата последнего изменения
             0072  000A[                  FCB_RESV                DB      10 DUP (?)      ; Зарезервировано ДОС
                    ??
                               ]
             007C  ??               FCB_CURRENT_RECORD      DB      ?       ; Номер текущей записи
             007D  ????????               FCB_RANDOM_RECORD       DD      ?       ; Номер записи при прямом
                                                                  ;  доступе
             0090                         ORG     090H
             0090                   DISK_TRANSFER_ADDRESS   LABEL   BYTE    ; Буфер для данных
 
             0100                         ORG     100H
                                          ASSUME  CS:CODE,DS:CODE,ES:CODE
             0100  E9 01CD R                    JMP     PROGRAM_START         ; Переход на начало программы
 
             = 0020                       RECORD_SIZE     EQU     32          ; Размер записи
             0103  03 00 00 00 00         KEYBOARD_BUFFER DB      3, 0, 0, 0, 0   ; Буфер ввода с клавиатуры
             0108  94 A0 A9 AB 20 E3 A6     FILE_ERROR_MSG  DB      'Файл уже существует', 10, 13, '$'
                 A5 20 E1 E3 E9 A5 E1
                 E2 A2 E3 A5 E2 0A 0D
                 24
             011E  8D A5 A2 AE A7 AC AE     BAD_OPEN_MSG    DB      'Невозможно открыть файл', 10, 13, '$'
                 A6 AD AE 20 AE E2 AA
                 E0 EB E2 EC 20 E4 A0
                 A9 AB 0A 0D 24
             0138  8E E8 A8 A1 AA A0 20     BAD_WRITE_MSG   DB      'Ошибка при записи в файл', 10, 13, '$'
                 AF E0 A8 20 A7 A0 AF
                 A8 E1 A8 20 A2 20 E4
                 A0 A9 AB 0A 0D 24
             0153  8E E8 A8 A1 AA A0 20     BAD_READ_MSG    DB      'Ошибка при чтении файла', 10, 13, '$'
                 AF E0 A8 20 E7 E2 A5
                 AD A8 A8 20 E4 A0 A9
                 AB A0 0A 0D 24
             016D  8E E8 A8 A1 AA A0 20     BAD_CLOSE_MSG   DB      'Ошибка при закрытии файла', 10, 13, '$'
 
                     Фиг. 5.6 Пример использования функциямй DOS (начало)
                 AF E0 A8 20 A7 A0 AA
                 E0 EB E2 A8 A8 20 E4
                 A0 A9 AB A0 0A 0D 24
 
             0189  8F E0 A8 20 A2 A2 AE     INPUT_BAD_MSG   DB      'При вводе требуется два символа', 10, 13, '$'
                 A4 A5 20 E2 E0 A5 A1
                 E3 A5 E2 E1 EF 20 A4
                 A2 A0 20 E1 A8 AC A2
                 AE AB A0 0A 0D 24
             01AB  82 A2 AE A4 20 A4 AE     CHAR_BAD_MSG    DB      'Ввод должен быть: символ|символ', 10, 13, '$'
                 AB A6 A5 AD 20 A1 EB
                 E2 EC 3A 20 E1 A8 AC
                 A2 AE AB 7C E1 A8 AC
                 A2 AE AB 0A 0D 24
 
                                    ;-----   Установка буфера (Области связи с диском)
 
             01CD                   PROGRAM_START:
             01CD  B4 1A                        MOV     AH, 1AH               ; Установка буфера
             01CF  8D 16 0090 R                 LEA     DX, DISK_TRANSFER_ADDRESS
             01D3  CD 21                        INT     21H
 
                                    ;-----   Поиск файла
 
             01D5  B4 11                        MOV     AH, 11H               ; Поиск файла с заданным
             01D7  8D 16 005C R                 LEA     DX, FCB               ;  именем
             01DB  CD 21                        INT     21H
             01DD  0A C0                        OR      AL, AL
             01DF  75 0A                        JNZ     NO_FILE               ; Переход если файл новый
             01E1  8D 16 0108 R                 LEA     DX, FILE_ERROR_MSG      ; Сообщение о неправильном
             01E5                   ERROR_EXIT:                   ; имени файла
             01E5  B4 09                        MOV     AH, 9H                ; Вывод сообщения на экран
             01E7  CD 21                        INT     21H             ;  и выход из программы
             01E9  CD 20                        INT     20H
 
                                    ;-----   Создание нового файла
             01EB                   NO_FILE:
             01EB  B4 16                        MOV     AH, 16H               ; Создание файла
             01ED  8D 16 005C R                 LEA     DX, FCB
             01F1  CD 21                        INT     21H
             01F3  0A C0                        OR      AL, AL                ; Проверка на успех
             01F5  74 06                        JZ      CREATE_OK
             01F7  8D 16 011E R                 LEA     DX, BAD_OPEN_MSG            ; Сообщение об ошибке при
             01FB  EB E8                        JMP     ERROR_EXIT            ;  создании файла
 
                                    ;-----  Установка параметров FCB
             01FD                   CREATE_OK:
             01FD  C6 06 007C R 00              MOV     FCB_CURRENT_RECORD, 0       ; Инициализация номера
             0202  C7 06 007D R 0000                  MOV     WORD PTR FCB_RANDOM_RECORD, 0   ;  записи
             0208  C7 06 007F R 0000                  MOV     WORD PTR FCB_RANDOM_RECORD+2, 0
             020E  C7 06 006A R 0020                  MOV     WORD PTR FCB_RECORD_SIZE, RECORD_SIZE
 
                     Фиг. 5.6 Пример использования функциямй DOS (продолжение)
                                    ;-----   Вывод в файл
 
             0214  B0 41                        MOV     AL, 'A'                 ; В этом цикле выводятся
             0216                   CHARACTER_LOOP:                     ; символы алфавита
 
             0216  8D 3E 0090 R                 LEA     DI, DISK_TRANSFER_ADDRESS
             021A  B9 0020                      MOV     CX, RECORD_SIZE
             021D  F3/ AA                       REP     STOSB                 ; Заполнение буфера символами
             021F  50                     PUSH    AX              ; Сохранение символа
             0220  8D 16 005C R                 LEA     DX, FCB
             0224  B4 15                        MOV     AH, 15H               ; Последовательный вывод
             0226  CD 21                        INT     21H             ;  блока символов
             0228  0A C0                        OR      AL, AL                ; Проверка на ошибку
             022A  58                     POP     AX              ; Восстановление символа
             022B  74 06                        JZ      WRITE_OK
             022D  8D 16 0138 R                 LEA     DX, BAD_WRITE_MSG       ; Ошибка записи
             0231  EB B2                        JMP     ERROR_EXIT
             0233                   WRITE_OK:
             0233  FE C0                        INC     AL              ; Следующий символ
             0235  3C 5B                        CMP     AL, 'Z'+1               ; Проверка на окончание вывода
             0237  75 DD                        JNE     CHARACTER_LOOP        ; Вывод следующего символа
 
                                    ;-----  Изменение файла
             0239                   KEYBOARD_LOOP:                      ; Цикл ввода символов
             0239  8D 16 0103 R                 LEA     DX, KEYBOARD_BUFFER     ;  с клавиатуры и
             023D  B4 0A                        MOV     AH, 0AH               ;  изменение файла
             023F  CD 21                        INT     21H             ; Ввод с клавиатуры
             0241  80 3E 0104 R 02              CMP     KEYBOARD_BUFFER+1, 2    ; Было введено два символа?
             0246  74 0A                        JE      KEY_INPUT_OK
             0248  8D 16 0189 R                 LEA     DX, INPUT_BAD_MSG       ; Сообщение об ошибке
             024C                   KEYBOARD_ERROR:
             024C  B4 09                        MOV     AH, 9H
             024E  CD 21                        INT     21H             ; Печать сообщения об ошибке
             0250  EB E7                        JMP     KEYBOARD_LOOP         ; Повторный ввод
             0252                   KEY_INPUT_OK:
             0252  8D 16 01AB R                 LEA     DX, CHAR_BAD_MSG            ; Установка указателя на
                                                                  ;  сообщение об ошибке
             0256  A0 0105 R                    MOV     AL, KEYBOARD_BUFFER+2   ; Выборка первого символа
             0259  3C 24                        CMP     AL, '$'                 ; Сравнение с символом конца
             025B  75 03                        JNE     CHANGE_RECORD         ; Изменение записи
             025D  EB 5C 90                     JMP     PROGRAM_EXIT
 
                                    ;-----  Чтение старой записи из файла
             0260                   CHANGE_RECORD:
             0260  3C 41                        CMP     AL, 'A'                 ; Проверка на то, что символ
             0262  7C E8                        JL      KEYBOARD_ERROR        ;  находится в диапазоне A-Z
             0264  3C 5A                        CMP     AL, 'Z'
             0266  77 E4                        JA      KEYBOARD_ERROR
             0268  2A E4                        SUB     AH, AH                ; Преобразование символа в
             026A  2C 41                        SUB     AL, 'A'                 ;  номер записи
             026C  A3 007D R                    MOV     word ptr FCB_RANDOM_RECORD, AX  ; Занесение номера в FCB
             026F  8D 16 005C R                 LEA     DX, FCB
             0273  B4 21                        MOV     AH, 21H               ; Прямое чтение записи
             0275  CD 21                        INT     21H
 
                     Фиг. 5.6 Пример использования функциямй DOS (продолжение)
             0277  0A C0                        OR      AL, AL                ; Проверка на ошибку
             0279  74 07                        JE      RANDOM_RECORD_OK
             027B  8D 16 0153 R                 LEA     DX, BAD_READ_MSG            ; Сообщение об ошибке
 
             027F  E9 01E5 R                    JMP     ERROR_EXIT
 
                                    ;-----  Вывод старой записи на экран
 
             0282                   RANDOM_RECORD_OK:
             0282  C6 06 00B0 R 0A              MOV     DISK_TRANSFER_ADDRESS+32, 10    ; Занесение символов конца
             0287  C6 06 00B1 R 0D              MOV     DISK_TRANSFER_ADDRESS+33, 13    ;  строки и конца вывода
             028C  C6 06 00B2 R 24              MOV     DISK_TRANSFER_ADDRESS+34, '$'   ;  в буфер
             0291  B4 09                        MOV     AH, 9H
             0293  8D 16 0090 R                 LEA     DX, DISK_TRANSFER_ADDRESS
             0297  CD 21                        INT     21H             ; Вывод записи на экран
 
                                    ;-----  Изменение файла
 
             0299  A0 0106 R                    MOV     AL, KEYBOARD_BUFFER+3   ; Выборка символа, на который будет
             029C  B9 001F                      MOV     CX, RECORD_SIZE-1       ;  заменяться содержимое записи
             029F  8D 3E 0091 R                 LEA     DI, DISK_TRANSFER_ADDRESS+1
             02A3  F3/ AA                       REP     STOSB                 ; Замена 31 символа
             02A5  B4 22                        MOV     AH, 22H
             02A7  8D 16 005C R                 LEA     DX, FCB
             02AB  CD 21                        INT     21H             ; Прямая запись на файла на
                                                                  ;  старое место
             02AD  0A C0                        OR      AL, AL                ; Проверка на ошибку
             02AF  74 07                        JZ      RANDOM_WRITE_OK
             02B1  8D 16 0138 R                 LEA     DX, BAD_WRITE_MSG       ; Сообщение об ошибке
             02B5  E9 01E5 R                    JMP     ERROR_EXIT
             02B8                   RANDOM_WRITE_OK:
             02B8  E9 0239 R                    JMP     KEYBOARD_LOOP         ; Обработка следующей записи
 
                                    ;-----  Конец программы
 
             02BB                   PROGRAM_EXIT:
             02BB  B4 10                        MOV     AH, 10H               ; Закрытие файла
             02BD  8D 16 005C R                 LEA     DX, FCB
             02C1  CD 21                        INT     21H
             02C3  0A C0                        OR      AL, AL                ; Проверка на ошибку
             02C5  74 07                        JZ      CLOSE_OK
             02C7  8D 16 016D R                 LEA     DX, BAD_CLOSE_MSG       ; Сообщение об ошибке
             02CB  E9 01E5 R                    JMP     ERROR_EXIT
             02CE                   CLOSE_OK:
             02CE  CD 20                        INT     20H             ; Возврат в ДОС
             02D0                   CODE    ENDS
                                          END
 
            Фиг. 5.6 Пример использования функциямй DOS (продолжение)
 
      Приведенная программа состоит из двух частей. В первой части
    создается файл из 26 записей длиной по 32 байта. Каждая запись
    соответствует одной букве алфавита: запись 1 - это "AAAA...A",
    запись 2 - "BBBB...B" и т.д. Данный файл формируется
    последовательно. Во второй части программы этот файл Mincho"'>    рассматривается как файл с произвольным доступом. В ответ на
    введенный пользователем с клавиатуры запрос программа считывает и
    выводит на дисплей одну из 26 записей. С помощью этого же ввода
    осущкствляется редактирование записи: 31 символ записи, начиная со
    второго, заменяется на значение, которое вводится с клавиатуры.
    Выполнение программы завершается при вводе с клавиатуры символа
    "$".
 
      В этом примере моделируется справочная база данных. На первом
    этапе программа осуществляет формирование этой базы данных. На
    втором этапе выполняется обработка произвольных запросов к базе
    данных и редактирование ее содержимого. Хотя любая реальная
    программа управления базой данных гораздо сложнее, чем приведенный
    здесь пример, однако он является хорошей иллюстрацией основных
    функций, относящихся к работе с файлами.
 
      Программа, приведенная на Фиг. 5.6, - это файл типа .COM. В
    следующем разделе мы обсудим различие между этим файлом и файлом
    типа .EXE. Использование в данном примере файла типа .COM позволяет
    для завершения работы программы воспользоваться прерыванием INT
    20H. В случае файла типа .COM начало программы в сегменте должно
    иметь смещение 100H. Первые 100H байт программного сегмента
    называются программным префиксом PSP и предназначены для хранения
    некоторых специальных данных, которые используются программной,
    написанной на языке ассемблера.
 
      Смещение блока FCB в сегменте равно 05CH, и использование в
    программе этого на первый взгляд произвольного адреса имеет
    определенные основания. Запись информации в данный блок FCB
    осуществляется командным процессором, входящим в состав DOS. После
    того, как пользователь вызвал программу, указав ее имя, DOS
    просматривает оставшуюся часть командной строки в поисках имен
    файлов. Первое встретившееся в команде имя помещается в блок FCB,
    смещение которого равно 05CH. Если в командной строке будет еще
    одно имя, то оно запишется в блок FCB со смещением 06CH. Так как в
    нашеи примере фигурирует только один файл, то используют только
    блок FCB со смещением 05CH. Запуск описываемой программы
    осуществляется с помощью следующей синтаксической конструкции:
 
      A> FIG5=6 TEST.FIL
 
      FIG5=6 - имя программы. В каталоге программа фигурирует под
    именем FIG5=6.COM. Файл TEST.FIL является файлом, который программа
    создает и затем модифицирует. Интерпретатор командных строк
    выбирает имя "TEST.FIL" и помещает его в соответствующее поле блока
    FCB со смещением 05CH. Рассматривая имя файла в качестве параметра
    командной строки, можно с помощью описываемой программы создавать и
    модифицировать любой файл. Если бы имя файла входило в ассемблерную
    программу, мы могли бы работать только с единственным файлом.
 
      Начиная со смещения 05CH, текст программы соответствует
    структуре блока FCB. Первая ячейка идентифицируется меткой блока
    FCB. Каждое из полей FCB имеет свою метку и длину, так что
    программа может обрабатывать их непосредственно. Например, чтобы
    задать длину записи, программа модифицирует переменную
    FCB_RECORD_SIZE.
 
      Начиная с адреса 080H помещается еще одно специальное поле
    программного префикса. Эта область памяти размером 128 байт
    отводится по умолчанию под область связи с диском DTA (Disk
    Transfer Area) и используется DOS в качестве буфера для всех
    файловых записей. Всякий раз, записывая или читая запись, DOS
    использует буфер области DTA. Во время инициализации DOS
    устанавливает смещение области DTA в программном сегменте равным
    080H. Программа может изменить это значение, используя функцию 1AH
    прерывания 21H. Это смещение должно быть изменено, еслм длина
    записи больше, чем 128 байт. В рассматриваемом примере область
    связи с диском сдвигается до смещения в сегменте, равного 90H. Это
    связано с тем, что блок FCB со смещением 05CH выходит за границу с
    адресом 80H. Если бы граница области DTA определялась соглашением,
    принятым по умолчанию, то при передаче файлов информация в
    последнем байте блока FCB была бы разрушена. В этом байте
    записывается номер записи при произвольном доступе к файлу. Так как
    в данной программе для чтения-записи данных используется
    произвольный доступ, упомянутое наложение информации необходимо
    исключить.
 
      Первая команда программы имеет смещение 100H и является
    переходом на фактическое начало программы. Такая структура
    программы может показаться неэффективной, однако ассемблирование
    происходит гораздо успешней, если все данные помещаются перед
    командами, которые на них ссылаются. Фактически в программе могут
    быть ошибки, если она содержит ссылки на данные вперед. Поэтому для
    большей надежности данные помещаются в начале программы.
 
      В первой части программы устанавливается область связи с
    диском. В данной программе эта буферная область имеет смещение 90H.
    Так как длина записи равняется только 32 байтам, то впереди
    программы имется достаточно места.
 
      Далее в программе используется прерывание 21H и функция DOS для
    поиска файла с именем, совпадающим с именем, записанным в блоке
    FCB. Обратите внимание, что пара регистров DC:DX указывает на блок
    FCB, как и должно быть при любых файловых операциях. Если система
    обнаружит файл с идентичным именем, программа завершит работу,
    выдав сообщение об ошибке и сохранив существующий уже файл. В
    данной программе обрабатываются только новые файлы. Существующие
    файлы здесь никак не используются, однако гарантируется, что их
    содержимое программой не сотрется. Конечно, в реальной практике
    програма была бы составлена так, чтобы охватывать случай как новых,
    так и уже существующих файлов.
 
      Создание файла обеспечивается участком программы, помещенным
    NO_FILE. Формировать блок FCB до этого данной программе не нужно,
    так как он был сформирован командным процессором. Если описываемая
    файловая операция не сможет быть выполнена, например, из-за
    отсутствия свободного места на диске или отсутствия места в
    каталоге диска, то программа завершит выполнение и выдаст
    соответствующее сообщение об ошибке.
      При любом обращении DOS к файлу программа должна, прежде всего,
    открыть файл. Процедура открытия файла устанавливает связь между
    операционной системой и пользовательской программой. В процессе
    этой операции DOS просматривает справочник диска, находит нужный
    файл (или не находит, что соответствует сбойной ситуации) и
    заполняет поле блока FCB, относящееся к длине файла. После того,
    как файл открыт, DOS не должна просматривать справочник диска
    всякий раз, когда происходит обращение к файлу. Система DOS
    сохраняет в блоке FCB информацию о файле до тех пор, пока она этот
    файл не "закроет". Термины "закрыть" и "открыть" файл еще раз
    указывают на связь с традиционным делопроизводством. Папку с файлом
    документов нужно открыть прежде, чем можно будет ознакомиться с
    содержащимся в ней бумагами, и закрыть до того, как ее уберут снова
    в бюро.
 
      В рассматриваемом примере открытие файла происходит при его
    создании. Если бы такой файл уже существовал, связь с ним была бы
    установлена с помощью функции открытия файла (AH=0FH). Если
    открытие файла произошло успешно, программма изменяет значения
    некоторых полей блока FCB. В частности, длина записи должна быть
    установлена равной 32 байт, так как по умолчанию DOS считает ее
    равной 128 байт.
 
      Часть программы с именем CHARACTER_LOOP передает в файл 26
    записей. Определяющий символ каждой записи передается в буфер
    области DTA оператором REP STOSB. Отдельные записи передаются на
    диск с помощью функции последовательной записи (AH=0AH). Программа
    также выполняет проверку на отсутствие ошибок.
 
      Начиная с метки KEYBOARD_LOOP программа переходит от
    формирования файла к запросу=коррекции записей в нем. В данном
    примере используется буферированный ввод с клавиатуры,
    поддерживаемый DOS. Это позволяет пользователю вводить строку из
    двух символов и, если необходимо, осуществлять редактирование.
    После ввода двух символов должна быть нажата клавиша окончания
    ввода. Программа выполняет проверку правильности ввода, и если
    последний не удовлетворяет требованиям, то он отвергается и
    выдается сообщение об ошибке.
 
      При вводе пользователем символа "$" программа заканчивает
    работу. В случае же ввода символов от "A" до "Z" программа
    осуществляет чтение соответствующей записи и выводит на дисплей ее
    содержимое. В оставшиеся 31 байт буфера программа записывает второй
    из введенных с клавиатуры символов. Модицифированная таким образом
    запись передается на диск в режиме произвольного доступа.
 
      В заключительной части программы осуществляется закрытие файла.
    Аналогично тому, как функция открытия файла устанавливала связь
    между DOS и пользовательской программой,
 
    ??????
 
      файла существенно для гарантии того, что DOS записала на диск все
    модифицированные записи. Во время нормального выполнения программы
    DOS может оставить несколько последних записей в буфере. Это
    ускоряет выполнение, так как DOS не должна обращаться к диску по
    поводу каждой записи. Функция закрытия файла осуществляет запись на
    диск содержимого буфера.
 
      Приведенный на Фиг. 5.6 пример программы иллюстрирует основные
    способы обращения к файлу с помощью DOS. Эта программа ничего
    полезного не выполняет, однако приближение ее к реальным задачам
    потребовало бы намного большего числа команд, которые мало что
    прояснили бы в отношении использования функций DOS. В данной
    программе важно обратить внимание на необходимость проверки ошибок
    после каждой операции, выполняемой DOS. В то время, как DOS с
    помощью прерывания 24H обрабатывает аппаратные ошибки,
    пользовательская программа должна разрешать такие ситуации, как
    совпадение имен файлов или отсутствие свободного места на дискете.
    В данном примере обработка ошибок проста и состоит из вывода
    соответствующего сообщения и завершения работ программы. Обработка
    ошибок в реальных программах значительно сложнее и более актуальна,
    так как в этом случае возможность потери важной информации должна
    быть исключена.
 
      И наконец, возможно, что проработав с данной программой, вы
    будете не очень удовлетворены ею как пользователь: в ней
    отсутствует запрос на ввод данных, сообщения об ошибках лаконичны и
    некоторые из выводимых сообщений частично накладываются на
    предыдущие, затирая их. Данная программа нуждается в доработке
    прежде, чем ею сможет воспользоваться кто-либо, не участвовавший в
    ее написании или тщательно в ней не разобравшийся.




Дисковая операционная система



Дисковая операционная система


    Поскольку для подготовки и выполнения программ мы собираемся
    использовать DOS, то начнем с рассмотрения того, что такое DOS, и
    каковы ее функции.  DOS обеспечивает операционную среду, в которой
    выполняются другие программы.  В больших ЭВМ операционная система
    представляет собой программу, которая управляет работой всей
    машины.  В большинстве случаев у таких ЭВМ имеется несколько
    пользователей, конкурирующих между собой из-за доступа к ресурсам
    машины.  Операционная система играет роль рефери, который решает,
    кто из пользователей, когда и к каким ресурсам имеет доступ.
    Операционная система позволяет пользователям работать, не мешая
    друг другу, а также предлагает им выбор сервисных программ, которые
    освобождают их от всех трудностей, связанных с учетом аппаратных
    особенностей ЭВМ.  Эти программы исключают выполнение пользователем
    операций, которые портят данные и программы других пользователей и,
    тем самым, нарушают правильную работу аппаратных средств.
    Значительная часть операционных систем больших ЭВМ устроена так,
    что пользовательская программа не имеет прямого доступа к
    аппаратным средствам.  Коллективные интересы пользователей ставятся
    здесь выше индивидуальной свободы пользовательских программ.
 
      В небольших компьютерных системах, подобных IBM PC,
    операционная система служит иной цели. В каждый момент времени с
    персональной ЭВМ работает только один пользователь, и управление
    ресурсами машины осуществляется извне: ими распоряжается тот, кто
    сидит за клавиатурой. На программном уровне разрешены любые
    последовательности команд. Выполнение программы может привести к
    неприятностям только для того пользоватея, который в этот момент
    работает с ЭВМ, и то только в том смысле, что его программа или
    данные будут для него потеряны.
      Назначение операционной системы IBM PC состоит в том, чтобы
    обеспечить операционную среду и набор сервисных программ для
    пользователей. В качестве пользователя может быть программист или
    какая-нибудь прикладная программа. Например, когда вы садитесь за
    клавиатуру и начинаете работать с системой, то вы - пользователь
    DOS. Однако, когда текстовый редактор записывает файл на дискету,
    то пользователем DOS является текстовый редактор. Вместо того,
    чтобы самому осуществить запись файла, текстовый редактор
    пользуется услугами DOS.
 
      Основная функция DOS IBM PC - это обеспечить файловую систему и
    операционную среду для программ. Файловая система представляет
    собой набор программных средств записи и считывания данных с
    дискеты или жесткого диска. Если все прикладные программы для
    записи данных используют DOS, то они могут коллективно пользоваться
    этими данными, и кроме того, в каждом случае при разработке
    приложений не надо будет заново переписывать файловую систему.




EXTRN и PUBLIC



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 говорят о том, что это
    область памяти предназначена для стека. Редактор связей, кроме
    того, проверяет, правильно ли установлен указатель стека в момент,
    когда управление передается программе.




Файловая система



Файловая система


    На каждой дискете, используемой в IBM PC, может храниться от 160 до
    360 Кбайт информации, а на жестком диске - более 107 байт.
    Очевидным образом возникает задача ведения архива.      При таких
    объемах информации необходим способ полного упорядочения хранимой
    информации.  В качестве пользователя DOS вы заинтересованы в том,
    чтобы данные представляли отдельную совокупность, как, например,
    программа на языке ассемблера.  Вас не интересует, где эти данные
    будут располагаться на дискете.  Физическое распределение этих
    данных на поверхности дискеты - это заботы системы.
 
      Основной единицей хранения данных является файл. Файл - это
    совокупность данных, интерпретируемых некоторым образом. Владелец,
    или создатель файла присваивает ему имя. Это имя может быть
    использовано при любых ссылках на эти данные для того, чтобы
    обеспечить к ним доступ. Ссылка на данные не требует никаких
    указаний в программе на то, где они физически располагаются.
 
      Любой файл состоит из записей. Каждая запись - это отдельный
    элемент данных, но не обязательно один байт. Чтобы понять, что
    такое файлы и записи, лучше всего вспомнить, в каком значении эти
    слова употребляются в делопроизводстве.
 
      Файл - это большой ящик или папка, в которой хранится множество
    документов. На файловой папке обычно указано ее название - имя
    файла. В папке собраны отдельные записи. Например, в файле
    преподаватели могут хранить контрольные работы, написанные
    студентами. Каждая отдельная контрольная работа, входящая в файл,
    соответствует одной записи. Собранные и храняшиеся у преподавателя
    записи содержательно именуются, например "первая контрольная
    работа". Чтобы отыскать чью-то контрольную работу, преподаватель
    сначала находит нужный файл, а затем просматривает этот файл в
    поисках требуемой записи.
 
      Как все это соотносится теперь с файлами, обрабатываемыми ЭВМ?
    Файл представляет собой совокупность связанных между собой данных,
    и у файла есть имя. Записи - это то, что составляет файл, Размер и
    содержание записей определяются программистом, DOS не проверяет
    формат записей, а просто помещает их в файл. Для системы DOS любая
    запись - это совокупность байтов в файле. Содержание байтов,
    составляющих запись, определяется программистом.
 
      Рассмотрим тепрь программу на языке ассемблера как пример
    файла. У программы есть имя, и это имя станет именем
    соответствующего файла. Файл состоит из записей, где каждая запись
    представляет собой один оператор языка ассемблера. Формат любой
    записи ни о чем не говорит DOS, он понятен только ассемблеру.
    Отдельные части одной записи соответствуют полям оператора языка
    ассемблера. Для DOS не важно, как записи разбиваются на поля, это
    дело прикладной программы, в данном случае - ассемблера.




Файлы com и exe



Файлы .com и .exe


    В предыдущем примере рассматривался файл типа .COM.  Однако
    результатом процесса ассемблирования-редактирования связей является
    обычно файл типа .EXE.  Зачем нужен файл типа .COM, если проще
    получить файл типа .COM?
 
      У каждого из обоих типов файлов есть свои преимущества. И чтобы
    принять обоснованное решение о том, какой из них предпочесть в
    каждом конкретном случае, нужно представлять их отличия.
 
      Главное различие между файлами типа .COM и типа .EXE связано с
    форматом записи соответствующего объектного файла на дискете. Оба
    типа файлов являются программами, записанными на машинном языке.
    Программа, записанная в файле типа .COM может сразу выполняться.
    DOS может непосредственно загрузить его в память машины с дискеты.
    После этого DOS передает управление в сегмент памяти, отведенный
    для команд, в точку со смещением 100H. Файл типа .EXE
    непосредственно выполнен быть не может. У соответствующего
    объектного файла, хранящегося на дискете, имеется заголовок. В нем
    содержится информация, сгенерированная редактором связей. Наиболее
    важная ее часть относится к информации, связанной с перемещением. В
    то время, как у файла типа .COM перемещаем один сегмент команд, у
    файла типа .EXE могут быть перемещены многие различные сегменты.
    Это ограничивает максимальный размер файла .COM 64 кбайтами, если
    только программа не подгружает еще и другие сегменты. Файл типа
    .EXE может содержать ряд сегментов, которые динамически
    перемещаются в пределах программной области.
 
      В чем состоит перемещаемость? Во время ассемблирования
    программа расположена в каком-то определенном месте памяти. Как
    было ранее установлено, ассемблер автоматически начинает каждый
    сегмент со смещением 0. В ассемблерных листингах рядом с некоторыми
    адресами стоят символы R. Это означает, что данный адрес является
    перемещаемым. Если программа сдвигается так, что ее начало будет
    иметь смещение, отличное от 0, то упомянутый адрес должен быть
    изменен. Обычно перемещением занимается редактор связей. Однако
    пересчет значений некоторых адресов не может быть выполнен до
    загрузки программы. В каждом файле типа .EXE имеется информация о
    таких адресах.
 
      Файл типа .COM не является перемещаемым. У такого файла
    отсутствует информация, необходимая для перемещения. Вместо этого у
    программы, составляющей файл типа .COM, должен быть перемещаем
    сегмент команд. Это означает, что хотя сам сегмент команд можно
    модифицировать, начальное смещение всегда должно быть одним и тем
    же. В такой программе все смещения должны оставаться неизмененными.
    Кроме того, от программиста требуется предусмотреть, чтобы при
    любой операции с сегментными регистрами (например, запись в
    сегментный регистр полученного значения) всегда производилось
    обращение к регистру текущего сегмента команд. Примером правильной
    программной последовательностью для записи в регистр DS текущего
    значения сегмента команд будет:
 
      PUSH  CS
      POP DS
 
      Иногда может показаться заманчивым реализовать ту же операцию с
    помощью следующей последовательности команд (предположим, что как и
    в приведенной на Фиг. 5.6 программе имя сегмента команд - "CODE")
 
      MOV     AX,CODE
      MOV     DS,AX
 
      Для программного файла типа .COM эта запись будет неправильной.
    В момент ассемблирования и редактирования связей сегментное
    значение для сегмента CODE неизвестно. Оно определяется только при
    загрузке программы. Поскольку файл типа .COM не может предоставить
    загрузчику перечня всех сегментных ссылок (информация для
    перемещения), то в данном случае программа будет выполняться
    неправильно.
 
      Между описываемыми типами файлов имеются различия в отношении
    установки значений сегметных регистров и расположения стека. Для
    файла типа .COM значения регистров CS, DS, ES и SS устанавливаются
    DOS, равными такими, что они указывают на тот сегмент, в который
    они загружают программу. Значение регистра SP устанавливается так,
    чтобы он указывал на последнюю доступную в сегменте ячейку памяти.
    Таким образом программа занимает начало, а стек - конец сегмента.
 
      В головной метке файла типа .EXE задаются значения регистров
    CS, IP, SS и SP. Значения регистров DS и ES DOS устанавливает таким
    образом, чтобы они указывали на тот сегмент, в который загружается
    программа. Регистр CS указывает на сегмент, который был
    идентифицирован как сегмент содержащий стартовый адрес программы.
    Если в файле типа .COM программа должна иметь начальное смещение в
    сегменте команд равным 100H, то в программном файле типа .EXE
    начальный адрес может иметь другое значение. Как показано ниже,
    значение этого адреса может содержаться в операторе END:
 
      END START_LOCATION
 
      Это является указанием ассемблеру-редактору связей, что после
    загрузки программы управление следует передать на метку
    START_LOCATION.
 
      В обоих типах файлов используется программный префикс PSP,
    который образуют первые 100H байтов того сегмента, куда загружается
    программа. В этой области памяти хранится специальная информация, о
    которой говорилось при рассмотрении программы, приведенной на
    Фиг. 5.6. В случае файла типа .EXE регистры DS и ES указывают на
    эту область данных, тогда как значения регистров CS и SS
    устанавливаются на соответствующих этапах
    ассемблирования-редактирования связей. В случае файла типа .COM все
    регистры указывают на PSP. Это обеспечивает обоим типам файлов
    непосредственный доступ к информации, хранящейся в порядке
    программного сегмента.
 
      Преимущества файла типа .COM состоит в том, что в этом случае
    регистр CS указывает на PSP, а в файле типа .EXE - нет. Прерывания
    20H и 27H, связанные с завершением выполнения программы и передачей
    управления DOS, требуют, чтобы во время прерывания регистр указывал
    на PSP. В случае файла типа .EXE это осуществить сложно. К
    счастью, следующая последовательность команд позволяет в
    программном файле типа .EXE передать управление обратно DOS.
 
      PROGRAM PROG FAR
         PUSH DS        ;   запись    сегмента    с    PSP
         MOV      AX,0
         PUSH AX        ;   запись   в   стек   смещения    0
         ...
         RET
      PROGRAM ENDP
 
      В относящейся к PSP ячейке со смещением 0 содержится команда
    INT 20H. Запись в стек состояния регистра DS и нуля устанавливает
    значение адреса длинного возврата, равное адресу PSP со смещением
    0. Выполнив команду возврата, программа перейдет к команде INT 20H.
    Но к этому моменту в регистре CS уже будет храниться значение PSP,
    и команда прерывания INT 20H возвратит управление DOS.
 
      Для прерывания 27H, при котором завершается работа программы и
    управление передается DOS с сохранением программы в памяти,
    аналогичного способа реализации нет. Хотя имеются методы записи в
    регистр CS правильного значения перед прерыванием 27H, обычно более
    простым является организация программы в виде файла типа .COM.
      И наконец, файл типа .COM занимает на диске меньше места, чес
    файл типа .EXE с такой же как в файле типа .COM программой. Так как
    у файла типа .COM отсутствует заголовок, то и места для него на
    диске не требуется. При рассмотрении в следующем разделе программы
    DEBUG будет изложен метод, позволяющий преобразовывать файл типа
    .EXE в файл типа .COM.




Функции DOS



Функции DOS


    Интерпретатор командных строк обеспечивает средства, необходимые
    для того, чтобы программа, написанная на языке ассемблера, начала
    выполняться.  Кроме того, DOS уже во время выполнения программы
    обеспечивает доступ к файловой системе с помощью механизма функций
    DOS.  В данном разделе объясняется, что представляют собой эти
    функции и как они могут быть использованы в программе.
 
      Программа использует функции DOS посредством программного
    прерывания. Благодаря этому, программа может вызывать
    соответствующую служебную программу, не зная ее адреса. Нужное
    прерывание задается программистом. А во время инициализации DOS
    векторы прерывания для функций системы определяются таким образом,
    чтобы они указывали на соответствующие подпрограммы. Следовательно,
    по мере получения других версий DOS нет необходимости вносить
    изменения в программы. На Фиг.5.3 приводятся векторы прерывания
    DOS.
 
             Прерывание      Действие
             ----------------------------------------------
              20H Окончание программы
              21H Вызов функции (см. Фиг. 5.5)
              22H Адрес завершения
              23H Адрес CTRL-BREAK
              24H Обработчик кртической ошибки
              25H Чтение с диска по абсолютному адресу
              26H Запись на диск по абсолютному адресу
              27H Завершить, но остаться резидентно
             ----------------------------------------------
 
               Фиг. 5.3 Прерывания DOS
      Некоторые прерывания фактически предназначены для
    пользовательских подпрограмм. Прерывания 22H, 23H и 24H являются
    указателями на подпрограммы, которые могут быть в программе
    пользователя. Эти векторы определяют программу, которая должна
    выполняться при наступлении соответствующей ситуации. Например, при
    нажатии клавиши CTRL-BREAK DOS выполняет прерывание 23H. Обычно
    нажатие этой клавиши вызывает останов программы. Обычно DOS
    выполняет стандартную обработку соответствующих ситуаций. Если же
    программе нужно обрабатывать их иначе, то она может изменить вектор
    прерывания.
 
      В качестве примера рассмотрим прерывание 24H - обработку
    неустранимой ошибки. Всякий раз обнаруживая ошибку система
    инициирует прерывание. Обычно соответствующий вектор указывает на
    программу в DOS, которая выводит на дисплей сообщение об ошибке. В
    случае ошибки, связанной с диском, DOS выводит сообщение о дисковой
    ошибке. Пользователь может по своему усмотрению сделать повторную
    попытку выполнения операции, вызвавшей ошибку, либо закончить
    выполнение, либо пропустить операцию, вызвавшую ошибку.
    Предположим, например, что вы пишите программу форматирования
    дискет. Это операция, в ходе которой на поверхности дискеты
    происходит физическая разметка дорожек и секторов. Вместе с
    форматированием дискеты проверяется отсутствие сбойных участков.
    Последняя операция называется верификацией дискеты. Так как при
    верификации допускается присутствие на дискете одно-двух сбойных
    участков, то вы специальным образом помечаете эти участки, чтобы в
    дальнейшем их случайно не использовать. Данная программа
    форматирования заменяет обработку неустранимых ошибок. Вам не
    нужно, чтобы DOS выводила для пользователя сообщение об ошибке.
    Вместо этого вы хотите, чтобы обработка ошибки верификации
    происходила в самой программе, и соответствующий участок на диске
    помечался как сбойный. Для этого вы заменяете вектор прерывания в
    ячейке 0:0090H(24H*4) указателем на свою подпрограмму обработки
    ошибок. Когда DOS зафиксирует дисковую ошибку, ваша подпрограмма
    может пометить это место как сбойный участок, никак не уведомляя об
    этом пользователя.
 
      Прерывания 25H и 26H связывают между собой две части системы. С
    точки зрения своей файловой структуры DOS фактически состоит из
    двух компонент. Одна из них, IBMBIO.COM, включает программы
    непосредственного доступа к аппаратным средствам. Другая,
    IBMDOS.COM реализует файловую систему. Упомянутые два прерывания
    используются, когда компонента DOS, относящаяся к файловой системе,
    обращается к другой компоненте - BIO. Хотя эти прерывания и могут
    использоваться программистом, основное их назначение - разделить
    две части DOS. Прерывание 25H осуществляет чтение, а прерывание 26H
    - запись информации с абсолютной адресацией диска. На этом уровне
    обеспечивается доступ к определенным участкам диска, а не записям в
    файле.
 
      Прерывания 20H и 27H обеспечивают механизм возврата управления
    к DOS после выполнения программы. Прерывание 20H соответствует
    нормальному завершению работы программы. Прерывание 27H интересно
    тем, что хотя оно связано с завершением программы, занимаемая
    программой область памяти не возвращается обратно в распоряжение
    DOS. Все содержимое данной области сохраняется неизменным до тех
    пор, пока не будет выключено питание или выполнена переустановка
    системы в начальное состояние. Это удобно в тех случаях, когда
    нужно ввести специальную обработку прерываний, либо аналогичную
    функцию, которая должна сохраниться как часть системного
    программного обеспечения. В гл.10 будет приведен пример
    использования прерывания INT 27H для расширения системы. В DOS
    имеется особенность работы с прерываниями 20H и 27H. Их
 
            Значение
            в AH              Функция
          ----------------------------------------------------------
            0     Завершение программы
            1     Ввод с клавиатуры
            2     Вывод на экран
            3     Дополнительный ввод (асинхронная коммуникация)
            4     дополнительный вывод
            5     Вывод на принтер
            6     Прямой ввод/вывод с консоли
            7     Прямой ввод с консоли без эха
            8     Ввод с консоли без эха
            9     вывод строки
            OAH   Буферизованный ввод с клавиатуры
            0BH   Проверка состояния клавиатуры
            0CH   Очистка буфера клавиатуры и функция # в AL
            0DH   Переустановка диска
            0EH   Выбор диска
            0FH   Открытие файла
            10H   Закрытие файла
            11H   Поиск первого
            12H   Поиск следующего
            13H   Уничтожение файла
            14H   Последовательное чтение
            15H   Последовательная запись
            16H   Создание файйла
            17H   Переименование файла
            19H   Текущий диск
            1AH   Установка адреса обмена с диском
            1BH   Адрес таблицы размещения
            21H   Прямое чтение
            22H   Прямая запись
            23H   Размер файла
            24H   Установка записи для прямого обращения
            25H   Установка вектора прерывания
            26H   Создание нового програмного сегмента
            27H   Прямое чтение блока
            28H   Прямая запись блока
            29H   Анализ имени файла
            2AH   Чтение даты
            2BH   Установка даты
            2CH   Получение времени
            2DH   Установка времени
          -------------------------------------------------------
 
               Фиг. 5.4 Функции прерывания DOS 21H
    использование предпочтительней в файле типа .COM, так как файл типа
    .EXE имеет существенно другой формат и использование в нем этих
    функций DOS немного сложнее. В следующем разделе будут рассмотрены
    различия между файлами типа .COM и типа .EXE и то, почему
    упомянутые прерывания, связанные с завершением работы программы,
    выполняются в них по-разному.
 
      Прерывание 21H является прерыванием, через которое происходи
    обращение к основным функциям DOS. Это прерывание обеспечивает
    доступ к системе ввода-вывода, управляемой DOS. На Фиг.5.4
    представлены все возможные функции, использующие это прерывание.
    Выбор функции в программе осуществляется с помощью записи в регистр
    AH нужного значения перед выполнением прерывания 21H.
      Параметры этих функций приводятся в приложении D руководства по
    DOS. Вместо подробного ознакомления мы разберем пример, в котором
    использованы некоторые из них. В частности, этот пример включает
    функции DOS, связанные с диском.




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



Глава 5


Dos и Ассемблер
    В этой главе излагаются все детали, необходимые для ассемблирования
    и выполнения программ.  В предыдущих главах объяснялось, как
    работает микропроцессор 8088.  Теперь время проверить полученные
    знания, так как только самостоятельное составление и успешная
    прогонка программ могут дать полное представление о системе команд
    микропроцессора 8088.
 
      В данной главе будут рассмотрены четыре основные этапа
    подготовки программы:  редактирование, ассемблирование, компоновка
    (редактирование связей) и отладка.    Каждый из этих этапов
    осуществляется с помощью отдельной программы и отдельного набора
    процедур.  Все программы выполняются под управлением дисковой
    операционной системы (DOS).  Три из этих программ входят в DOS и
    могут быть заказаны вместе с IBM PC.  Ассемблер не входит в DOS, но
    может быть получен таким же образом.  В этой книге раасматриваются
    только программы, разработанные фирмой IBM.




Имена файлов



Имена файлов


    Рассмотрим сначала, как система DOS формирует имена файлов.  Каждое
    сформированное DOS имя файла состоит из двух частей.  Первая часть
    имени файла имеет длину от 1 до 8 символов.  Эта часть определяется
    пользователем и соответствует присвоенному им "имени" файла.
    Вторая часть имени, называемая расширением, имеет длину от 1 до 3
    символов.  Эта часть, определяющая "тип" файла, обычно задается
    прикладной программой.  Имя и его расширение разделяются точкой.
    Например, в имени файла "COMMAND.COM" COMMAND является именем, а
    COM - расширением.
 
      В некоторых случаях расширение имени файла определяется самим
    пользователем. При этои DOS или прикладная программа используют это
    расширение для идентификации типа файла. В имени файла
    "COMMAND.COM" .COM определяет файл команд. С ассемблированием
    связан один входной файл и от одного до трех выходных файлов.
    Расширение входного ассемблерного файла есть .ASM, а выходных
    файлов: объектного - .OBJ, листинга - .LST и файла перекрестных
    ссылок - .CRF. Во многих случаях в прикладных программах требуется,
    чтобы у имени файлов были определенные расширения.
 
ДИРЕКТОРИИ
 
    Так как на любой дискете может поместиться большое количество
    информации, то использовать всю дискету для записи только одного
    файла было бы неэкономно.  Операционная система позволяет хранить
    на фиксированном диске или дискете одновременно несколько файлов.
 
      На магнитком носителе может храниться более одного файла
    благодаря тому, что система организует каталог содержимого диска.
    Этот каталог напоминает оглавление книги. В нем перечислены все
    файлы, имеющиеся на диске или дискете. Кроме имени файла DOS
    помещает в каталоге и другую необходимую и полезную информацию.
    Прежде всего в нем имеются указатели, которые нужны для определения
    фактического местонахождения данных на магнитном носителе. Кроме
    этого, каталог удобен тем, что имеет временные ярлыки для каждого
    файла. Когда какая-нибудь программа создает либо обновляет файл,
    DOS производит запись соответствующей даты и времени. Это очень
    удобно в тех случаях, когда существует множество копий некоторой
    информации и вам требуется самая последняя версия.
 
      Организация каталога на диске решает задачу хранения нескольких
    файлов на одном диске или дискете. Однако в каждый момент времени
    DOS может обращаться только к одному дисководу. Если в системе
    имеется больше, чем один дисковод с гибким или жестким диском, то
    нужно сообщить DOS, на каком из них расположен файл. В этом случае
    наименование дисковода указывается в качестве префикса имени файла.
    Например, у файла COMMAND.COM в дисководе A уточненное полное имя
    будет A:COMMAND.COM.




Карта связей



Карта связей


    На Фиг. 5.16 приведена полученная в результате редактирования карта
    связей.  Так как рассматриваемый пример прост, то и карта не очень
    содержательна.  Каждому сегменту в исполняемом файле соответствует
    отдельная строка карты.  В строке последовательно указаны значения
    начального и конечного адресов каждого сегмента в том виде, в каком
    они будут загружены в память.  Заметьте, что размер сегмента CODE
    равен 3CH.    Это является суммарным размером сегментов CODE в двух
    программных модулях.  Другой сегмент в нашем примере - это сегмент
    STACK размером 80H байт.
      По поводу адресов, приведенных в карте связи, нужно сделать
    следующие замечания. Во-первых, все они являются 20- битовыми
    адресами и отсчитываются от ячейки 0. Так как загрузка программы
    будет осуществляться DOS, то занрузчик изменит значения этих
    адресов. Однако относительно друг друга их значения останутся
    такими же. В отношении сегментов следует еще отметить, что в памяти
    они не располагаются последовательно. Хотя длина сегмента CODE
    равняется только 3CH, сегмент STACK начинается с адреса 40H.
    Сегменты должны располагаться на границах параграфов для того,
    чтобы адреса смещения сохраняли правильные значения. Благодаря
    привязке к границам параграфов, сегментные регистры указывают точно
    на первую ячейку сегмента. Следовательно, в нашем случае редактор
    связей расположил сегмент STACK на первой границе параграфа сразу
    же после конечного адреса сегмента CODE. С учетом того, что конец
    сегмента CODE равен 3BH, следующий адрес ячейки, который делится на
    16, будет равен 40H.
 
          ----------------------------------------------------
             Start  Stop   Length Name             Class
             00000H 0007FH 00080H STACK
             00080H 000CEH 0004FH CODE
 
            Program entry point at 0008:0000
          ----------------------------------------------------
 
          Фиг. 5_16 Карта связей для Фиг. 5.13 и 5.14
 
      Возможно вы заметили, что общая длина сегментов CODE в
    действительности не равна 3CH. В отсутствие других спецификаций
    редактор связей поместил начало каждой части сегмента CODE на
    границах параграфов. Длина первого модуля FIG5=13 равняется 2BH.
    Следующий модуль, FIG5=14, редактор связей поместил на следующей
    границе параграфа, в данном случае по адресу 30H. Так как длина
    второго модуля равна 0CH, общий размер сегмента CODE будет равен
    03CH. Выравнивание по границам параграфов выполняется по умолчанию
    совместно с ассемблированием и редактированием связей. Оператор
    языка ассемблера SEGMENT может, если нужно, изменить это
    выравнивание на побайтовое (BYTE), либо пословно (WORD). При
    выравнивании типа BYTE программные программные упаковываются в один
    сегмент. В смысле экономии памяти это наиболее эффективный способ
    объединения модулей. Однако выравнивание по границе параграфа
    гарантирует, что во время выполнения программы не возникает никаких
    трудностей с адресацией сегментов. Если в программе производятся
    вычисления адресов и выравнивание производилось не по границам
    параграфов, то возможно возникновение ошибок.
 
      В конце карты связей указывается входная точка исполняемого
    файла. Этот адрес, как и другие, вычисляется по отношению к началу
    исполняемого модуля и перераспределяется загрузчиком. Имеется
    несколько способов указания стартового адреса для программы типа
    .EXE. При одном из способов программа выполняется, начиная с
    первого байта программного модуля. При этом вы должны следить за
    тем, чтобы в первом байте первого сегмента рабочего файла
    содержалась команда, с которой вы хотите начать выполнение. Более
    предпочтительным является способ задания входной точки в операторе
    END головной программы. На Фиг. 5.13 последним в программе является
    оператор
 
      END START
 
      где START - это метка первой выполняемой команды. Так как
    модули связаны друг с другом в определенном порядке, то эта же
    команда будет первой и в программе. Однако если модули связать в
    обратном порядке, то входная точка будет располодена правильным
    образом. В этом можно убедиться на практике.
 
      При любой операции связывания должен быть только один оператор
    END с указанием стартового адреса. Обратите внимание, что в
    подпрограмме FIG5=14 в операторе END входная точка не указана. Если
    имеется более одной входной точки, то редактор связей обычно
    выбирает ту, которая указана последней. Лучше непосредственно
    задавать входную точку, чем допускать вероятность того, что
    редактор связей выберет не ту входную точку. Имейте в виду, что
    этот способ задания входной точки программы пригоден только в
    случае файла типа .EXE. Программа типа .COM всегда выполняется,
    начиная со смещения 100H сегмента команд.




Командный процессор



Командный процессор


    Наряду с файловой системой DOS обеспечивает операционную среду для
    прикладных программ.  Первый компонент DOS с которым сталкивается
    пользователь, - это командный процессор.  Эта часть DOS берет на
    себя обработку вводимых пользователем команд и запуск прикладных
    программ.
 
      В первый момент после включения питания "интеллектуаль- ность"
    IBM PC невысока: возможно и имеется большой потенциал, но
    способностей хоть как-то реализовать его немного. В постоянной
    памяти ЭВМ хранятся программы тестирования компонентов системы -
    POST (Power=On Self=Test - самопроверка при включении) и установки
    в начальное состояние устройств ввода-вывода. Остальная часть
    записанной в ПЗУ базовой системы ввода-вывода BIOS (Basic Input
    Output System) предоставляет программисту, работающему с языком
    ассемблера, набор средств, которые помогают ему обращаться к
    аппаратным средствам, не беспокоясь о том, как технически они
    реализованы. Но этого не достаточно, чтобы обеспечить среду для
    выполнения серьезных прикладных программ.
 
      Последнее является функцией DOS. После установки ЭВМ в
    начальное состояние программа POST выполныет загрузку DOS с диска
    или дискеты в оперативную память. Этот процесс называется загрузкой
    системы. Первое, что делает DOS, - загружает минимальную программу,
    необходимую для загрузки остальной части DOS. По окончании процесса
    загрузки на дисплей выводтися название операционной системы и
    указание на авторские права. Помимо всего прочего в названии указан
    номер соответствующей версии операционной системы. Иногда этот
    номер играет важную роль, так как каждая новая версия означает
    дополнительные функциональные возможности операционной системы.
 
      После операции загрузки система готова к приему команд от
    оператора (за исключением специального случая, о котором будет
    сказано ниже). На этом этапе управление передается командному
    процессору - DOS произвела загрузку в память командного процессора,
    файловой системы и других служебных программ, и все они готовы
    выполнять свои функции. Передача управления командному процессору
    индицируется им следующим запросом к оператору
 
      A>
 
      Этот запрос содержит двоякий смысл. Символ ">" означает
    готовность командного процессора к приему команды. Префикс "A"
    указывает на выбранный по умолчанию дисковод с гибким диском. Так
    как DOS может обрабатывать файлы, расположенные только на каком-то
    одном диске, то в случае одновременной работы с несколькими дисками
    или дискетами пользователь должен указать, к какому из дисководов
    следует обратиться системе. В персональной ЭВМ дисководы
    обозначаются буквами латинского алфавита. У вычислительной системы
    с двумя накопителями на гибких дисках имеется дисковод A: и
    дисковод B:. Жесткий диск обычно обозначается C: (После
    наименования дисковода следует двоеточие.) Обычно файлы,
    используемые системой DOS, считываются с дисковода, выбранного
    системой по умолчанию, если только оператор не изменит этот
    порядок. Для того чтобы считать файл с выбранного по умолчанию
    дисковода, системе требуется только имя этого файла. Для считывания
    файла с любого другого дисковода нужно кроме имени файла указать
    DOS наименование дисковода.
 
      Только в ответ на команды, которые поступают от пользователя
    DOS выполняет какие-то действия. Все команды, относящиеся к DOS,
    вводятся в ответ на запрос с ее стороны, индицируемый символом ">".
    Пользователь вводит имя нужной ему команды, после чего поступившая
    заявка обрабатывается командным процессором. Как он обрабатывает
    эту заявку, зависит от команды, которую ввел пользователь. Имеются
    встроенные, или резидентные команды, которые всегда доступны. Либо
    команда может инициировать нерезидентное, или транзитное
    выполнение. Для выполнения таких команд должен существовать
    определенный файл на диске.
 
      Встроенные команды обеспечивают поддержку файловой системы. Они
    сделаны резидентными в DOS, поскольку часто используются при работе
    с данными, хранящимися на дисках. После того, как пользователь ввел
    команду, интерпретатор командных строк передает управление
    соответствующей программе DOS. Программа реализует свою функцию,
    соответствующую спецификации введенной команды, затем возвращает
    управление DOS. На Фиг.5.1 приведены резидентные команды дисковой
    операционной системы.
 
            Команда           Действие
          --------------------------------------------------------
            COPY    Копирует файл с одного места в другое
            DATE    Вывод/модификация текущей даты
            DIR     Вывод каталога дискеты
            ERASE   Удаление файла с дискеты
            PAUSE   Система ждет нажатия клавиши
            REM     Вывод комментария
            RENAME        Изменить имя файла
            TIME    Вывод/модификация текущего времени
            TYPE    Вывод содержимого файла
          --------------------------------------------------------
            Фиг. 5.1 Резидентные команды DOS
 
      Примером резидентной команды может служить команда DIR, которая
    выводит на дисплей справочник дискеты. На Фиг.5.2 показаны выходные
    данные, полученные в результате выполнения команды чтения каталога.
    Обратите внимание, что в справочнике дискеты для каждого
    записанного на ней файла уазываются его имя и тип, а также длина в
    байтах, дата и время его создания. Так как для загрузки любой
    программы DOS необходимо выполнить команду чтения каталога, то эта
    команда являеися встроенной.
 
             ----------------------------------------
            A>dir
             Volume in drive A has no label
             Directory of  A:\
 
            COMMAND  COM      37637  17/06/88  12:00
            AUTOEXEC BAT         38 4/03/89  17:33
            CONFIG      SYS     96  17/06/88  12:00
            COUNTRY  SYS      12838  17/06/88  12:00
            DISKCOPY COM      10428  17/06/88  12:00
            DISPLAY  SYS      15741  17/06/88  12:00
            FDISK COM  70151  17/06/88  12:00
            FORMAT      COM  22923  17/06/88  12:00
            KEYB  COM  14759  17/06/88  12:00
            KEYBOARD SYS      23360 3/08/88  12:00
            REPLACE  EXE      17199  17/06/88  12:00
            SELECT      COM  3674 3/08/88  12:00
            SELECT      HLP  27562 3/08/88  12:00
            SELECT      PRT  1594 3/08/88  12:00
            SYS   COM  11472  17/06/88  12:00
            012345      678    109  17/06/88  12:00
                   16 File(s)     17408 bytes free
             ------------------------------------------
 
                  Фиг. 5.2 Каталог дискеты
 
      Если пользователь введет нерезидентную команду, то командный
    процессор попытается загрузить ее с диска или дискеты. В этом
    случае он выступает в роли загрузчика программы. Предполагая, что
    имя файла совпадает с именем команды, интерпретатор просматривает
    справочник в поисках такого файла, а когда находит, загружает его в
    память. Затем интерпретатор передает управление загруженной
    программе, которая теперь может реализовывать свои функции.
 
      Но не каждый файл может быть загружен с помощью командного
    процессора. Тип файла должен быть либо .COM, либо .EXE, что
    соответствует либо файлу команды, либо выполняемому файлу. Конечным
    продуктом выполнения операций ассемблирования и редактирования
    связей является файл типа .EXE. Отсюда вытекает возможность
    написания собственной системной команды. Если написали,
    странслировали и скомпоновали программу на языке ассемблера, а
    затем оставили эту программу на дискете, то ее можно загружать и
    выполнять так же, как и любую другую программу DOS. Именно это
    позволяет писать программы, которые будут выполняться под
    управлением DOS.
 
      Существуют различия между файлами типа .COM и типа .EXE. Они
    имеют различные структуры и управление им передается по- разному.
    Хотя обычно после этапа редактирования связей получаются файлы типа
    .EXE, существуют некоторые причины для использования и файлов типа
    .COM. В следующем разделе будут обсуждаться различия между типами
    файлов и тем, как преобразовывать файл типа .EXE в файл типа .COM.
 
      Рассмотрим теперь пример вызова программы. Хорошей иллюстрацией
    здесь может служить ассемблер. Чтобы вызвать ассемблер, нужно
    ввести команду
 
      A>ASM
 
      Каталог дискеты содержит файл с именем ASM.EXE. Это и есть
    ассемблер. После ввода команды ASM, он просматривает дискету в
    дисководе A: (выбранном по умолчанию). Найдя файл с именем ASM.EXE,
    командный процессор загружает и передает управление ассемблеру.
    Теперь вычислительная система находится под управлением ассемблера.
    При благополучном завершении трансляции ассемблер вернет управление
    командному процессору. Заметьте, что файл, содержащий ассемблер -
    это файл типа .EXE, поэтому он может быть загружен командным
    процессором.
 
      Если ассемблер находится на дискете, установленной в дисководе
    A:, то пользователь может обратиться к другому дисководу следующим
    образом:
 
      A>B:ASM
 
      Префикс B: указывает DOS, что файл находится на дискете в
    дисководе B:. Файл полностью определяется не только указанием его
    имени, но и дисковода, с которого он будет считан. Одного имени
    файла достаточно только при считывании файла с дисковода,
    выбранного по умолчанию. Для того чтобы оттранслировать файл,
    расположенный на носителе в дисководе B: с помощью ассемблера,
    который находится на дискете в дисководе A:, нужно ввести следующую
    команду:
 
      A>ASM B:FILE.ASM
 
      В этой команде одновременно задаются программы ASM, считываемые
    с дисковода, который выбран по умолчанию, и исходный файл FILE.ASM,
    считываемый с дисковода B:.
 
      Это можно сделать и другим способом: задать команду B:, которая
    предписывает DOS сделать дисководом, выбираемым по умолчанию,
    дисковод B:.
 
      A>B:
      B>A:ASM FILE.ASM
 
      Заметьте, что после этого запрос со стороны системы меняется на
    B>. Приведенная в этом примере команда по своему действию полностью
    идентична команде из предыдущего примера.
 
      Кроме того, интерпретатор командных строк может работать с
    файлом, называемом файлом с пакетом команд, с расширением имени
    .BAT. Этот тип файла совершенно отличен лт файлов типа .COM и типа
    .EXE. Файл типа .BAT не содержит выполняемого машинного кода, а
    состоит из нетранслированных команд, которые интерпретируются
    командным процессором. Все содержащиеся в этом файле команды
    выполняются DOS по очереди. Можно считать, что файл типа .BAT
    заменяет процедуру ввода команд с клавиатуры, так как они
    содержатся непосредственно в соответствующем файле. После того,
    как система закончила обработку пакетного файла, она обращается за
    следующей командой к клавиатуре. Все эти особенности делают файл
    типа .BAT удобным средством выполнения повторяющихся заданий. После
    того, как такой файл уже создан, единственная команда обращения к
    нему заменяет ввод всех содержащихся в нем команд.
 
      В системе допускается специальный файл с именем AUTOEXEC.BAT.
    Если такой файл имеется на диске, то сразу же после своей загрузки
    DOS обращается к нему, передавая управление командам, составляющим
    пакет команд этого файла. Это позволяет автоматически загружать с
    диска нужную пользователю программу. Предположим, что вы написали
    прикладную программу, использующую DOS. (При этом говорят, что
    программа была написана с "привязкой к DOS".) В случае создания
    файла AUTOEXEC.BAT, инициирующего выполнение прикладной программы,
    оператору, работающему с этой прикладной программой, совершенно не
    нужно будет знать, как работает интерпретатор командных строк. Он
    знает, что управление осуществляет программа и это главное.




Многомодульность



Многомодульность


    Как указывает само имя программы LINK, ее основное назначение
    "связать", или объединить, несколько объектных модулей в один
    выполняемый модуль.  Все рассмотренные до сих пор примеры
    относились к одномодульным программам, т.е.  все, что они должны
    были выполнять, реализовывалось в одном исходном модуле.  Однако
    этот путь не всегда возможен или желателен.
 
      Имеется ряд причин, в силу которых программа программа сожет
    быть разбита на несколько модулей. Во-первых, размер программы.
    Редактирование очень большой программы становится весьма громоздким
    и трудным делом, а ее ассемблирование занимает много времени.
    Предположим, что вы допустили ошибку в единственной строке
    ассемблерной программы, состоящей из 5000 строк. Чтобы изменить
    одну эту строку, необходимо выполнить редактирование всей
    программы. После этого нужно оттранслировать всю программу из 5000
    строк, что занимает довольно много времени. После относительно
    быстрого этапа редактирования связей программа готова к выполнению.
 
      Предположим, теперь, что вместо того, чтобы иметь дело с
    программой, состоящей из 5000 строк, вы разбиваете ее на десять
    программых модулей, по 500 строк в каждом. Для внесения изменений в
    единственную строку вам необходимо выполнить редактирование только
    исходного файла из 500 строк. Ассемблирование программы из 500
    строк занимает значительно меньше времени, чем программы из 5000
    строк. Этап редактирования связей все так же будет занимать
    относительно немного времени, особенно по сравнению с
    ассемблированием большой программы. Уменьшение размеров отдельных
    модулей позволяет более быстро осуществить процесс
    редактирования-ассемблирования.
 
      Другая причина разбиения программы на меньшие модули связана с
    этапом ее разработки. В случае больших программных средств в их
    разработке, как правило, участвуют несколько человек. Если имеется
    один исходный файл, то отдельные программисты вынуждены работать с
    ним по очереди. Такой подход очень быстро становится неудобным.
 
      И последняя из причин создания модульных программ заключается в
    возможности их универсального использования. Предположим, что
    созданная вами программа включает несколько подпрограмм. Если вы
    хорошо справились с этим, то каждая из подпрограмм выполняет у вас
    особую функцию с хорошо документированной спецификацией входа и
    выхода. Через некоторое время при написании новой программы вы
    захотите использовать в ней ту же самую подпрограмму. Если эта
    подпрограмма оформлена в виде отдельного программного модуля, то
    включить ее в новую программу не составляет труда. В противном
    случае вам придется как-то выделить этот фрагмент из исходной
    программы и перенести его в новую программу. После одной-двух
    попыток вам, возможно, захочется поискать другой способ.
 
      Разбиение программы на модули требует от программиста ряда
    действий. Во-первых, нужно тщательно продумать, как ваша программа
    будет строиться из меньших компонентов. Во-вторых, нужно определить
    как входные, так и выходные параметры этих меньших программ. И
    наконец, должна быть возможность обмена данными между программными
    модулями. Первые два пункта относятся к основам программирования и
    мы их здесь касаться не будем. Последний же пункт связан с
    ассемблированием и редактором связей, поэтому его мы рассмотрим.
 
      Если разработанная вами программа состоит из нескольких
    модулей, то в этом случае у ведущей, или основной программы должна
    быть возможность вызывать эти подпрограммы. Это реализуется
    командой CALL, имеющей один операнд - метку соответствующей
    подпрограммы. Во всех рассмотренных до сих пор примерах
    подпрограмма была частью того же самого программного модуля, так
    что ассемблеру было точно известно, каким будет адрес подпрограммы
    в момент ее выполнения. Это позволяло ассемблеру определять
    правильное значение смещения для поля адреса в команде.
 
      Теперь мы сталкиваемся с ситуацией, когда ассемблирование
    подпрограммы осуществляется отдельно от ассемблирования команды
    CALL. Это означает, что ассемблер не может определить правильный
    адрес для процедуры вызова, т.е. из-за того, что ассемблирование
    подпрограммы и основной программы осуществляется раздельно, у
    ассемблера нет способа предсказать правильное значение адреса.
    Однако эту задачу может выполнить программа LINK. Определение
    адресов производится на этапе редактирования связей. Так как при
    работе программы LINK ее входом являются все программные модули, то
    редактору связей известно, где будет конец каждой из подпрограмм.
    После этого редактор связей может определить значения тех адресов,
    которые были известны ассемблеру.




Операция редактирования связей



Операция редактирования связей


    Рассмотрим теперь операции, с помощью которых описанные выше
    программные модули были объединены в один исполняемый модуль.
    Ассемблирование программ выполняется с помощью команд, описанных в
    предыдущем разделе:
 
      B:>A:MAS    FIG5=13,,,;
      B:>A:MASM FIG5=14,,,;
 
       При этом получается два объектных модуля FIG5=13.OBJ и
    FIG5=14.OBJ.  Для объединения этих модулей вызывается программа
    LINK.  На Фиг. 5.15 приведены операции, с которых начинается работа
    программы LINK.
 
      В данном примере предполагается, что дискета с DOS установлена
    в дисководе A:, рабочая дискета - в дисководе B:, и дисковод B:
    выбирается по умолчанию. После запуска программа LINK запрашивает
    пользователя, для каких объектных файлов следует выполнить
    редактирование связей. Имена файлов вводятся без указания типа
    .OBJ. Если связываемых модулей больше одного, то их имена вводятся
    через разделитель "+". В данном примере выполняется редактирование
    связей для модулей FIG5=13 и FIG5=14.
 
            -------------------------------------------
               A>LINK
 
               IBM Personal Computer Linker
               Version 1.10 (c)Copyright IBM Corp 1982
               Object Modules [.OBJ]: B:FIG5_13+B:FIG5_14
               RunFile [A:FIG5_13.EXE]: B:
               List File [NUL.MAP]: B:
               Libraries {.LIB]:
 
               A>
            -------------------------------------------
 
           Фиг. 5.15 Выполнение редактирования связей
 
      Модули связываются в том же порядке, в каком их имена
    передаются программе LINK. В данном случае программа FIG5=13
    предшествует программе FIG5=14. Перечисление модулей в обратном
    порядке привело бы к такому же обратному порядку их расположения в
    итоговом модуле. Как правило, порядок формирования программы
    безразличен. Единственное исключение делается для входной точки
    программы.
 
      Следующий запрос редактора связей относится к имени
    исполняемого, или рабочего, файла. По умолчанию ему присваивается
    имя первого из объектных модулей с расширением .EXE. Вводя другое
    имя, можно изменить имя файла, но не его расширение .EXE.
 
      Далее запрашивается имя файла для хранения карты связей.
    Допускается любое имя, однако в режиме по умолчанию формирование
    карты не производится. В нашем примере ввод символа B: является
    указанием редактору связей записать карту связей на дисководе B:.
    Редактор связей выбрал для этого файла имя FIG5=13.MAP. Полученный
    в результате операции связывания файл FIG5=13.MAP приводится на
    Фиг. 5.16 и будет рассмотрен в следующем параграфе.
 
      Последний запрос редактора связей касается библиотек программ,
    которые могут быть включены в полученный при связывании модуль. В
    случае некоторых языков высокого уровня на этом шаге может
    возникнуть необходимость указать имя библиотеки рабочих программ.
    Для программ на языке ассемблера такой необходимости нет.




Отладчик DEBUG



Отладчик DEBUG


    Программа DEBUG (отладчик) дает средство обнаружения ошибок при
    работе с программой, транслированной в машинный язык.  Программа
    DEBUG обеспечивает возможность пошагово выполнять программу и
    следить за тем, что при этом происходит.  Программа DEBUG - это еще
    одно программное средство, поставляемое как часть DOS.  Вы
    загружаете ее так же, как и любую другую программу, и работаете в
    диалоге, используя клавиатуру и экран.  Когда программа DEBUG
    ожидает каких-либо действий со стороны пользователя, то свой запрос
    она обозначает символом "-".
 
      Вместо перечисления всех команд, которые входят в программу
    DEBUG, используем данный отладчик для проверки работы только что
    составленной программы, приведенной на Фиг. 5.13 и П5.14. На
    Фиг. 5.17 приведен соответствующий листинг.
      В данном примере сначала вызывается программа DEBUG и
    указывается та программа, которую предполагается отлаживать - в
    нашем случае программа FIG5=13.EXE. После того, как программа DEBUG
    загружена, она производит загрузку отлаживаемой программы.
    Управление теперь принадлежит отладчику, и он с помощью символа "-"
    показывает, что ожидает ввода. До тех пор, пока вы не введете для
    него указаний, с программой ничего происходить не будет.
 
      Команда R выводит содержимое всех регистров в момент,
    соответствующий загрузке программы FIG5=13 и передаче ей управления.
    Содержимое регистров не требует пояснений, за исключением, быть
    может, значений флагов.  Флаг NV указывает на отсутствие
    переполнения, флаг UP - флаг направления и т.д.  При выводе
    содержимого регистров в последней строке приводится следующая
    выполняемая команда.  В ячейке 04C5:0000 записана команда PUSH DS.
                  B>A:DEBUG  FIG5_13.EXE
                  -R
 
                  AX=0000  BX=0000  CX=0120  DX=0000  SP=FFF0  BP=0000  SI=0000  DI=0000
                  DS=2C26  ES=2C26  SS=2C26  CS=2C26  IP=0000   NV UP DI PL NZ NA PO NC
                  2C26:0000  1E             PUSH      DS
 
                  -U
 
                  2C26:0000  1E             PUSH      DS
                  2C26:0001  B80000   MOV AX,0000
                  2C26:0004  50             PUSH      AX
                  2C26:0005  FC             CLD
                  2C26:0006  8CC8     MOV AX,CS
                  2C26:0008  8ED8     MOV DS,AX
                  2C26:000A  8D361D00       LEA SI,[001D]
                  2C26:000E  AC             LODSB
                  2C26:000F  A24000   MOV [0040],AL
                  2C26:0012  E82C00   CALL      0041
                  2C26:0015  803E40000A     CMP [0040],0A
                  2C26:001A  75F2     JNZ 000E
                  2C26:001C  CB             RET Far
                  2C26:001D  9D             POPF
                  2C26:001E  E2A0     LOOP      FFC0
                  2C26:0020  20AFE0AE       AND [BX+AEE0],CH
                  2C26:0024  A3E0A0   MOV [A0E0],AX
 
                  -D2C26:0
 
                  2C0E:0000   CD 20 00 A0 00 9A EE FE 1D F0 ED 04 04 1C 3C 01   . ............<.
                  2C0E:0010   22 1B EB 04 22 1B 04 1C 01 01 01 00 02 06 FF FF   "..."...........
                  2C0E:0020   FF FF FF FF FF FF FF FF FF FF FF FF 08 2C D0 FF   .............,..
                  2C0E:0030   04 1C 14 00 18 00 0E 2C FF FF FF FF 00 00 00 00   .......,........
                  2C0E:0040   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   ................
                  2C0E:0050   CD 21 CB 00 00 00 00 00 00 00 00 00 00 20 20 20   .!...........
                  2C0E:0060   20 20 20 20 20 20 20 20 00 00 00 00 00 20 20 20       .....
                  2C0E:0070   20 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00       ........
 
                  -RAX
                  AX 0000
                  :1234
 
                  -E 2C0E:21
                  2C0E:0021   69.   73.   20.   61.20 20.
 
                  -G 3C
 
                  AX=0E54  BX=0000  CX=003F  DX=0000  SP=FFEA  BP=0000  SI=001D  DI=0000
                  DS=2C26  ES=2C26  SS=2C26  CS=2C26  IP=003C   NV UP DI PL NZ NA PO NC
                  2C26:003C CD10          INT      10
                  -T
 
                  AX=0E54  BX=0000  CX=003F  DX=0000  SP=FFEA  BP=0000  SI=001D  DI=0000
                  DS=2C26  ES=2C26  SS=2C26  CS=F000  IP=0165   NV UP DI PL NZ NA PO NC
                  F000:F065 FB            STI
                  -T  
 
          Фиг. 5.17 Листинг отладчика для Фиг 5.13 и 4.14 (начало)
                  AX=0E54  BX=0000  CX=003F  DX=0000  SP=FFEA  BP=0000  SI=001D  DI=0000
                  DS=2C26  ES=2C26  SS=2C26  CS=F000  IP=0166   NV UP DI PL NZ NA PE NC
                  F000:F066 FC            CLD
                  -G 2C26:3E
 
                  T
                  AX=0E54  BX=0000  CX=003F  DX=0000  SP=FFEA  BP=0000  SI=001D  DI=0000
                  DS=2C26  ES=2C26  SS=2C26  CS=2C26  IP=013E   NV UP DI PL NZ NA PO NC
                  2C26:003E         RET
                  -G
 
                  Эта программа - тест
 
                  Program terminated normally
                  -R
 
                  AX=0754  BX=0000  CX=003F  DX=0000  SP=FFEA  BP=0000  SI=001D  DI=0000
                  DS=2C26  ES=2C26  SS=2C26  CS=2C26  IP=003E   NV UP DI PL NZ NA PO NC
                  2C26:003E C3            RET
                  -Q
 
                  B>
 
      Фиг. 5.17 Листинг отладчика для Фиг 5.13 и 4.14 (продолжение)
 
 
      Здесь следует немного задержаться и проанализировать
    информацию, которая записывается в регистры. Содержимое регистров
    соответствует моменту, когда программа FIG5=13 получает управление
    от командного процессора. Обратите внимание, что пара регистров
    CS:IP указывает на первую команду, определяемую оператором END
    программы. Регистры DS и ES указывают на префикс программного
    сегмента. И наконец, пара регистров SS:SP указывает на сегмент
    STACK. Описанное состояние регистров будет сравниваться позднее с
    аналогичным состоянием регистров для файла типа .COM.
 
      Чтобы просмотреть большее число команд, надо ввести символ "U"
    (дизассемблировать), и на дисплей выводится около двадцати
    следующих команд. Это удобно при обладке программы, для которой нет
    листинга. Дизассемблирование программы позволяет просмотреть ее
    команды. Это может сэкономить вам бумагу и время в случае, когда в
    программу внесены небольшие изменения. Так как ваш листинг больше
    не соответствует той программе, которая находится в памяти, то ее
    дизассемблирование позволяет вам узнать правильные адреса для
    каждой команды.
 
      Однако у дизассемблирования с помощью программы DEBUG имеется
    ряд недостатков по сравнению с использованием листинга. Отсутствуют
    комментарии (может быть очень важные для понимания программы), и
    ячейки памяти идентифицируются только по адресу, а не по имени
    переменной. Например, хранящаяся в ячейке 04C5:000E команда имеет,
    как показано на Фиг.5.13, следующий вид:
 
      MOV   OUTPUT_CHARACTER,AL
 
      а в дизассемблированном виде
 
      MOV   [0030],AL
 
      Это одна и та же команда. Для программиста, выполняющего
    отладку, имя переменной OUTPUT_CHARACTER говорит больше, чем адрес
    ячейки [0030]. Однако программе DEBUG не известны имена переменных,
    и она вынуждена оперировать фактическими адресами.
 
      Кроме того, программа, DEBUG не обеспечивает той же самой
    ассемблерной мнемоники, которую воспринимает ассемблер. Это значит,
    что некоторые команды будут выглядеть по-разному. Команда из ячейки
    04C5:0014 будет при дмзассемблировании иметь вид
 
      CMP   B,[3000],0A
 
      но та же саммая команда на Фиг.5.13 представлена в виде:
 
      CMP   OUTPUT_CHARACTER,10
 
      Программа дизассемблирования как на входе, так и на выходе
    работает только с шестнадцатеричными значениями. Этим объясняется
    появление значения 0A. Мы уже выяснили, почему получается значение
    [0030], вместо имени OUTPUT_CHARACTER. Что же такое символ "B,"?
 
      Ассемблер оперирует переменными вполне определенного типа. Это
    значит, что во время ассемблирования тип переменных может иметь
    значение: байт, слово или какой-нибудь другой. Таким образом, когда
    программист вводит команду, содержащую ссылку на область памяти, то
    ассемблеру известен размер этой области. На программа DEBUG не
    имеет представления о длине переменной, записанной по адресу
    [0030]. Однако программе дизассемблирования точно известно, что
    данная команда пересылает ровно один байт данных, указанных
    непосредственно в команде, по адресу [0030]. Таким образом, символ
    "B," указывает на то, что непосредственная операция состоит в
    пересылке одного байта. Для получения того же самого результата с
    помощью ассемблера соответствующая команда должна иметь вид:
 
      CMP   BYTE PTR [0030],10
 
      Вы можете рассматривать символ "B," как сокращение BYTE PTR.
    Аналогично символ W используется для WORD PTR,L - для длинного
    (far) возврата и т.д.
 
      Вместе с командой в дизассемблированном виде вводится и ее
    объектный код. Как вы можете заметить, по адресу 04C5:001C записаны
    какие-то команды, которых нет на Фиг. 5.13. Эта область данных,
    содержащая строку "Это тест". Однако команде, осуществляющей
    дизассемблирование, не известно, где в программе кончаются команды
    и начинаются данные. Таким образом она все интерпретирует как
    команды. (Кстати, именно эта последовательность команд выполнялась
    бы, если в вашей программе был сделан переход в рассматриваемую
    область данных.)
 
      Команда вывода на экран D позволяет просмотреть на дисплее
    области данных. Отображение на экране состоит из двух частей.
    Вместе с листингом содержимого ячеек памяти в шестнадцатеричном
    представлении приводятся символы в коде ASCII, которые
    соответствуют этим значениям. Если отображение команд подобным
    образом не имеет смысла, то область данных представляется очень
    ясно. Когда вам будет нечем особенно заняться, вы можете
    попробовать написать такую программу, команды которой в коде ASCII
    соответствуют инициалам вашего имени. С помощью отладчика можно
    изменять содержимое регистров и ячеек памяти. Если ввести символ R
    (регистр) и затем тип регистра, то на дисплей будет выведено
    содержимое этого регистра с возможностью его коррекции. Если нажать
    клавишу "возврат", то содержимое регистра останется прежним. Оно
    будет изменено, если ввести новое значение.
 
      Можно также модифицировать содержимое ячеек памяти. Ввод
    символа E (редактирование) позволяет это сделать. При этом
    программа DEBUG выводит на дисплей значения отдельных ячеек памяти,
    после которых следует символ . Вы можете изменить содержимое
    ячейки, вводя новое значение, либо нажать клавишу пробела, чтобы
    перейти к следующей ячейке, или - клавишу "возврат", чтобы
    вернуться к режиму запроса следующей команды отладчика. В
    рассматриваемом примере значения в первых трех ячейках остаются
    прежними. Содержимое ячейки 04C5:0024 изменено со значения 61H на
    значенее 20H. Так как эта ячейка входит в область данных, то
    выводимое сообщение будет отличаться от тог, которое было в
    транслированной программе.
 
      В любой команде, обращающейся к ячейкам памяти, предполагается,
    что адрес является частью команды. Команда E, как и команда
    отображения, выводит на дисплей содержимое ячейки по указанному в
    ней адресу. Точно так же можно было использовать адрес в команде
    дизассемблирования. Можно ввести адрес в виде сегмента и смещения,
    или только смещения. Если вы указали только смещение, то
    соответствующий сегментный регистр будет выбран программой DEBUG. В
    случае команды U используется регистр CS, а для команд D и E по
    умолчанию сегмент будет определяться регистром DS.
 
      Теперь попытаемся выполнить эту программу. Ее можно просто
    запустить и посмотреть, что будет происходить. На для этого не
    нужна программа DEBUG. Программа DEBUG позволяет задать точки
    останова, называемые "точками прерывания" программы. Благодаря
    введению в программу таких точек можно возвращать управление
    программе DEBUG. Это дает еще одну возможность проверки состояния
    памяти и регистров для того, чтобы контролировать ход выполнения
    программы.
 
      Команда G, (выполнять) передает управление от программы DEBUG
    пользовательской программе. Выполнение команд начинается с ячейки,
    задаваемой парой регистров CS:IP (так же, как в реальном
    микропроцессоре). Тестируемая программа продолжает выполняться до
    тех пор, пока она не пройдет точку прерывания. В нашем примере мы
    задали точку прерывания по адресу 3CH. Так как мы указали только
    смещение, то для определения сегмента программа DEBUG использует
    содержимое регистра CS. Из листинга, приведенного на Фиг. 5.14,
    видно, что смещение 3CH соответствует команде INT 10H. В
    рассматриваемом примере программы было выбрано именно это место,
    потому что это - та точка, где управление передается подпрограмме
    BIOS, вызываемой из ПЗУ. Проверка программы в этой точке
    гарантирует, что мя установили регистры в нужное состояние перед
    выполнением подпрограммы BIOS.
 
      Как только встречается точка прерывания, управление
    возвращается программе DEBUG. При этом, так же как и в случае
    команды R, на дисплей выводятся содержимое регистров и следующая
    выполняемая команда. Так как управление опять передано программе
    DEBUG, вы можете использовать любую из команд отладки.
 
      Имеются ограничения на использование точек прерывания.
    Фактически точка прерывания реализуется кодом операции 0CCH.
    Соответствующая этому коду команда вызывает прерывание INT 3.
    Данное математическое прерывание возвращает управление программе
    DEBUG. Если какая-то команда возвращает управление отладчику, то
    точка прерывания должна находиться в начале этой команды. Если же
    точка прерывания выбрана где-то в другом месте, то управление не
    будет возвращено отладчику и будет выполняться не та команда
    программы, которая предполагалась. Например, если бы было задано
    "=G 3D", то по адресу 3CH была бы команда INT 0CCH, и дальнейшее
    выполнение программы предсказать трудно.
 
      Если точка прерывания выбрана осмотрительно, то никаких
    осложнений не будет. Командв "G" позволяет задать до десяти точек
    прерывания. После прохождения любой из них происходит
    восстановление исходных значений точек прерывания. Выполнение
    команды отладки "G" без указания точек прерывания никогда не выйдет
    ни на какую из ранее заданных точек прерывания, потому что все они
    были удалены. Если вы запустили программу, и произошел ее останов и
    она зациклилась, то возможно, что вернуть управление, которое
    передано программе, удастся только с помощью клавиши системного
    сброса Ctrl=Alt=Del, т.е. вам придется начать все с начала.
    Запуская незнакомую программу, следует быть осторожным.
 
      Если вы захотите ввести пермаментную точку прерывания,
    воспользуйтесь командой E для изменения значения первого байта
    команды на значение 0CCH. Эта точка прерывания будет там постоянно
    или, по крайней мере, до тех пор, пока вы ее не измените. Возможно
    вы захотите использовать это прерывание в точке входа в
    подпрограмму обработки ошибки и проанализируете возникающие ошибки
    более тщательно, чем при передаче их обработки программе.
 
      Существует еще одно обстоятельство, связанное с точками
    прерывания, о котором следует помнить. Если вы попытаетесь задать
    точку прерывания в области, относящейся к ПЗУ, то ничего не
    получится. Так как вы не можете менять содержимое ПЗУ, то команда
    0CCH никогда туда не запишется.
 
      Рассмотрим следующую команду отладчика - команда трассировки T.
    Данная команда инициирует выполнение одной команды отлаженной
    программы. В нашем примере команда T выполнена несколько раз. Как
    вы можете убедиться, выполняется несколько первых команд BIOS,
    вызванной по прерыванию INT 10H. Подпрограмма BIOS, естественно,
    находится в ПЗУ. Команда трассировки позволяет "приостановить"
    программу при ее выполнении в ПЗУ.
 
      Перед передачей управления пользовательской программе команда
    трассировки выставляет в регистре флагов соответствующий бит
    трассировки. Этот бит инициирует прерывание INT 1 после выполнения
    каждой команды. Вектор прерывания INT 1 возвращает управление
    программе DEBUG. Выполнение прерывания INT 1 автоматически
    сбрасывает бит трассировки в исходное состояние. Это значит, что
    программа DEBUG не прерывается после выполнения каждой ее команды.
    Команда трассировки служит прекрасным средством "пробиться" через
    трудный участок программы. При этом программа DEBUG выводит на
    экран каждую команду вместе с содержимым регистров как раз в
    момент, предшествующий выполнению этой команды. Так как в данном
    режиме используются не точки прерывания, а собственно прерывания,
    то можно выполнять трассировку даже программ ПЗУ.
 
      Вернемся к нашему примеру. Команда =G 4C5:3E обеспечивает
    полное выполнение подпрограммы BIOS. Обратите внимание, что
    программа вывела на дисплей символ "Э". Вызванная по прерыванию 10H
    подпрограмма BIOS выводит символы на дисплей. В данном случае это
    первый символ выводимого сообщения. Так как теперь можно быть
    уверенными, что наша программа выполняется правильно, то, введя
    символ "G", мы обеспечим выполнение программы до конца без точек
    прерывания.
 
      В данном примере рассматривался файл типа .EXE, и потому для
    возврата управления системе DOS мы не могли использовать прерывание
    INT 20H. Вместо этого программа записала в стек состояние регистра
    DS и значение 0. Управление передается обратно системе DOS в конце
    основной программы с помощью команды возврата типа FAR. Программа
    DEBUG распознает это и фиксирует состояние машины в конце
    тестируемой программы. Если бы это был файл типа .EXE, то
    прерывание INT 20H аналогичным образом вернуло бы управление
    программе DEBUG. Теперь, уделив достаточно времени этому примеру,
    мы можем выйти из программы DEBUG и вернуться в систему DOS с
    помощью команды завершения Q.




Перекрестные ссылки



Перекрестные ссылки


    Чтобы воспользоваться файлом перекрестных ссылок, сформированным
    ассемблером, требуется дополнительная обработка.  Для перевода
    файла типа .CRF в текстовый файл в коде ASCII нужно выполнить
    программу CREF.  Программа CREF запускается точно так же, как и
    ассемблер, за исключением того, что при запуске задаются только два
    файла:  входной файл типа .CRF и выходной файл типа .REF.  При
    вводе команды DOS A> CREF запрашиваются имена двух файлов.
    Альтернативой может служить команда A> CREF B:FIG5=10, B, которая в
    качестве входного файла использует файл B:FIG5=10.CRF и формирует
    файл B:FIG5=10.REF.  Как и случае с ассемблером имеются и другие
    варианты данной команды, описанные в справочном руководстве по
    Макроассемблеру.
 
      На Фиг. 5.12 показан выход формирователя перекрестных ссылок.
    Данная конкретная таблица перекрестных ссылок получена для
    программы, приведенной на Фиг. 5.6. В левом столбце перечислены все
    символические имена, определенные в программе. Напротив каждого
    символичсекого имени приводится последовательность целочисленных
    параметров. Числа соответствуют номерам строк, в которых появляется
    это имя. Если за номером строки следует символ #, то имя юыло
    определено в этой строке. Если же символ # отсутствует, то значит в
    этой строке содержится ссылка на имя.
           Фиг. 5.6 Пример использования функций ДОС
 
             Symbol  Cross Reference         (# is definition)    Cref-1
 
            BAD_CLOSE_MSG  . . . . . . . . .    50#   169
            BAD_OPEN_MSG . . . . . . . . . .    37#   86
            BAD_READ_MSG . . . . . . . . . .    46#   141
            BAD_WRITE_MSG  . . . . . . . . .    41#   105   159
 
            CHANGE_RECORD  . . . . . . . . . 126      128#
            CHARACTER_LOOP . . . . . . . . .    94#   110
            CHAR_BAD_MSG . . . . . . . . . .    60#   123
            CLOSE_OK . . . . . . . . . . . . 168      171#
            CREATE_OK  . . . . . . . . . . .    3#   28   28   173
 
            DISK_TRANSFER_ADDRESS  . . . . .    26#   68   95   144   145   146   148   152
 
            ERROR_EXIT . . . . . . . . . . .    76#   87   106   142   160   170
 
            FCB  . . . . . . . . . . . . . .    5#   71   82   99   136   155   165
            FCB_BLOCK  . . . . . . . . . . .    15#
            FCB_CURRENT_RECORD . . . . . . .    23#   89
            FCB_DATE . . . . . . . . . . . .    18#
            FCB_DRIVE  . . . . . . . . . . .    6#
            FCB_EXT  . . . . . . . . . . . .    11#
            FCB_FILE_SIZE  . . . . . . . . .    17#
            FCB_NAME . . . . . . . . . . . .    7#
            FCB_RANDOM_RECORD  . . . . . . .    24#   90   91   135
            FCB_RECORD_SIZE  . . . . . . . .    16#   92
            FCB_RESV . . . . . . . . . . . .    19#
            FILE_ERROR_MSG . . . . . . . . .    33#   75
 
            INPUT_BAD_MSG  . . . . . . . . .    54#   117
 
            KEYBOARD_BUFFER  . . . . . . . .    32#   112   115   124   150
            KEYBOARD_ERROR . . . . . . . . . 118#     130   132
            KEYBOARD_LOOP  . . . . . . . . . 111#     121   162
            KEY_INPUT_OK . . . . . . . . . . 116#     122#
 
            NO_FILE  . . . . . . . . . . . .    74    80#
 
            PROGRAM_EXIT . . . . . . . . . . 127      163#
            PROGRAM_START  . . . . . . . . .    29    66#
 
            RANDOM_RECORD_OK . . . . . . . . 140      143#
            RANDOM_WRITE_OK  . . . . . . . . 158      161#
            RECORD_SIZE  . . . . . . . . . .    31#   92   96   151
            WRITE_OK . . . . . . . . . . . . 104      107#
 
            Фиг. 5.12 Таблица перекрестных ссылок для
                    программы Фиг. 5.6
 
      Как может быть использован листинг перекрестных ссылок?
    Перекрестные ссылки позволяют определить, в каком месте
    используется каждое имя. Например, если переменная получает Mincho"'>    неверное значение, то листинг перекрестных ссылок показывает все
    команды, где имеются ссылки на данное символическое имя. Это
    поможет определить те команды, с которыми связано неправильное
    выполнение программы. Возможно также, что вы занимаетесь
    модификацией уже существующей программы, написанной кем-то другим
    или же вами, но так давно, что вы успели забыть, как эта программа
    работает. Если вы захотели изменить одну из подпрограмм, то вам
    должно быть известно, какие части программы эту подпрограмму
    используют. Листинг перекрестных ссылок показывает все команды CALL
    (а так же другие команды, имеющие к этому отношение), в которых
    есть ссылки на это символическое имя. Проанализировав
    соответствующие места программы, вы можете решить: допустимо ли
    вносимое изменение для всех тех участков, откуда вызввается данная
    подпрограмма. Листинг перекрестных ссылок значительно облегчает
    задачу определения всех участков программы, содержащих ссылки.




Преодразование файла типа exe в файл типа com



Преодразование файла типа .exe в файл типа .com.


    На дискете с DOS имеется сервисная программа под именем EXE2BIN.
    Эта программа преобразует файл типа .EXE в файл типа .COM.    Однако
    программа EXE2BIN работает не со всеми файлами.  Далее излагается
    метод использования программы DEBUG, с помощью которого любая
    программа преобразуется в файл типа .COM.
 
      На Фиг. 5.18 приведена программа, которую мы будем
    преобразовывать. Эта программа выполняет точно такие же функции,
    что и программа предыдущего примера, а именно - выводит на дисплей
    фразу : "Это тест". Однако в данной программе эта строка выводится
    на дисплей по прерыванию INT 21H с помощью функции 9 DOS.
            Microsoft (R) Macro Assembler Version 5.00              1/1/80 04:02:33
            Фиг. 5.18 Пример преобразования файла типа .EXE в тип .COM  Page     1-1
 
 
                                          PAGE    ,132
                                          TITLE   Фиг. 5.18 Пример преобразования файла типа .EXE в тип .COM
             0000                   CODE    SEGMENT
                                          ASSUME  CS:CODE,DS:CODE
             0100                         ORG     100H
 
             0100  8D 16 010A R                 LEA     DX, MESSAGE
             0104  B4 09                        MOV     AH, 9H                ; Функция вывода строки ДОС
             0106  CD 21                        INT     21H             ; Вывод строки на экран
             0108  CD 20                        INT     20H             ; Возврат в ДОС
 
             010A  9D E2 A0 20 AF E0 AE     MESSAGE DB      'Эта программа - тест', 10, 13, '$'
                 A3 E0 A0 AC AC A0 20
                 2D 20 E2 A5 E1 E2 0A
                 0D 24
             0121                   CODE    ENDS
                                          END
 
            Фиг. 5.18 Пример перевода .EXE в .COM
 
      Обратите внимание, что данная программа записана как файл типа
    .COM. На это указывает оператор ORG 100H, предшествующий первой
    команде. Остальная часть программы должна быть перемещаемым
    сегментом команд, и об этом не нужно забывать при написании
    программы, которая будет преобразовываться в файл типа .COM.
 
      Ассемблирование и редактирование связей этой программы
    осуществляется обычным способом. Однако до запуска программы DEBUG
    нужно изменить в имени файла тип .EXE на тип .COM. Это необходимо
    сделать, так как программа DEBUG не позволяет записывать файл типа
    .EXE. На Фиг. 5.19 показана последовательность шагов, которую нужно
    выполнить. В данном примере вводится команда программы DEBUG без
    имени файла. В качестве имени можно было бы в данной строке указать
    FIG5=18.COM, зато его отсутствие позволило продемонстрировать
    некоторые другие функции программы DEBUG. Команда N отладчика
    позволяет задать имя файла. После этого команда L выполняет
    загрузку файла в память. Если указать имя файла в команде DEBUG, то
    последняя выполнит все то же самое, что и команды N и L.
      Теперь, когда файл загружен, вы обнаружите, что в
    дествительности программа загрузилась, начиная со смещения 400H.
    Команда M сдвигает содержимое области памяти с 400H на 100H. Длина
    области, равная 1000H, была выбрана для гарантии того, что там
    поместится вся программа. Теперь программа соответствует формату
    файла типа .COM и может быть опять записана на дискету. Однако
    прежде, чем это сделать, вы изменяете содержимое регистра CX, чтобы
    он указал фактическую длину программы. При любом считывании и
    записи файлов на дискету, осуществляемых программой DEBUG, длина
    файла хранится в регистре CX. Так как файл типа .COM теперь намного
    короче, чем был файл типа .EXE, то мы можем сэкономить дисковую
                  B>A:ASM FIG5_18,,,;
                  The IBM Personal Computer Assembler
                  Version 1.00 (c)Copyright IBM Corp 1981
 
                  Warnings Severe
                  Errors      Errors
                  0     0
 
                  B>A:LINK FIG5_18,,,;
                  Ibm Personal Computer Linker
                  Version 1.10 (C)Copyright IBM Corp 1982
 
                   Warning: No STACK segment
                  There was 1 error detected.
 
                  B>RENAME FIGS5_18.EXE FIGS5_18.COM
 
                  B>A:DEBUG
                  -NFIGS_18.COM
                  -L
                  -M 400 1000 100
 
                  -U100 10F
 
                  06D7:0100 BA091    MOV  DX,0109
                  06D7:0103 B409          MOV  AH,09
                  06D7:0105 CD21          INT  21
                  06D7:0107 CD20          INT  20
                  06D7:0109 54            PUSH SP
                  06D7:010A 68            DB   68
                  06D7:010B 69            DB   69
                  06D7:010C 7320          JNC  012E
                  06D7:010E 69            DB   69
                  06D7:010F 7320          JNC  0131
 
                  -D100
 
                  06D7:0100  BA 09 01 B4 09 CD 21 CD-20 54 68 69 73 20 69 73   :..4.M!M' This is
                  06D7:0110  20 61 20 74 65 73 74 DA-0D 24 00 00 00 00 00 00    a test..$.......
                  06D7:0120  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
                  06D7:0130  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
                  06D7:0140  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
                  06D7:0150  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
                  06D7:0160  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
                  06D7:0170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00    ................
 
                  -RCX
                   CX 0380
                  :120
 
                  -W
 
                  Writing 0120 bytes
                  -Q
                   Фиг. 5.19 Пример преобразования из.EXE в .COM (начало)
                  >BDEBUG FIG5_18.COM
                  -R
 
                  AX=0000  BX=0000  CX=0120  DX=0000  SP=FFF0  BP=0000  SI=0000  DI=0000
                  DS=04B5  ES=04B5  SS=04B5  CS=04B5  IP=0100   NV UP DI NZ NA PO NC
 
                  -Q
 
                  B>FIG5_18
                  Эта программа - тест
 
      Фиг. 5.19 Пример преобразования из.EXE в .COM (продолжение)
 
    память, задав в регистре CX правильное значение для программы.
    Команда W записывает файл обратно на дискету. Кстати, это еще одно
    преимущество использования файлов типа .COM. Программа DEBUG не
    будет записывать файл типа .EXE на дискету, потому что в памяти
    отсутствует информация головной метки. В то же время файл типа .COM
    может быть записан на дискету программой DEBUG. Если вы отлаживаете
    программу и вам нужно изменить в ней один или два байта без ее
    повторного ассемблирования (это называется "латанием" программы),
    то это можно сделать. Просто внесите в программу изменения,
    убедитесь, что регистр CX установлен правильно, и с помощью команды
    W запишите программу на дискету.
 
         Команда        Описание
      -------------------------------------------------
            D     Вывод содержимого памяти
            E     Изменить содержимое памяти
            F     Заполнить блок памяти
            G     Выполнять программу
            H     Шестнадцатеричное сложение и вычитание
            I     Считать и показать значение из порта
            L     Загрузить с диска
            M     Переслать блок памяти
            N     Назначить имя файла
            O     Вывести значение в порт
            Q     Выход из отладчика
            R     Вывести значения регистров
            S     Поиск строки байт
            T     Выполнить одну команду
            U     Дизассемблировать блок кода
            W     Записать данные на диск
      --------------------------------------------------
            Фиг. 5.20 Команды DEBUG
 
      В результате работы отладчика получился новый вариант программы
    FIG5=18.COM. Обращая внимание на состояние регистров, мы видим, как
    они устанавливаются в случае файла типа .COM. Сравните это с
    показанным на Фиг.5.17 состоянием регистров для файла типа .EXE.
    Разница между ними поможет уяснить некоторые различия между файлами
    типа .COM и типа .EXE.
      Имеются и другие команды, используемые при работе с отладчиком
    DEBUG. На Фиг. 5.20 приведен полный набор команд для работы с
    программой DEBUG. В руководстве по DOS подробно описаны эти
    команды.




Редактор связей



Редактор связей


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

      Программа редактирования связей LINK (LINK.EXE), записанная на
    той же дискете, что и другие распространенные в DOS программы,
    фактически реализует две различные функции. Во-первых, она может
    связать много различных объектных модулей в одну программу.
    Во-вторых, на основе ассемблерного объектного модуля редактор связи
    формирует выполняемый загружаемый модуль. Рассмотрим по отдельности
    обе эти функции программы LINK.


Создание программы на языке Ассемблера



Создание программы на языке Ассемблера


    Путь от идеи к готовой для выполнения программы состоит из
    нескольких этапов.  В данном разделе рассматриваются этапы создания
    программы на языке ассемблера для IBM PC.  К обсуждаемым здесь
    средствам относятся:  строковый редактор, ассмеблер, редактор
    связей (компоновщик) и отладчик.  С помощью редактора создаются
    исходные программы на языке ассемблера.  Ассемблер преобразует
    исходную программу в объектный код, который очень близок к
    машинному языку.  Редактор связей трансформирует объектный код в
    файл типа .EXE, содержащий программу, которая готова к выполнению.
    И наконец, программа-отладчик может оказать помощь в выявлении
    ошибок в программе.
 
СТРОКОВЫЙ РЕДАКТОР ДОС
 
    Редактор строк формирует текстовые файлы.  Содержимое текстового
    файла представлено в коде ASCII.  Редактор позволяет вводить нужный
    вам текст в файл.  Если затем понадобится изменить файл, то для
    этого опять используется редактор.
 
      Редактор строк (EDLIN) входит в состав DOS IBM PC. Файл
    EDLIN.COM является внешней командой, т.е. загружается в память
    только по запросу. Для запуска редактора должна быть выполнена
    следующая команда:
 
      A>EDLIN FILE.ASM
 
      где FILE.ASM - имя текстового файла, с которым будет работать
    редактор. Файл FILE.ASM уже может существовать, как в случае, когда
    вы вносите изменения в сформированную программу. Если же такого
    файла еще нет, то он будет создан с помощью редактора EDLIN. По
    окончании редактирования результирующий текст помещается в файл
    FILE.ASM. Если в данном редактировании файл не создавался, то
    редактор EDLIN выполняет переименование старого варианта файла
    FILE.ASM в файл FILE.BAK (backup - копия). Создание копии файла
    позволяет с ее помощью устранить любые серьезные ошибки, допущенные
    при редактировании файла. Вы ликвидируете файл со внесенными при
    редактировании ошибками и переименовываете файл .BAK в файл .ASM.
    Таким образом, это служит подстраховкой при редактировании текста.
 
      Редактор EDLIN является редактором строк. Каждую строку текста
    он обрабатывает отдельно и этим отличается от экранного редактора,
    который выводит на экран целый фрагмент редактируемого текстового
    файла. При работе с экранным редактором, таким как Персональный
    Редактор (Personal Editor), разработанный фирмой IBM, вы
    перемещаете курсор и осуществляете редактирование в любом месте
    экрана в то время, как с помошью редактора EDLIN каждый раз
    редактируется только одна строчка текста. Если вы собираетесь
    основательно заняться программированием на языке ассемблера, то вам
    лучше пользоваться экранным редактором. Поставляемый фирмой IBM
    Персональный Редактор является очень хорошим экранным редактором
    текста. Именно с его помощью были подготовлены все примеры в этой
    книге. Редактор EDLIN рассматривается здесь только потому, что он
    входит в состав DOS. Однако учмтывая, что это не лучший вариант
    редактора, описание редактора EDLIN включает только краткое
    упоминание его команд и соответствующий пример. Для того, чтобы
    подробней ознакомиться с командами редактора EDLIN, следует
    обратиться к руководству по DOS.
 
      На Фиг.5.7 подытожены сведения о командах редактора EDLIN. При
    разборе примера мы будеи на них ссылаться.
 
            Действие         Синтаксис
         --------------------------------------------------------------------------------
           Изменение строки         [n] A
           Уничтожение строки       [строка][,строка] D
           Редактировать строку     [строка]
           Конец редактирования     E
           Вставка строки           [строка] I
           Просмотр строк           [строка][,строка] L
           Выход из редактора       Q
           Замена контекста         [строка][,строка] [?] ЗаменяемаяСтрока [<F6>Строка]
           Поиск контекста          [строка][,строка] [?] СтрокаПоиска
           Записать строки          [n] W
         --------------------------------------------------------------------------------

            Фиг. 5.7 Команды EDLIN (Copyright IBM 1981)
 
      Фиг. 5.8 иллюстрирует выполнение двух этапов редактирования
    с использованием редактора EDLIN. В первой части редактирования
    создается файл с именем FIG5=8.ASM. Сообщение "New file" ("новый
    файл") указывает на то, что файла с таким именем до этого не было.
    Символом "*" обозначается запрос со стороны редактора EDLIN. Всякий
    раз, когда на дисплее появляется этот символ, можно вводить любую
    из команд, приведенных на Фиг.5.7. Команда "I" позволяет вводить
    текст в файл. По мере ввода текста редактор EDLIN указывает на
    экране номера строк. Ввод порции текста завершается нажатием
    клавиши Control=Z (на листинге - ^Z). Команда E завершает этап
    редактирования, записывает файл и возвращает управление DOS.
      На второй части Фиг. 5.8 показано редактирование файла,
    созданного в первой чати. Редактор вызывается той же самой
    командной строкой, а сообщение "End of input file" ("конец ввода
    файла") указывает на то, что данный файл уже существует. Команда L
    выводит на экран текущее содержимое файла. В данном примере
    вносятся изменения в некоторые строки программы при выполнении
    команды редактирования. Если ввести символ "3", то на дисплей будет

 
      A>EGLIN FIG5_8.ASM
      New file
      *I
           1:*    PAGE  ,132
           2:*CODE      SEGMENT
           3:*    ASSUME      CS:CODE
           4:*
           5:*START:    PROC  NEAR
           6:*    MOV   AX,CODE
           8:*    MOV   DS,AX
           8:*    RET
           9:*START:    ENDP
          10:*END
          11:*^C
      *E
      A>
      A>EDLIN FIG5_8.ASM
      End of input file
      *L
           1:*    PAGE  ,132
           2: CODE      SEGMENT
           3:     ASSUME      CS:CODE
           4:
           5: START     PROC  NEAR
           6:     MOV   DS,AX
           8:     MOV   DS,AX
           8:     RET
           9: START     ENDP
          10: END
      *3
           2:*CODE      SEGMENT
           2:*CODE      SEGMENT,DS:CODE
      *5
           5:*START:          PROC  NEAR
           5:*START:    PROC  NEAR
      *6
           6:*    MOV   AX,CODE
           6:*    MOV   AX,CS
      *9I
           9:*
          10:*^C
      *L
           1:*    PAGE  ,132
           2: CODE      SEGMENT
           3:     ASSUME      CS:CODE
           4:
           5: START     PROC  NEAR
           6:     MOV   DS,AX
           8:     MOV   DS,AX
           8:     RET
           9:
          10: START     ENDP
          11: END
       *E
       A>
      --------------------------------------------
            Фиг. 5.8 Пример работы с EDLIN
    выведена третья строка, готовая для редактирования. У системы
    имеется набор встроенных команд построчного редактирования, которые
    приведены на Фиг.5.9. Эти команды редактирования можно использовать
    как при работе с редактором EDLIN, как и всегда, когда
    осуществляется ввод символов с клавиатуры под управлением DOS, в
    частности, при вводе команд, относящизся к командному процессору.
 
      Вернемся к примеру, приведенному на Фиг. 5.8. После того, как
    строка с указанным номером выведена на дисплей, ее можно
    отредактировать с помощью команд DOS. Клавиша F3 позволяет повторно
    вывести строку на дисплей и вносить изменения, начиная с конца
    строки. На примере редактирования строки 5 показано использование
    клавиша DEL для удаления из поля метки символа ":". При
    редактировании строки 6 используется клавиша (курсор вправо) для
    установки курсора после ",". Вслед за этим код "CODE" заменяется на
    символ "CS". Кроме того, для наглядности текста в данном примере
    производится вставка пустой строки перед строчкой 9. После этого
    опять выдается листинг файла для того, чтобы были видны внесенные
    при редактировании изменения. Команда E - окончание редактирования
    - возвращает управление DOS.
 
      ----------------------------------------------------------
       DEL - Уничтожение следующего символа в хранимой строке
       ESC - Отмена редактирования хранимой строки
       F1 или -> Копировать символ из хранимой строки
       F2 - Копировать все символы до заданного
       F3 - Копировать оставшиеся символы на экран
       F4 - Пропустить все символы до заданного
       F5 - Принять отредактированную строку для продолжения
       INS - Вставить символ в строку (отмена - INS повторно)
      ----------------------------------------------------------
 
            Фиг. 5.9 Клавиши редактирования в DOS
 
      Имеется и ряд других операций, которые можно выполнять с
    помощью редактора EDLIN и команж редактирования, вхадящих в DOS.
    Лучший способ изучить их - это просмотреть руководство по DOS и
    затем все операции попробовать. Однако в случае серьезных
    программных разработок лучше обратиться к экранному редактору.




Таблица символических имен



Таблица символических имен


    В листинговом файле содержится дополнительная информация, о которой
    до сих пор в этой книге нигде не говорилось.  После листинга
    программы выводится таблица символических имен.  На Фиг. 5.11
    показан пример такой таблицы, которая является таблицей имен для
    программы, приведенной на Фиг. 5.6.  В этой таблице перечислены все
    символические имена, определенные в программе, и кроме того,
    указаны атрибуты каждого из них.  Будучи очень формальной системой,
    ассемблер хранит эту информацию и для удобства пользователя
    приводит ее в листинговом файле.  Символические имена
    подразделяются при этом на метки, переменные и константы.  В
    таблице приведено значение каждого имени, если оно известно, и
    кроме того, безотносительно к типу данных - его длина.

            Microsoft (R) Macro Assembler  Version 4.00               4/15/89 23:14:35
 
            Фиг. 5.6 Пример использования функций ДОС           Symbols-1
 
            Segments and Groups:
 
                        N a m e           Size  Align Combine Class
 
            CODE . . . . . . . . . . . . . .    02D0  PARA  NONE
 
            Symbols:
                        N a m e           Type  Value Attr
 
            BAD_CLOSE_MSG  . . . . . . . . .    L BYTE      016D  CODE
            BAD_OPEN_MSG . . . . . . . . . .    L BYTE      011E  CODE
            BAD_READ_MSG . . . . . . . . . .    L BYTE      0153  CODE
            BAD_WRITE_MSG  . . . . . . . . .    L BYTE      0138  CODE
 
            CHANGE_RECORD  . . . . . . . . .    L NEAR      0260  CODE
            CHARACTER_LOOP . . . . . . . . .    L NEAR      0216  CODE
            CHAR_BAD_MSG . . . . . . . . . .    L BYTE      01AB  CODE
            CLOSE_OK . . . . . . . . . . . .    L NEAR      02CE  CODE
            CREATE_OK  . . . . . . . . . . .    L NEAR      01FD  CODE
 
            DISK_TRANSFER_ADDRESS  . . . . .    L BYTE      0090  CODE
 
            ERROR_EXIT . . . . . . . . . . .    L NEAR      01E5  CODE
 
            FCB  . . . . . . . . . . . . . .    L BYTE      005C  CODE
            FCB_BLOCK  . . . . . . . . . . .    L WORD      0068  CODE
            FCB_CURRENT_RECORD . . . . . . .    L BYTE      007C  CODE
            FCB_DATE . . . . . . . . . . . .    L WORD      0070  CODE
            FCB_DRIVE  . . . . . . . . . . .    L BYTE      005C  CODE
            FCB_EXT  . . . . . . . . . . . .    L BYTE      0065  CODE  Length = 0003
            FCB_FILE_SIZE  . . . . . . . . .    L DWORD 006C      CODE
            FCB_NAME . . . . . . . . . . . .    L BYTE      005D  CODE  Length = 0008
            FCB_RANDOM_RECORD  . . . . . . .    L DWORD 007D      CODE
            FCB_RECORD_SIZE  . . . . . . . .    L WORD      006A  CODE
            FCB_RESV . . . . . . . . . . . .    L BYTE      0072  CODE  Length = 000A
            FILE_ERROR_MSG . . . . . . . . .    L BYTE      0108  CODE
 
            INPUT_BAD_MSG  . . . . . . . . .    L BYTE      0189  CODE
 
                        Фиг. 5.11 Таблица символических имен
                           для программы Фиг. 5.6 (начало)
            KEYBOARD_BUFFER  . . . . . . . .    L BYTE      0103  CODE
            KEYBOARD_ERROR . . . . . . . . .    L NEAR      024C  CODE
            KEYBOARD_LOOP  . . . . . . . . .    L NEAR      0239  CODE
            KEY_INPUT_OK . . . . . . . . . .    L NEAR      0252  CODE
 
            NO_FILE  . . . . . . . . . . . .    L NEAR      01EB  CODE
 
            PROGRAM_EXIT . . . . . . . . . .    L NEAR      02BB  CODE
            PROGRAM_START  . . . . . . . . .    L NEAR      01CD  CODE
 
            RANDOM_RECORD_OK . . . . . . . .    L NEAR      0282  CODE
            RANDOM_WRITE_OK  . . . . . . . .    L NEAR      02B8  CODE
            RECORD_SIZE  . . . . . . . . . .    Number      0020
 
            WRITE_OK . . . . . . . . . . . .    L NEAR      0233  CODE
 
 
                173 Source    Lines
                173 Total     Lines
                 57 Symbols
 
              48738 Bytes symbol space free
 
                  0 Warning Errors
                  0 Severe    Errors
 
            Фиг. 5.11 Таблица символических имен
                 для программы Фиг. 5.6 (продолжение)