Главная Обратная связь

Дисциплины:






Оформление программ в виде отдельных модулей



Язык АССЕМБЛЕРА и программирования

Глава 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 = цвет символа (в графических режимах).

 

Директива MACRO

Эта директива используется для создания макрокоманд. Формат директивы:

имя MACRO список_параметров

операторы

ENDM

Список_параметров представляет перечень фиктивных аргументов макроса и имеет следующий синтаксис:

[фикт_арг1[, фикт_арг2..]]

Каждый фиктивный аргумент имеет следующий синтаксис:

имя_фикт_аргум[: тип_фикт_аргум]

 

 

; Программа hello3_m.asm состоит из вызывающей программы и макроса ;WriteMsg. В WriteMsg используются функции BIOS.

WriteMsg MACRO

mov di,OFFSET Hello

mov ah,0eh

mov bh,0

Next: mov al,[di]

cmp al,’$’

je Quit

int 10h

inc di

jmp Next

Quit: ret

ENDM

 

AStack SEGMENT STACK

DW 12 DUP(?)

AStack ENDS

 

AData SEGMENT

Hello DB ‘Здравствуйте!$’

AData ENDS

 

ACode SEGMENT

ASSUME CS: ACode,DS: AData,SS: AStack

Main PROC FAR

push ds

sub ax,ax

push ax ;адрес начала PSP

mov ax,AData

mov ds,ax

WriteMsg

ret

Main ENDP

ACode ENDS

END Main

 

Рис 1.4. Программа содержит макрокоманду WriteMsg.

 

Еще один полезный пример программы, преобразующей строку цифр в коде ASCII в двоичный формат и наоборот(Рис 1.5.).

 

;Преобразование ASCII и двоичных форматов

TITLE EXCONV (EXE)

;--------------------------------------------------------

stacksg SEGMENT PARA STACK ‘Stack’

dw 32 dup(?)

stacksg ends

;--------------------------------------------------------

datasg SEGMENT PARA ‘Data’

ascval db ‘12345’

binval dw 0

asclen db 5

mult10 dw 1

asvout db 5 dup(0)

datasg ends

;----------------------------------------------------------

codesg SEGMENT PARA ‘Code’

begin PROC FAR

ASSUME cs:codesg,ds:datasg,ss:stacksg

push ds

sub ax,ax

push ax

mov ax,datasg

mov ds,ax

;---------------------------------------------------------

call b10asbi ;вызов преобразования ASCII

call c10bias ;вызов двоичного преобразования

ret

begin endp

;----------------------------------------------------------

; Преобразование ASCII в двоичное

;----------------------------------------------------------

b10asbi PROC

mov cx,10 ; фактор умножения

lea si,ascval-1 ; адрес ascval

xor bx,bx

mov bl,asclen ; длина ascval

b20:

mov al,[si+bx] ; выбрать ASCII- символ

and ax,000fh ; очистить зону тройки

mul mult10 ; умножить на фактор 10

add binval,ax ; прибавить к двоичному

mov ax,mult10 ; вычислить следующий

mul cx ; фактор умножения

mov mult10,ax

; mov mult10,al

dec bl ; последний ASCII символ?

jnz b20 ; нет­ продолжать

ret

b10asbi endp

;-----------------------------------------------------------

; Преобразование двоичного в ASCII

;-----------------------------------------------------------

c10bias proc

mov cx,10 ; фактор деления

lea si,asvout+4

mov ax,binval ; загрузить двоичное число

c20:

cmp ax,0010 ; значение меньше 10?

jb c30 ; да- выйти

xor dx,dx ; очистить часть частного

div cx ; разделить на 10

or dl,30h

mov [si],dl ; записать ASCII символ

dec si

jmp c20

c30:

or al,30h ; записать полученное частное

mov [si],al ; как ASCII- символ

ret

c10bias endp

codesg ENDS

end begin

Рис. 1.5. Преобразование форматов.

 

Оформление программ в виде отдельных модулей

В этом случае программа собирается в виде отдельных модулей. Признаком программного модуля является директива END [имя_модуля]. Она располагается в конце модуля. При этом только головной модуль имеет в директиве END имя.

На Рис. 1.6. приведена программа, состоящая из двух модулей CALLMUL1 и SUBMUL. Модуль CALLMUL1 является головным и вызывает модуль SUBMUL. Все вызываемые модули в вызывающем должны быть описаны с помощью директивы EXTRN. Головной модуль должен обеспечить возврат в MS-DOS. Все модули транслируются независимо и объединяются в единый проект на этапе компоновки. Вызываемые модули могут предварительно помещаться в библиотеку.

TITLE CALLMUL1 (EXE)

EXTRN SUBMUL: FAR

;======================================================

STACKSG SEGMENT PARA STACK ‘Stack’

dw 64 dup(?)

STACKSG ENDS

;======================================================

DATASG SEGMENT PARA ‘Data’

QTY dw 0140h

PRICE dw 2500h

REZ dd ?

DATASG ENDS

;======================================================

CODESG SEGMENT para ‘Code’

BEGIN PROC FAR

ASSUME cs:codesg,ds:datasg,ss:stacksg

push ds

sub ax,ax

push ax

mov ax,datasg

mov ds,ax

mov ax,price ;загрузить стоимость

mov bx,qty ;и количество

call submul ;вызвать подпрограмму

mov WORD ptr REZ,ax ; результат умножения

mov WORD ptr REZ+2,dx

ret

BEGIN ENDP

CODESG ENDS

END BEGIN

 

 

TITLE SUBMUL Подпрограмма для умножения

;=====================================================

CODESG SEGMENT PARA ‘Code’

SUBMUL PROC FAR

ASSUME cs:codesg

PUBLIC submul

mul bx ;ax-стоимость

;bx-количество

;произведение в dx:ax

ret

SUBMUL ENDP

CODESG ENDS

END

Рис. 1.6.





sdamzavas.net - 2020 год. Все права принадлежат их авторам! В случае нарушение авторского права, обращайтесь по форме обратной связи...