flda |
dw 250 |
;определение данных |
||||||
fldb |
dw 125 |
|
||||||
fldc |
dw ? |
|
||||||
DATASG ENDS |
|
|
|
|
|
|
|
|
;------------------------------------------------- |
|
|
|
|
|
|
|
|
codesg segment para 'Code' |
|
|||||||
begin proc far |
|
|||||||
assume cs:codesg,ds:codesg,ss:codesg,es:nothing |
||||||||
|
|
|
|
|
|
|
;записать ds в стек |
|
|
PUSH DS |
|||||||
|
SUB AX,AX |
|
|
|
;записать в стек |
|||
|
PUSH AX |
|
|
|
|
; нулевой адрес |
||
|
MOV AX,DATASG |
|
;поместить адрес DATASG |
|||||
|
MOV DS,AX |
|
|
; в регистр ds |
||||
|
mov ax,flda |
;переслать 0250 в ax |
||||||
|
add ax,fldb |
;прибавить 0125 к ax |
||||||
|
mov fldc,ax |
;записать сумму в fldc |
||||||
|
ret |
;вернуться в DOS |
||||||
begin endp |
|
|||||||
codesg ends |
|
|||||||
|
end begin |
|
||||||
Обратите внимание на следующие изменения в COM-программе (по сравнению с EXE-программой):
-сегмент стека и сегмент данных отсутствуют;
-директива assume указывает ассемблеру установить относительные адреса с начала сегмента кодов. Регистр cs также содержит этот адрес, являющийся к тому же адресом префикса программного сегмента (PSP). Директива org служит для резервирования 100h байтов от начального адреса под PSP;
-директива org 100h устанавливает относительный адрес для начала выполнения программы. Программный загрузчик использует этот адрес для командного указателя;
-команда jmp используется для обхода данных, определенных в программе.
Если элементы данных определяют после команд, то первая команда jmp не требуется. Кодирование элементов данных перед командами позволяет ускорить процесс ассемблирования и является методикой, рекомендуемой в руководстве по ассемблеру.
16
2.2. Стек для COM-программы
Для COM-файла DOS автоматически определяет стек и устанавливает oдинаковый общий сегментный адрес во всех четырех сегментных pегистрах. Если для программы размер сегмента в 64К является достаточным, то DOS устанавливает в регистре SP адрес конца cегмента – шестнадцатеричное fffe (FFFEh). Это будет верх стека. В обоих случаях DOS записывает затем в стек нулевое слово.
Возможность использования стека зависит от размера программы и ограниченности памяти. С помощью команды dir можно определить pазмер файла и вычислить необходимое пространство для стека.
2.3. Программы в виде COMфайлов
Пример 1
;Умножение двойных слов
codesg |
segment para 'Code' |
||
assume cs:codesg,ds:codesg,ss:codesg |
|||
org |
100h |
|
|
begin: |
jmp short main |
|
|
; --------------------------------------------- |
|
|
|
multcnd |
dw |
3206h |
;элементы данных |
|
dw |
2521h |
|
multplr |
dw |
6400h |
|
|
dw |
0A26h |
|
product |
dw |
0 |
|
|
dw |
0 |
|
|
dw |
0 |
|
; |
dw |
0 |
|
|
|
|
|
main proc |
near |
|
;основная процедура |
call |
e10xmul |
;вызвать 1-е умножение |
|
call |
z10zero |
;очистить произведение |
|
call |
f10xmul |
;вызвать 2-е умножение |
|
ret |
|
|
|
main endp |
|
|
|
;Умножение двойного слова на слово:
; -----------------------------------------------
e10xmul proc |
|
|
mov |
ax,multcnd+2 |
; умножить правое слово |
mul |
multplr |
; множимого |
mov |
product+4,ax |
;записать произведение |
|
|
17 |
mov |
product+2,dx |
|
mov |
ax, multcnd |
;умножить левое слово |
mul |
multplr |
; множимого |
add |
product+2,ax |
; сложить с полученным ранее |
adc |
product,dx |
|
ret |
|
|
e10xmul endp
;Умножение двух двойных слов:
;--------------------------------------------
f10xmul proc |
|
|
mov |
ax, multcnd+2 |
; слово-2 множимого |
mul |
multplr+2 |
; * слово-2 множителя |
mov |
product+6,ax |
; сохранить результат |
mov |
product+4,dx |
|
mov |
ax, multcnd+2 |
; слово-2 множимого |
mul |
multplr |
; * слово-1 множителя |
add |
product+4,ax |
; сложить с предыдущим |
adc |
product+6,dx |
|
adc |
product,00 |
;прибавить перенос |
mov |
ax, multcnd |
; слово-1 множимого |
mul multplr+2 |
; * слово-2 множителя |
|
add product+4, ax |
; сложить с предыдущим |
|
adc product+6,dx |
|
|
adc product,00 |
; прибавить перенос |
|
mov ax,multcnd |
; слово-1 множимого |
|
mul multplr |
; * слово-1 множителя |
|
add product+2,ax |
; сложить с предыдущим |
|
adc product,dx |
|
|
ret |
|
|
f10xmul endp |
|
|
;Очистка области результата:
;----------------------------------------
z10zero proc
mov product,0000 mov product+2,0000 mov product+4,0000 mov product+6,0000 ret
z10zero endp codesg ends
18
end begin
-----------------------------------------------------------
|
Пример 2 |
|
|
; |
Организация бесконечного цикла с помощью jmp |
||
codesg segment para 'Code' |
|
||
|
assume cs:codesg,ds:codesg,ss:codesg,es:codesg |
||
|
org 100h |
|
|
main proc near |
|
||
|
mov ax,01 |
;инициализация ax |
|
|
mov bx,01 |
;инициализация bx |
|
a20: |
mov cx,01 |
;инициализация cx |
|
add ax,01 |
;прибавить 01 к ax |
||
|
|||
|
add bx,ax |
;прибавить ax к bx |
|
|
shl cx,1 |
;удвоить cx |
|
|
jmp a20 |
;переход на a20 |
|
main endp |
|
||
codesg ends |
|
||
|
end main |
|
|
После ассемблирования получится программа:
;Организация цикла с помощью jmp
0100 |
|
codesg segment para 'Code' |
|
0100 |
|
assume cs:codesg,ds:codesg,ss:codesg,es:codesg |
|
0100 |
|
org 100h |
|
0100 |
|
main proc near |
|
0100 |
B8 0001 |
mov ax,01 |
;инициализация ax |
0103 |
BB 0001 |
mov bx,01 |
; инициализация bx |
0106 |
B9 0001 |
mov cx,01 |
; инициализация cx |
0109 |
|
a20: |
|
0109 |
05 0001 |
add ax,01 |
; прибавить 01 к ax |
010C |
03 D8 |
add bx,ax |
; прибавить 01 к bx |
010E |
D1 E1 |
shl cx,1 |
; удвоить cx |
0110 |
EB F7 |
mp a20 |
; переход на a20 |
0112 |
|
main endp |
|
0112 |
|
codesg ends |
|
0112 |
|
end main |
|
-----------------------------------------------------------
Пример 3
; Организация цикла командой loop codesg segment para 'Code'
assume cs:codesg,ds:codesg,ss:codesg,es:codesg org 100h
19
main proc near |
|
mov ax,01 |
; инициализация ax |
mov bx,01 |
; инициализация bx |
mov dx,01 |
; инициализация dx |
mov cx,10 |
; число циклов |
; |
|
a20: |
|
inc ax |
; прибавить 01 к ax |
add bx,ax |
; прибавить ax к bx |
shl dx,1 |
; удвоить dx |
loop a20 |
; уменьшить cx и повторить цикл, если |
; |
не нуль, т.е. переход на a20 |
ret |
;завершить работу |
begin endp |
|
codesg ends |
|
end begin |
|
Контрольные вопросы
1.Каков максимальный размер СОМ-программы?
2.Какие сегменты можно определить в программе, которая будет преобразована в COM-файл?
3.Как преобразовать исходный текст EXE-программы в СОМпрограмму?
4.Два варианта размещения данных в СОМ-программе.
5.Отличие директивы assume СОМ-программы от директивы assume EXE-программы.
6.Как формируется стек для СОМ-программ?
20