Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа №4.pdf
Скачиваний:
12
Добавлен:
12.06.2015
Размер:
371.08 Кб
Скачать

А. В. Карпов

СОЗДАНИЕ И ВЫПОЛНЕНИЕ ПРОСТЫХ ПРОГРАММ НА АССЕМБЛЕРЕ МП i8086 (часть I)

Методические указания к лабораторной работе

Волгоград 2006

УДК 681.325

Создание и выполнение простых программ на Ассемблере МП i8086 (часть I): Методические указания к лабораторной работе/ Сост. А. В. Карпов. -- Волгоград, 2006.-- 17 с.

Приведено описание лабораторной работы “Создание и выполнение простых программ на Ассемблере МП i8086” по курсу “Вычислительные машины, системы и сети”, в которой изучаются директивы языка, элементы и структура простейших программ на Ассемблере МП i8086. Издание предназначено для студентов дневной, вечерней и заочной форм обучения специальности 2102.

© А. В. Карпов, 2006

2

Цель работы

Целью настоящей работы является изучение директив языка, элементов и структуры простейших программ на Ассемблере МП i8086.

1 Элементы и структура программы на языке Ассемблера

Формат строки

Строки исходного кода на языке Ассемблера имеют следующий формат:

<метка> <команда/директива> <операнды> <;комментарий>

где <метка> представляет собой необязательное имя идентификатора, <команда/директива> - это мнемоника команды или директивы, <операнды> - содержат сочетание 0, 1 или 2 (иногда более) констант, ссылок на память или регистры, или текстовых строк, как это требуется в каждой конкретной команде или директиве, <;комментарий> - необязательный комментарий.

В любом месте в строки качестве символа продолжения строки можно поместить символ обратной косой черты (\). Однако данный символ нельзя использовать для разбиения идентификаторов. Обратная косая черта означает: "считать следующую строку, и продолжить обработку с данной точки". При этом можно комментировать каждую строку. Например:

foo mystructure \

; Начать заполнение

структуры

<0,\

; Сначала

-

нулевое

значение

1,\

;

Затем -

единица

 

2>\

;

Структура

завершается значением 2

Метки

Метки - это имена, использующиеся в программе для ссылки на числа и строки символов или ячейки памяти.

Метки позволяют присваивать имена переменным в памяти, значениям и адресам, где находятся конкретные инструкции. Например:

dseg SEGMENT ‘DATA’ FactorialValue DW ? Factorial DW ?

dseg ENDS

cseg SEGMENT ‘CODE’

ASSUME CS: cseg, DS: dseg FiveFactorial PROC

start:

MOV AX, dseg MOV DS, AX

MOV [FactorialValue], 1

3

MOV [Factorial], 2 MOV CX, 4

FiveFactorialLoop:

MOV AX, [FactorialValue] MUL [Factorial]

MOV [FactorialValue], AX INC [Factorial]

LOOP FiveFactorialLoop FiveFactorial ENDP

END

Метки FactorialValue и Factorial эквивалентны адресам двух 16-битовых переменных. Они используются для последующей ссылки в программе на эти две переменные. Метка FiveFactorial - это имя подпрограммы (процедуры или функции), содержащей код. Она позволяет вызывать этот код в других частях программы. Метки start и FiveFactorialLoop есть адреса команд:

MOV AX, dseg

и

MOV AX, [FactorialValue]

соответственно.

 

 

 

 

 

Метки могут состоять из следующих символов:

?

0 – 9.

A – Z

a – z

_

@

$

Цифры 0 - 9 не могут использоваться в качестве первых символов метки. Символы $ и ? имеют специальное значение, поэтому их не следует использовать в именах идентификаторах.

Каждая метка должна определяться только один раз, то есть метки должны быть уникальными. Как операнды метки могут использоваться любое число раз.

Метка может занимать всю строку, то есть на этой строке кроме метки может отсутствовать команда или директива. В этом случае значением метки является адрес команды или директивы на следующей строке программы. Например:

JMP DoAddition

...

DoAddition:

ADD AX, DX

следующей инструкцией, выполняемой после инструкции JMP, которая выполняет переход на метку DoAddition, является команда ADD AX, DX. Предыдущий пример эквивалентен следующему:

JMP DoAddition

...

DoAddition: ADD AX, DX

Метка не может совпадать с любым из зарезервированных слов Ассемблера.

4

Определения меток в коде программы (и содержащиеся на отдельной строке, и после которых на той же строке следуют директивы или инструкции) должны заканчиваться двоеточием (:). Двоеточие просто завершает метку и не является ее частью. Например, в следующем фрагменте программы:

LoopTop: mov al,[si] inc si

and al,al jz Done

jmp LoopTop Done: ret

метки LoopTop и Done определены с двоеточиями, но в ссылках на эти метки двоеточия не указываются.

Другие метки в общем случае не должны завершаться двоеточием. В примере программы в начале данной лабораторной работы содержатся несколько меток без двоеточий.

Мнемоники команд и директивы

Основным полем в строке программы на Ассемблере является поле <команда/директива>. Это поле может содержать мнемонику команды или директиву.

Команды непосредственно выполняются процессором i8086. Ассемблер компилирует каждую мнемонику команды непосредственно в соответствующую команду на машинном языке.

В отличие от мнемоник команд, директивы не генерируют выполняемого кода. Вместо этого они управляют различными аспектами работы Ассемблера - от типа ассемблируемого кода до используемых сегментов и формата создаваемых файлов листингов и т. д.

Директивы Ассемблера

Директива SEGMENT используется для того, чтобы начать сегмент. Каждой директиве SEGMENT должна соответствовать директива ENDS, завершающая сегмент.

Полная форма директивы SEGMENT имеет следующий вид:

имя SEGMENT выравнивание комбинирование использование 'класс'

где поля "выравнивание", "комбинирование", "использование" и "класс" необязательны1.

Поле "имя" задает имя сегмента. Имена сегментов являются метками, поэтому в своих исходных модулях они должны быть уникальны. При завершении сегмента то же имя должно использоваться в директиве ENDS. Пример:

1 См. Приложение 1.

5

cseg SEGMENT

...

cseg ENDS

Сегменты могут быть вложенными, что означает, что можно определить сегмент до того, как закончится предыдущий сегмент, например:

DataSeg SEGMENT PARA PUBLIC 'DATA'

...

DataSeg2 SEGMENT PARA PRIVATE 'FAR_DATA'

...

DataSeg2 ENDS

...

DataSeg ENDS

Директива ENDS определяет конец сегмента. Например: cseg ENDS

завершает сегмент с именем cseg, который начинался по директиве SEGMENT. При использовании стандартных директив определения сегментов необходимо явным образом завершать каждый сегмент.

Директива ASSUME позволяет сообщить Ассемблеру, на какой сегмент или группу указывает данный сегментный регистр. Это не то же самое, что действительная загрузка сегментного регистра для ссылки на данный сегмент (это необходимо делать отдельно с помощью инструкции MOV). Назначение директивы ASSUME состоит в том, чтобы дать Ассемблеру возможность проверить допустимость ссылок на память и при обращении к памяти автоматически включить префиксы переопределения сегментов (если это требуется).

Директива ASSUME для регистра CS должна следовать перед любым кодом в каждом исходном модуле. Благодаря этому Ассемблер знает, в каком сегменте подразумевается размещение инструкций1.

Пример директивы ASSUME:

DataSeg SEGMENT PARA PUBLIC 'DATA'

...

DataSeg ENDS

CodeSeg SEGMENT PARA PUBLIC 'CODE' ASSUME CS:CodeSeg,DS:DataSeg

...

CodeSeg ENDS

Директива END. Каждая программа должна содержать директиву END, отмечающую конец исходного кода программы. Все строки, которые следуют за директивой END, Ассемблером игнорируются. Если

1 По мере необходимости в любой исходный модуль могут включаться другие

директивы ASSUME (с указанием различных сегментных регистров).

Подразумеваемый сегмент для любого сегментного регистра может быть изменен, когда это необходимо. В одной директиве ASSUME можно изменить любой или все

сегментные регистры.

6

опустить директиву END, то генерируется ошибка, поэтому необходимо всегда указывать директиву END.

Например:

sseg SEGMENT ‘STACK’ DB 200h DUP (?)

sseg ENDS

dseg SEGMENT ‘DATA’

...

dseg ENDS

cseg SEGMENT ‘CODE’

ASSUME CS: cseg, DS: dseg, SS: sseg start:

MOV AX, dseg MOV DS, AX MOV AH, 4ch INT 21h

cseg ENDS END start

Это простейшая программа на Ассемблере. Она ничего не делает, просто немедленно возвращает управление DOS.

На одной строке с директивой END содержится метка start. Кроме завершения программы, директива END может выполнять еще и вторую функцию, указывая, где должно начинаться выполнение при запуске программы. Иногда требуется начать выполнение программы в файле

.EXE не с первой команды. Директива END предусматривает такие случаи. Пример:

sseg SEGMENT ‘STACK’ DB 200h DUP (?)

sseg ENDS

dseg SEGMENT ‘DATA’

...

dseg ENDS

cseg SEGMENT ‘CODE’

ASSUME CS: cseg, DS: dseg, SS: sseg Delay:

MOV CX, 40 DelayLoop:

LOOP DelayLoop RET

start:

MOV AX, dseg MOV DS, AX CALL Delay MOV AH, 4ch INT 21h

7