
- •Язык ассемблера и программирования Глава 1. Директивы языка ассемблера Директива segment
- •Директива group
- •Директива assume
- •Assume сегментный_регистр : имя [, ...]
- •Директива Proc
- •Директива macro
- •Оформление программ в виде отдельных модулей
- •Передача параметров в подпрограмму
- •Описание
- •Директивы упрощенного описания сегментов Директива model
- •Вызов процедур с использованием кадра стека
- •Глава 2. Вывод информации на терминал в текстовом режиме Вывод символьной строки. Модуль puts.
Язык ассемблера и программирования Глава 1. Директивы языка ассемблера Директива segment
Формат директивы:
имя_сегмента SEGMENT [выравнивание] [объединение] [класс]
.
.
.
имя_сегмента ENDS
Операнд выравнивания определяет начальную границу сегмента.
PARA (по умолчанию)-сегмент начинается на границе параграфа.
BYTE-сегмент может начинаться в произвольном месте.
WORD-сегмент начинается на границе слова.
Объединение указывает способ обработки сегмента при компоновке.
NONE: Значение по умолчанию. Сегмент должен быть логически отделен от других сегментов. Предполагается, что сегмент имеет собственный базовый адрес.
PUBLIC: Все PUBLIC-сегменты, имеющие одинаковое имя и класс, загружаются компоновщиком в смежные области. Все такие сегменты имеют один общий базовый адрес.
STACK: В любой компонуемой программе должен быть определен по крайней мере один сегмент STACK. Если объявлено более одного стека, то стековый указатель SP устанавливается на начало первого стека.
AT-параграф: Параграф должен быть определен предварительно.
‘Класс’: Операнд ‘класс’ может содержать любое правильное имя, заключенное в одиночные кавычки. Данный операнд используется компоновщиком для обработки сегментов, имеющих одинаковые имена и классы.
Директива group
Назначение этой директивы- собрать однотипные сегменты под одно имя так, чтобы они поместились в один сегмент объемом 64 Кбайт. Формат директивы:
имя GROUP имя сегмента [, ......]
Директива assume
Назначение директивы ASSUME- установить для ассемблера связь между сегментами и сегментными регистрами CS, DS, ES и SS. Формат директивы:
Assume сегментный_регистр : имя [, ...]
;Программа hello1.asm без подпрограмм
;Данные программы
DATA SEGMENT
HELLO DB ‘ Здравствуйте!$’
DATA ENDS
; Код программы
CODE SEGMENT
ASSUME CS:CODE,DS:DATA
START: mov ax,DATA
mov ds,ax
mov ah,9
mov dx,OFFSET HELLO
int 21h
mov ah,4ch ;выход из программы
int 21h
CODE ENDS
END START
Рис.1.1 В этом примере приведен пример оформления программы.
Сегмент STACK не определен, поэтому компилятор выдаст предупреждение. В этом случае SS указывает на сегмент данных, а SP=0ffh.
Директива Proc
Эта директива служит для определения процедур. Формат процедуры:
Proc имя [[модификатор_языка] язык] [тип]
[ARG аргументы] [RETURNS список]
[LOCAL аргументы]
[USES список]
.
.
.
[имя] ENDP
Тип процедуры может быть NEAR или FAR. Процедура, находящая в одном сегменте с вызывающей процедурой, имеет тип NEAR. Если операнд опущен, то ассемблер принимает значение NEAR. Если процедура является внешней по отношению к вызывающему сегменту, то процедура должна быть объявлена как PUBLIC.
PUBLIC имя_процедуры
имя_процедуры PROC FAR
; Программа hello2.asm состоит из вызывающей и вызываемой подпрограммы
AStack SEGMENT STACK
DW 12 DUP(?)
AStack ENDS
AData SEGMENT
Hello DB ‘Здравствуйте!$’
AData ENDS
ACode SEGMENT
ASSUME CS: ACode,DS: AData,SS: AStack
WriteMsg PROC NEAR
mov ah,9
int 21h
ret
WriteMsg ENDP
Main PROC FAR
COMMENT !
Формирование и запись в стек адреса PSP, в первых двух байтах которого хранится код завершения программы int 20h. В этом случае выход в MS-DOS может осуществляться по инструкции ret. При загрузке программы в регистре DS хранится адрес PSP программы.
!
push ds
sub ax,ax
push ax ; адрес начала PSP
mov ax,AData
mov ds,ax
mov dx,OFFSET Hello
call WriteMsg
ret
Main ENDP
ACode ENDS
END Main
Рис. 1.2. Процедура Main вызывает процедуру WriteMsg.
Здесь используется ближний вызов, так как эти две процедуры находятся в одном сегменте. Следует иметь в виду, что программный модуль заканчивается директивой END [имя_точки_входа_в_модуль].
Если проект содержит насколько модулей то имя_точки_входа_в_модуль должно быть определено только в одном главном модуле.
; Программа hello3.asm состоит из вызывающей и вызываемой подпрограммы.
; В WriteMsg используются функции BIOS.
AStack SEGMENT STACK
DW 12 DUP(?)
AStack ENDS
AData SEGMENT
Hello DB ‘Здравствуйте! $’
AData ENDS
ACode SEGMENT
ASSUME CS: ACode,DS: AData,SS: AStack
WriteMsg PROC NEAR
mov bx,dx
mov ah,0eh
mov bh,0
Next: mov al,[bx]
cmp al,’$’
je Quit
int 10h
inc bx
jmp Next
Quit: ret
WriteMsg ENDP
Main PROC FAR
push ds
sub ax,ax
push ax ;адрес начала PSP
mov ax,AData
mov ds,ax
mov dx,OFFSET Hello
call WriteMsg
ret
Main ENDP
ACode ENDS
END Main
Рис. 1.3. Программа, использующая средства BIOS для вывода.
В этой программе для вывода информации используется функция 0Eh прерывания 10h. Формат вызова этой функции:
На входе:
ah = 0eh- запись символа в телетайптном режиме;
al = ASCII - код записываемого символа;
bh = номер страницы видеопамяти (только в текстовых режимах);
bl = цвет символа (в графических режимах).