Ассемблер и макроассемблер
Ассемблер и макроассемблер
После того, как исходный файл уже создан, можно применить
ассемблер. Существуют две версии ассемблера: полная версия,
называемая Макроассемблером, которая на специальной, отведенной для
программы ассемблера дискете, именуется 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 (продолжение)