Страница 20 из 20 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 |