В предыдущем примере рассматривался файл типа .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.