Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КНИГА_АСМ ассемблер.doc
Скачиваний:
61
Добавлен:
19.11.2019
Размер:
732.16 Кб
Скачать

2.10 Exe и com программы

Как известно, любая программа, в конце концов, транслируется в исполняемый файл, имеющий либо EXE, либо COM формат.

В EXE – программе создаются отдельные сегменты для кода, для данных и для стека, причем, если программа большая сегментов для данных и для кода может быть даже несколько. Все эти сегменты, так или иначе, описывает программист, при написании программы. Сегмент стека в принципе можно не описывать (не создавать), в этом случае программа будет работать со стеком DOS, хотя tlink при трансляции выдаст предупреждение (Warning: no stack), которое можно проигнорировать.

В COM – программе для кода, данных и стека отводится один общий сегмент. То есть COM формат используется при написании программ небольшого объема, полностью помещающихся в 64 Кбайта памяти. Мы в дальнейшем, в основном, будем придерживаться именно этого формата.

Загружая в память на исполнение как COM, так и EXE программу, DOS, помимо самой программы, размещает в памяти еще и так называемый «префикс программного сегмента» (PSP). Занимает PSP 256 байт памяти и в него DOS записывает различную служебную информацию. Для EXE программ DOS сама выделяет память под PSP, то есть программист об этом заботиться не должен. А вот для COM программ ситуация иная, здесь программист сам должен выделить память под PSP с помощью директивы org 100h (или org 256) .

Ситуация в памяти после загрузки на исполнение EXE программы показана на рис. 2.9.

Как видно из рисунка 2.9 сегментный регистр ds сразу после загрузки указывает «не туда куда надо» (ds указывает на первый байт PSP, а должен указывать на первый байт сегмента данных). Именно поэтому в начале EXE программы ds нужно настроить надлежащим образом.

ds; es

PSP

ss

сегмент

стека

ss:sp

сегмент данных

cs:ip

программа

(сегмент кода)

рис 2.9

Стандартно EXE программа пишется следующим образом:

stack segment stack ; описание сегмента стека

; Первое слово stack – название сегмента, можно было назвать сегмент и по другому, ; например, vasya. Кстати, транслятор нас предупредит, что мы используем ; зарезервированное слово stack не по назначению. Это предупреждение можно спокойно ; проигнорировать. Второе слово stack говорит транслятору, а потом и DOS ; что это сегмент стека.

db 100 dup (0) ; выделяем под стек 100 байт (можно больше, можно меньше)

stack ends ; конец сегмента стека

data segment ; описание сегмента данных

; здесь располагаются переменные и массивы

data ends

code segment ; описание сегмента кода

assume cs:code, ds:data

; Это директива для транслятора. Объяснять ее назначение долго и сложно. Проще ; поверить, что она необходима.

start: ; программа начинается с метки (любой!)

mov ax, data

mov ds, ax ; настраиваем ds на начало сегмента данных

; здесь пишется программа

mov ah, 4ch

int 21h ; стандартный выход из программы

code ends

end start ; startметка, с которой мы начали программу

Дадим необходимые пояснения. Все что находится в строке программы после «точки с запятой» транслятор понимает как комментарий. Сегменты stack, data и code можно было назвать и другими именами, но тогда мы должны использовать в директивах ends и assume и команде mov ax, data эти другие имена. Изменять второе слово stack нельзя, тогда у нас не будет создан сегмент стека. Причины настройки ds на начало сегмента данных объяснялись в этом разделе выше. Остается выяснить, зачем нужен стандартный выход из программы.

Когда процессор выполняет нашу программу, он «понятия не имеет» где она кончается. Он просто выбирает команды из памяти и их выполняет. Выполнив последнюю команду нашей программы, процессор продолжит выбирать информацию из памяти и буде пытаться выполнять эту информацию в качестве команд. Поскольку после последней команды программы в памяти, скорее всего, «мусор», такая ситуация почти наверняка приведет к зависанию системы. Поэтому в конце программы организуется корректный возврат управления в ту среду (DOS NAVIGATOR или Far или ….), из которой была запущена наша программа.

Ситуация в памяти после запуска СОМ программы представлена на рис. 2.10.

cs; es; ds; ss

PSP

cs:ip

программа

ss:sp

рис. 2.10

Как видно из рисунка 2.10 DOS настраивает все сегментные регистры на первый байт PSP. В регистр ip программист, выделяя директивой org 100h место под PSP, заносит 100h. После этого пара cs:ip указывает на первую команду программы. В указатель стека sp DOS загрузит число fffeh. После этого пара ss:sp указывает на ячейку, отстоящую почти на 64К от начала PSP, с тем, чтобы стек располагался как можно дальше от программы и данных и не мог их испортить при своем росте в сторону младших адресов (во всяком случае, уменьшается вероятность такой ситуации).

Стандартно СОМ программа пишется таким образом:

code segment

assume cs: code, ds: code

org 100h

start:

jmp begin ; перепрыгиваем область данных

; здесь можно располагать переменные и массивы

begin:

; здесь располагается программа

mov ah, 4ch

int 21h ; стандартный выход из программы

; здесь можно располагать переменные и массивы

code ends

end start

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