Различия между программами COM и EXE файлов

Существует два основных типа загрузочных программ: EXE и COM. Рассмотрим требования к EXE-программам. DOS имеет четыре требования для инициализации ассемблерной EXE-программы: 1) указать ассемблеру, какие сегментные регистры должны соответствовать сегментам, 2) сохранить в стеке адрес, находящийся в регистре DS, когда программа начнет выполнение, 3) записать в стек нулевой адрес и 4) загрузить в регистр DS адрес сегмента данных.

Существуют определенные различия между программой, выполняемой как EXE-файл и программой, выполняемой как COM-файл.

1. Размер программы. EXE-программа может иметь любой размер, в то время как COM-файл ограничен размером одного сегмента и не превышает 64К. COM-файл всегда меньше, чем соответствующий EXE-файл; одна из причин этого - отсутствие в COM-файле 512-байтового начального блока EXE-файла.

2. Сегмент стека. В EXE-программе определяется сегмент стека, в то время как COM-программа генерирует стек автоматически. Таким образом при создании ассемблерной программы, которая будет преобразована в COM-файл, стек должен быть опущен.

3. Сегмент данных. В EXE программе обычно определяется сегмент данных, а регистр DS инициализируется адресом этого сегмента. В COM-программе все данные должны быть определены в сегменте кода.

4. Инициализация. EXE-программа записывает нулевое слово в стек и инициализирует регистр DS. Так как COM-программа не имеет ни стека, ни сегмента данных, то эти шаги отсутствуют. Когда COM-программа начинает работать, все сегментные регистры содержат адрес префикса программного сегмента (PSP),

- 256-байтового (шест. 100) блока, который резервируется операционной системой DOS непосредственно перед COM или EXE программой в памяти. Так как адресация начинается с шест. смещения 100 от начала PSP, то в программе после оператора SEGMENT кодируется директива ORG 100H.

5. Обработка. Для программ в EXE и COM форматах выполняется ассемблирование для получения OBJ-файла, и компоновка для получения EXE-файла. Если программа создается для выполнения как EXE-файл, то ее уже можно выполнить. Если же программа создается для выполнения как COM-файл, то компоновщиком будет выдано сообщение:

Warning: No STACK Segment

(Предупреждение: Сегмент стека не определен)

 

ПРИМЕР ПРОГРАММЫ

Программа преобразования двузначного шестнадцатеричного числа в символьном виде в двоичное представление.

Вход: исходное шестнадцатеричное число из двух цифр вводится с клавиатуры

Выход: результат преобразования помещается в регистр dl.

<1> data segment para public “data”;сегмент данных

<2> message db “Введите две 16-теричные цифры, $”

<3> data ends

<4> stk segment stack

<5> db 256 dup (“?”);сегмент стека

<6> stk ends

<7> code segment para public “code”;начало сегмента кода

<8> main proc;начало процедуры main

<9> assume cs:code,ds:data,ss:stk

<10> mov ax,data;адрес сегмента данных в регистр ах

<11> mov ds,ax;ax в ds

<12> mov ah,9

<13> mov dx,offset message

<14> int 21h

<15> xor ax,ax;очистить регистр ах

<16> mov ah,1h;1h в регистр ah

<17> int 21h;генерация прерывания с номером 21h

<18> mov dl,al;содержимое регистра al в регистр dl

<19> sub dl,30h;вычитание: (dl)=(dl)-30h

<20> cmp dl,9h;сравнить (dl) с 9h

<21> jle M1;перейти на метку М1, если dl<9h или dl=9h

<22> sub dl,7h;вычитание: (dl)=(dl)-7h

<23> M1:;определение метки М1

<24> mov cl,4h;пересылка 4h в регистр сl

<25> shl dl,cl;сдвиг содержимого dl на 4 разряда влево

<26> int 21h;вызов прерывания с номером 21h

<27> sub al,30h;вычитание: (dl)=(dl)-30h

<28> cmp al,9h;сравнить (al) c 9h

<29> jle M2;перейти на метку М2, если al<9h или al=9h

<30> sub al,7h;вычитание: (al)=(al)-7h

<31> M2:;определение метки М2

<32> add dl,al;сложение: (dl)=(dl)+(al)

<33> mov ax,4c00h;пересылка 4с00h в регистр ax

<34> int 21h;вызов прерывания с номером 21h

<35> main endp;конец процедуры main

<36> code ends;конец сегмента кода

<37> end main;конец программы с точкой входа main

 

Строки 1-3 определяют сегмент данных. В строке 2 описана текстовая строка с сообщением «Введите две шестнадцатеричные цифры».

Строки 4-6 описывают сегмент стека, который является просто областью памяти длиной 256 байт, инициализированной символами «”?”». Отличие сегмента стека от сегментов других типов состоит в использовании и адресации памяти. В отличие от сегмента данных (наличие которого необязательно, если программа не работает с данными), сегмент стека желательно определять всегда.

Строки 7-36 содержат сегмент кода. В этом сегменте в строках 8-35 определена одна процедура main.

Строка 9 содержит директиву ассемблера, которая связывает сегментные регистры с именами сегментов.

Строки 10-11 выполняют инициализацию сегментного регистра DS.

Строки 12-14 выводят на экран сообщение message:

Строка 15 подготавливает регистр АХ к работе, обнуляя его.

Строки 16-17 обращаются к средствам операционной системы для ввода символа с клавиатуры. Введенный символ операционная система помещает в регистр AL.

Строка 18 пересылает содержимое AL в регистр DL. Это делается для того, чтобы освободить AL для ввода второй цифры.

Строка 19 преобразует символьную цифру в ее двоичный эквивалент путем вычитания 30h, в результате чего в регистре DL будет двоичное значения числа.

В строках 20-21 выясняется, нужно ли корректировать двоичное значение DL. Если оно лежит в диапазоне 0…9, то в DL находится правильный двоичный эквивалент введенного символа шестнадцатеричной цифры. Если значение в DL больше 9, то введенная цифра является одним из символов A,B,C,D,E,F. В первом случае строка 21 передаст управление на метку М1.

В строках 24-25 значение в DL сдвигается на 4 разряда влево, освобождая место в младшей тетраде под младшую шестнадцатеричную цифру.

В строке 26 в регистр AL вводится вторая шестнадцатеричная цифра.

В строках 27-29 выясняется, попадает ли двоичный эквивалент второго символа шестнадцатеричной цифры в диапазон 0…9. Наша вторая цифра не попадает в диапазон, поэтому для получения правильного двоичного эквивалента нужно произвести дополнительную корректировку. Это делается в строке 38.

Строки 33-34 предназначены для завершения программы и возврата управления операционной системе.

 

СТРУКТУРЫ

Описание типа структуры

Структура - это составной объект, занимающий несколько соседних ячеек памяти. Это тип данных, состоящий из фиксированного числа элементов разного типа. Компоненты структуры называются полями, они могут быть разного типа (размера) - байт, слово и т. д. Поля именуются, доступ к полям осуществляется по именам. Для использования структур в программе необходимо выполнить 3 действия.

1. Задать шаблон структуры. По смыслу это означает определение нового типа данных, который впоследствии можно использовать для определения переменных этого типа.

2. Определить экземпляр структуры. Этот этап подразумевает инициализацию конкретной переменной с заранее определенной структурой.

3. Организовать обращение к элементам структуры.

Существует разница между описанием структуры в программе и ее определением. Описание структуры в программе означает лишь указание компилятору ее схемы или шаблона; память при этом не выделяется. Компилятор извлекает из этого шаблона информацию о расположении полей структуры и их значениях по умолчанию. Определение структуры означает указание транслятору на выделение памяти и присвоение этой области памяти символического имени. Описать структуру можно только один раз, а определить любое количество раз.

Описание шаблона структуры.

Прежде чем использовать структуру, надо описать ее тип - указать, сколько в ней полей, какие имена у полей и т. д. Описание типа структуры выглядит так:

<имя типа> STRUC

<описание поля>

…….

<описание поля>

<имя типа> ENDS

Описание типа открывает директива STRUC, где указывается имя, которое дали типу структуры. Это же имя должно быть в директиве ENDS. Между этими двумя директивами может быть указано любое число директив, описывающих поля структуры.

Например, тип структуры DATE из трех полей Y (год), M(месяц), D(день) можно описать так:

 

DATE STRUC

Y DW 2004

M DB 3

D DB?

DATE ENDS

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

После того как описан тип структуры, можно определять в программе переменные этого типа, отводить под них память. Такие переменные называются переменными-структурами или просто структурами. Описываются они с помощью директив следующего вида:

 

имя_переменной имя_типа <нач_знач {, нач_знач}>

 

Пример описания переменных-структур:

DT1 DATE <?, 6, 9>

DT2 DATE <2005,, >

DT3 DATE <,, >

 

Y M D
?    
    ?
    ?

Это директивы особого рода. До этого мы рассматривали директивы, названиями которых были служебные слова, а здесь названием является имя DATE. Каждая такая директива описывает одну переменную, имя которой указывается в начале директивы.

 

DT2 DATE <2005,, > эквивалентно DT2 DATE <2005>

DT3 DATE <,, > эквивалентно DT3 DATE < >

Одной директивой можно описать сразу несколько структур, т. е. можно описать массив, элементами которого являются структуры. Например по директиве

 

DTS DATE <, 12, 5 > 10 dup (<>)

 

описывается массив из 11 структур типа DATE, причем поля первой из них будут иметь начальные значения: 2004, 12, 5, а остальные десять структур получают один и тот же набор начальных значений, взятых по умолчанию: 2004, 3,?.

Описав тип структуры и переменные этого типа, получаем право работать с этими переменными-структурами. Как единое целое структуры обрабатываются редко, обычно они обрабатываются по полям. чтобы сослаться на поле структуры, надо использовать конструкцию вида

 

<имя переменной-структуры>.<имя поля>

DT3.D

Такая конструкция обозначает ту ячейку памяти, которую занимает указанное поле указанной переменной. Встречая эту конструкцию, ассемблер заменяет ее на адрес данной ячейки.

Пример. Если в переменной DT1 хранится мартовская дата, то требуется записать сюда дату следующего дня года.

 

cmp DT1.M, 3

jne FIN; не март - FIN

cmp DT1.M, 31

je APRL; 31 марта - APRL

inc DT1.D; следующий день в марте

jmp FIN

APRL: mov DT1.M, 4; замена 31 марта 1 апреля

mov DT1.D, 1

FIN: ….

 

 

ОБЪЕДИНЕНИЯ

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

имя_объединения UNION

<описание полей>

имя_объединения ENDS

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

ПРОЦЕДУРЫ


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: