- •Глава 14 Элементы программирования на языке ассемблера После изучения данной главы вы должны знать:
- •Основные компоненты языка ассемблер Алфавит языка
- •Константы (числа и строки) Числа — только целые
- •Строки (литералы)
- •Команды (операторы)
- •Директивы (псевдооператоры)
- •Модификаторы
- •Адресация регистров и ячеек памяти в ассемблере
- •Непосредственная адресация
- •Прямая адресация регистров мпп
- •Адресация ячеек оп
- •Основные команды языка ассемблер
- •Команды пересылки данных
- •Арифметические команды
- •Команды сложения, вычитания и сравнения
- •Команды приращения
- •Команды умножения
- •Команды деления
- •Логические команды
- •Команды безусловной передачи управления
- •Команды перехода к подпрограмме и выхода из подпрограммы
- •Команда перехода к подпрограмме: call opr
- •Команда выхода из подпрограммы
- •Команды условной передачи управления
- •Команды условной передачи управления для беззнаковых данных
- •Команды условной передачи управления для знаковых данных
- •Команды условной передачи управления для прочих проверок
- •Команды управления циклами
- •Команды прерывания
- •Основные директивы ассемблера
- •Директивы определения идентификаторов
- •Директивы определения данных
- •Директивы определения сегментов и процедур
- •Видеооперации с прерыванием 21h dos
- •Программирование работы с клавиатурой
- •Программирование работы с принтерами
- •Печатающие устройства параллельного типа
- •Печатающие устройства последовательного типа
- •Программирование работы с файлами
- •Прерывания, используемые при работе с файлами на дисках
- •Некоторые аспекты создания исполняемых программ
- •Процедуры формирования программы
- •Структура программы на языке ассемблера для получения исполняемого файла формата exe
- •Основные сведения о листинге и его структуре
- •Особенности структуры машинных команд
- •Последовательность работы пк при выполнении программы
- •Краткие сведения об отладчике программ debug
- •Основные команды отладчика debug
- •Вопросы для самопроверки
Структура программы на языке ассемблера для получения исполняемого файла формата exe
Операционная система MS DOS предъявляет некоторые обязательные требования к структуре ASM-программы, предназначенной для последующего создания EXE-файла:
Программа может использовать 4 сегмента памяти, начальные адреса которых должны быть загружены в регистры микропроцессора CS, SS, DS и ES, а сами сегменты в явном виде определены в программе в виде операторных скобок: имя_сегмента segment ... имя_сегмента ends (версии MS DOS 4.0 и выше допускают более простое указание сегментов в программе: имя_сегмента).
В программе должно быть указание, какие сегментные регистры закрепляются за используемыми сегментами памяти; при исполнении программы сегментные регистры CS, SS, ES в соответствии с этими указаниями загружаются автоматически.
Сегмент данных DS в EXE-программе не может быть загружен автоматически, поскольку он используется программным загрузчиком для формирования начального адреса служебной области памяти — префикса программного сегмента (PSP), непосредственно предшествующего любой исполняемой программе EXE. Регистр сегмента данных DS должен быть инициирован принудительно — для этого следует в самом начале ASM-программы записать в стек вектор-адрес возврата к служебной области PSP: содержимое регистра DS и нулевое смещение, а затем в регистр DS загрузить адрес сегмента данных. PSP — это группа служебных слов в оперативной памяти, формируемая для каждой загружаемой программы пользователя и занимающая обычно 256 байтов (100h). При запуске программы пользователя в ОЗУ автоматически формируется PSP, и ее начальный адрес помещается в регистр DS.
Обеспечение после завершения выполнения программы возврата к префиксу программного сегмента; проще всего это можно сделать, оформив обращение к исполняемой программе в виде обращения к процедуре (главной процедуре, обязательно с атрибутом far) и поместив в конце программы команду возврата ret (выход из программы можно выполнить также, используя прерывание 20H DOS или функцию 4Ch прерывания 21H DOS, но управление при этом передается не в PSP, а непосредственно в резидентную часть программы COMMAND.COM).
Типовая структура ASM-программы включает в себя:
Имя программы.
TITLE prog.ASM
Может присутствовать комментарий назначения программы.
Инициализацию стековой памяти в сегменте стека:
STACKSEG segment stack
DW N dup(?) ; меньше 32 слов в стеке обычно задавать не следует
STACKSEG ends
Инициализацию всех переменных в сегменте данных:
DATASEG segment
; задаются имена всех констант и переменных,
; их начальные значения и резервируется память под них
DATASEG ends
Назначение сегментных регистров в сегменте кодов:
CODESEG segment
Assume CS:codeseg, DS:dataseg, SS:stackseg
Организацию главной программной процедуры far:
MAIN proc far
Запись адреса префикса программного сегмента (PSP) в стек:
push DS
sub AX, AX
push AX
Инициализацию содержимого регистра сегмента данных:
mov AX, dataseg
mov DS, AX
; при указании в команде в качестве операнда символического
; имени сегмента (dataseg) происходит пересылка начального адреса
; этого сегмента — неверно указывать offset dataseg
Текст программы пользователя в сегменте кодов:
основной текст программы
Восстановление адреса PSP в DS:
ret
Тексты процедур; если имеются процедуры near, используемые в данной программе, то записываются тексты этих процедур.
Закрытие главной процедуры main, сегмента кодов и выход из программы:
MAIN endp
CODESEG ends
end MAIN
Итак, обобщенная структура программы:
title prog.asm
stackseg segment
; задание поля памяти для стека
stackseg ends
dataseg segment
; задание полей памяти для данных и определение всех констант и переменных
dataseg ends
codeseg segment
assume CS:codeseg, DS:dataseg, SS:stackseg
main proc far
push DX
sub AX, AX
push AX
mov AX, dataseg
mov DS, AX
; основной текст программы
; ...
ret
; тексты ближних процедур
main endp
codeseg ends
end main
Рассмотрим программу расчета сложных процентов.
Капитал Q вкладывается в некоторое мероприятие, обеспечивающее ежегодный прирост капитала D%. Задача: определить текущую величину капитала в течение первых N лет. Вот соответствующая ASM-программа для создания исполняемого EXE-файла.
TITLE |
RASCHET.ASM |
; расчет сложных процентов |
|
||||
STACKSG |
SEGMENT |
STACK 'STACK' |
|
||||
|
DW |
64 DUP(?) |
|
||||
STACKSG |
ENDS |
|
|
||||
DATASG |
SEGMENT |
'DATA' ; задание переменных |
|
||||
VVQ |
DB |
' Введите величину начального капитала (до 64 000)' |
|
||||
|
DB |
10,13,'$' |
|
||||
|
DB |
10,13,'Введите процент годового прироста' |
|
||||
|
DB |
10,13,'$' |
|
||||
VVN |
DB |
10,13,'Введите количество расчетных лет' |
|
||||
|
DB |
10,13,'$' |
|
||||
Q0 |
DW |
? |
|
||||
D |
DW |
? |
|
||||
D1 |
DW |
? |
|
||||
N |
DW |
? |
|
||||
I |
DW |
1 |
|
||||
Q |
DW |
? |
|
||||
BUF |
DB |
5, 0, 0, 0, 0, 0, 0, 0 |
|
||||
VIV1 |
DB |
' год капитал' |
|
||||
|
DB |
10,13,'$' |
|
||||
SRB |
DB |
14 DUP(0), '$' |
|
||||
SR |
DB |
6 DUP(0), '$' |
|
||||
SRK |
DB |
10, 13, '$' |
|
||||
FT10 |
DW |
1 |
|
||||
TEN |
DW |
10 |
|
||||
STO |
DW |
100 |
|
||||
DATASG |
ENDS |
|
|
||||
CODESG |
SEGMENT |
'CODE' |
|
||||
MAIN |
PROC |
FAR |
|
||||
|
ASSUME |
CS:CODESG, DS:DATASG, SS:STACKSG |
|
||||
|
PUSH |
DS |
|
||||
|
SUB |
AX, AX |
|
||||
|
PUSH |
AX |
|
||||
|
MOV |
AX, DATASG |
|
||||
|
MOV |
DS, AX |
|
||||
|
MOV |
AH, 9 ; запрос на ввод Q |
|
||||
|
MOV |
DX, offset VVQ |
|
||||
|
INT |
21H |
|
||||
|
MOV |
AH, 0Ah ; ввод Q |
|
||||
|
MOV |
DX, offset BUF |
|
||||
|
INT |
21H |
|
||||
|
CALL |
STR2BIN |
|
||||
|
MOV |
Q0, DI |
|
||||
|
MOV |
AH, 9 ; запрос на ввод D |
|
||||
|
|
MOV |
DX, offset VVD |
||||
|
|
INT |
21H |
||||
|
|
MOV |
AH, 0AH ; ввод D |
||||
|
|
MOV |
DX, offset BUF |
||||
|
|
INT |
21H |
||||
|
|
CALL |
STR2BIN |
||||
|
|
MOV |
D, DI |
||||
|
|
MOV |
AH, 9 ; запрос на ввод N |
||||
|
|
MOV |
DX, offset VVN |
||||
|
|
INT |
21H |
||||
|
|
MOV |
AH, 0AH ; ввод N |
||||
|
|
MOV |
DX, offset BUF |
||||
|
|
INT |
21H |
||||
|
|
CALL |
STR2BIN |
||||
|
|
MOV |
N, DI |
||||
|
|
MOV |
AX, D |
||||
|
|
MOV |
D1, AX |
||||
|
|
ADD |
D1, 100 ; расчет D1 = (1 + D/100) * 100 |
||||
|
|
MOV |
AX, Q0 ; присвоение Q = Q0 |
||||
|
|
MOV |
Q, AX |
||||
|
|
MOV |
AH, 9 |
||||
|
|
MOV |
DX, offset VIV1 |
||||
|
|
INT |
21H |
||||
|
RST: |
MOV |
AX, Q ; расчет Q = Q * D1 |
||||
|
|
MUL |
D1 |
|
|||
|
|
DIV |
STO |
|
|||
|
|
MOV |
Q, AX |
|
|||
|
|
MOV |
AX, I |
|
|||
|
|
CALL |
BIN2STR |
|
|||
|
|
MOV |
AH, 9 ; вывод года |
|
|||
|
|
MOV |
DX, offset SR |
|
|||
|
|
INT |
21H |
|
|||
|
|
MOV |
AH, 9 ; вывод пробела |
|
|||
|
|
MOV |
DX, offset SRB |
|
|||
|
|
INT |
21H |
|
|||
|
|
MOV |
AX, Q ; вывод прибыли |
|
|||
|
|
CALL |
BIN2STR |
|
|||
|
|
MOV |
AH, 9 |
|
|||
|
|
MOV |
DX, offset SR |
|
|||
|
|
INT |
21H |
|
|||
|
|
MOV |
AH, 9 ; перевод строки |
|
|||
|
|
MOV |
DX, offset SRK |
|
|||
|
|
INT |
21H |
|
|||
|
|
INC |
I ; I = I + 1 |
|
|||
|
|
MOV |
AX, I ; сравнение I с N |
|
|||
|
|
CMP |
AX, N |
|
|||
|
|
JLE |
RST ; условный переход по I <= N |
|
|||
|
|
RET |
|
|
|||
|
BIN2STR |
PROC |
NEAR |
|
|||
|
|
MOV |
SI, offset SR+5 ; процедура перевода двоичного |
|
|||
|
PR2: |
SUB |
DX, DX ; кода в код ASCII с предварительным |
|
|||
|
|
MOV |
[SI], DL ; обнулением поля SR |
|
|||
|
|
DEC |
SI |
|
|||
|
|
CMP |
SI, offset SR |
|
|||
|
|
JA |
PR2 |
|
|||
|
|
MOV |
CX, 10 |
|
|||
|
|
MOV |
SI, offset SR+5 |
|
|||
|
PR1: |
XOR |
DX, DX |
|
|||
|
|
DIV |
CX |
|
|||
|
|
OR |
DL, 30H |
|
|||
|
|
MOV |
[SI], DL |
|
|||
|
|
DEC |
SI |
|
|||
|
|
CMP |
AX,0 |
|
|||
|
|
JNE |
PR1 |
|
|||
|
|
RET |
|
|
|||
|
BIN2STR |
ENDP |
|
|
|||
|
STR2BIN |
PROC |
NEAR ; процедура перевода ASCII-кодов |
|
|||
|
|
MOV |
FT10, 1 ; в двоичный код |
|
|||
|
|
XOR |
DI, DI |
|
|||
|
|
MOV |
CX, 10 |
|
|||
|
|
LEA |
SI, BUF + 1 |
|
|||
|
|
XOR |
BH, BH |
|
|||
|
|
MOV |
BL, [BUF + 1] |
|
|||
|
PR3: |
MOV |
AL, [SI+BX] |
|
|||
|
|
AND |
AX, 0FH |
|
|||
|
|
MUL |
FT10 |
|
|||
|
|
ADD |
DI, AX |
|
|||
|
|
MOV |
AX, FT10 |
|
|||
|
|
MUL |
TEN |
|
|||
|
|
MOV |
FT10, AX |
|
|||
|
|
DEC |
BX |
|
|||
|
|
JNZ |
PR3 |
|
|||
|
|
RET |
|
|
|||
|
STR2BIN |
ENDP |
|
|
|||
|
MAIN |
ENDP |
|
|
|||
|
CODESG |
ENDS |
|
|
|||
|
|
END |
MAIN |
|
В качестве иллюстративного примера для сравнения сложности программ на языке ассемблера с программами на языке высокого уровня, ниже приводится без пояснений программа решения этой задачи на языке Basic:
10 print “Расчет сложных процентов“
20 input “Введите Q, D, N“, Q, D, N
30 D1 = 1 + D/100
40 I = 1
50 Q = Q * D1
60 print I, Q
70 I = I + 1
80 if I <= N then goto 50
90 end