Справочник программиста на персональном компьютере фирмы IBM. Системные ресурсы - Преобразование программ из типа .EXE в тип .COM

ОГЛАВЛЕНИЕ

 

1.3.6 Преобразование программ из типа .EXE в тип .COM.

Программисты на ассемблере имеют возможность преобразовать
свои программы из обычного формата EXE в формат COM. Файлы EXE
имеют заголовок, содержащий информацию для привязки; DOS привязы-
вает некоторые адреса программы при загрузке. С другой стороны,
файлы COM существуют в таком виде, что привязка не требуется -
они хранятся уже в том виде, в котором загружаемая программа
должна быть в памяти машины. По этой причине файлы EXE по меньшей
мере на 768 байтов больше на диске, чем их COM эквиваленты (хотя
при загрузке в память они будут занимать одинаковое место). Файлы
COM также быстрее загружаются, поскольку не требуется привязки.
Других преимуществ у них нет, а некоторые программы слишком слож-
ны и слишком велики, чтобы их можно было преобразовать в тип COM.
Привязка - это процесс установки адресов, связанных с сегмент-
ным регистром. Например, программа может указывать на начало
области данных следующим кодом:

MOV DX,OFFSET DATA_AREA
MOV AX,SEG DATA_AREA
MOV DS,AX

Смещение в DX связано с установкой сегментного регистра DS. Но
какое значение должен принимать сам DS? Программа требует абсо-
лютный адрес, но номер параграфа, в котором будет располагаться
DATA_AREA зависит от того, в какое место в памяти будет загружена
программа - а это зависит от версии MS DOS, а также от того,
какие резидентные программы будут находиться в младших адресах
памяти. По этой причине во время компоновки программы можно толь-
ко установить некоторые сегментные значения через смещения отно-
сительно начала программы. Затем, когда DOS осуществляет привяз-
ку, значение начального адреса программы прибавляется к сегмент-
ным значениям, давая абсолютные адреса, требуемые в сегментном
регистре. На рис. 1-6 показан процесс привязки.
Файлы COM не нуждаются в привязке, поскольку они хранятся в
таком виде, что не нуждаются в фиксации сегмента. Все в программе
хранится относительно начала кодового сегмента, включая все дан-
ные и стек. По этой причине вся программа не может превышать
65535 байт по длине, что соответствует максимальному смещению,
которое существует в используемой схеме адресации (поскольку
верхняя часть этого блока занята стеком, то реальное пространство
доступное для кода и данных немного меньше чем 65535 байт, хотя
стековый сегмент при необходимости может быть вынесен за границу
64K байтного блока). В файлах COM все сегментные регистры указы-
вают на начало PSP; сравните с файлами EXE, где DS и ES инициали-
зируются аналогичным образом, но CS указывает на первый байт
следующий за PSP.
Для представления программы в виде файла COM требуется соблю-
дение следующих правил:
1. Не оформляйте программу в виде процедуры. Вместо этого,
поместите в самое начало метку, вроде START, и завершите програм-
му оператором END START.
2. Поместите в начале программы оператор ORG 100H. Этот опера-
тор указывает начало кода (т.е. устанавливает счетчик комманд).
Программы COM начинаются с 100H, что является первым байтом,
следующим за PSP, поскольку CS указывает на начало PSP, которое
расположено на 100H байт ниже. Для того чтобы начать выполнение с
любого другого места поместите по адресу 100H инструкцию JMP.
3. Оператор ASSUME должен устанавливать DS, ES и SS таким
образом, чтобы они совпадали со значением для кодового сегмента,
например, ASSUME CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG.
4. Данные программы могут помещаться в любом месте программы,
до тех пор, пока они не перемешаны с кодом. Лучше начинать прог-
раммы с области данных, поскольку макроассемблер может выдавать
сообщения об ошибках при первом проходе, если имеются ссылки на
идентификатор данных, который еще не обнаружен. Для перехода к
началу кода используйте в качестве первой команды программы инст-
рукцию JMP.
5. Нельзя использовать фиксацию сегментов типа MOV AX,SEG
NEW_DATA. Достаточно указания одного смещения метки. В частности,
нужно опускать обычный код, используемый в начале программы для
установки сегмента данных, MOV AX,DSEG / MOV DS,AX.
6. Стековый сегмент полностью опускается в начальном коде.
Указатель стека инициализируется на вершину адресного пространст-
ва 64K, используемого программой (напоминаем, что стек растет
вниз в памяти). В программах COM он должен быть сделан меньше чем
64K, SS и SP могут быть изменены. Имейте ввиду, что при компонов-
ке программы компоновщик выдаст сообщение об ошибке, указывающее,
что сегмент стека отсутствует. Игнорируйте его.
7. Завершите программу либо инструкцией RET, либо прерыванием
20H. Прерывание 20H - это стандартная функция для завершения
программы и возврата управления в DOS. Даже когда программа за-
вершается инструкцией RET, на самом деле используется прерывание
20H. Это происходит потому, что вершина стека первоначально со-
держит 0. При выполнении завершающей инструкции программы RET, 0
выталкивается из стека, переназначая счетчик команд на начало
PSP. Находящаяся в этой ячейке функция 20H, выполняется как сле-
дующая инструкция программы, вызывая передачу управления в DOS.
Все это означает, что Вам не надо при старте программы помещать
на стек DS и 0 (PUSH DS / MOV AX,0 / PUSH AX), как это требуется
для EXE файлов.
После того как программа сконструирована таким образом, ас-
семблируйте и компонуйте ее как обычно. Затем преобразуйте ее в
форму COM c помощью утилиты EXE2BIN, имеющейся в MS DOS. Если имя
программы, построенной компоновщиком MYPROG.EXE, то просто введи-
те команду EXE2BIN MYPROG. В результате Вы получите программный
файл с именем MYPROG.BIN. Все что Вам останется после этого сде-
лать - переименовать этот файл в MYPROG.COM. Вы можете также
сразу использовать команду EXE2BIN MYPROG MYPROG.COM, для получе-
ния файла с расширением COM.

Низкий уровень.

В данном примере содержится полная короткая программа, которая
по установке переключателей определяет количество накопителей в
машине и затем выводит сообщение на экран. Она может служить
примером короткой утилиты того сорта, для которых формат COM
идеален.
CSEG SEGMENT
ORG 100H
ASSUME CS:CSEG, DS:CSEG, SS:CSEG
;---данные
START: JMP SHORT BEGIN ;переход к коду
MESSAGE1 DB 'The dip switches are set for $'
MESSAGE2 DB 'disk drive(s).$'
;---печать первой части сообщения
BEGIN: MOV AH,9 ;функция 9 прерывания 21H - вывод
MOV DX,OFFSET MESSAGE1 ;строки
INT 21H ;выводим строку
PUSH AX ;сохраняем номер функции на будущее
;---получаем установку переключателей из порта A микросхемы 8255
IN AL,61H ;получаем байт из порта B
OR AL,10000000B ;устанавливаем бит 7
OUT 61H,AL ;заменяем байт
IN AL,60H ;получаем установку переключат.
AND AL,11000000B ;выделяем старшие 2 бита
MOV CL,6 ;подготовка к сдвигу AL вправо
SHR AL,CL ;сдвигаем 2 бита в начало
ADD AL,49 ;добавляем 1, чтобы считать с 1
;и 48 для перевода в ASCII
MOV DL,AL ;помещаем результат в DL
MOV AL,61H ;должны восстановить порт B
AND AL,01111111B ;сбрасываем бит 7
OUT 61H,AL ;возвращаем байт
;---печать числа накопителей
MOV AH,2 ;функция 2 прерывания 21H
INT 21H ;печатаем число из DL
;---печать второй половины сообщения
POP AX ;берем номер функции со стека
MOV DX,OFFSET MESSAGE2
INT 21H ;выводим строку
INT 20H ;завершение программы
CSEG ENDS
END START