Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции / Gl11.doc
Скачиваний:
25
Добавлен:
20.05.2014
Размер:
97.28 Кб
Скачать

14

11.1. Переменные и константы времени ассемблирования.

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

Вот простой пример. Нам нужно задать четыре массива слов, заполненных нулями. Размер первого массива равен N, размер второго —N+ 2, размер третьего — 2N– 1, четвертого — остаток от деленияNна 3. Решение приN= 5:

.DATA

m1 DW 5 DUP(0)

m2 DW 7 DUP(0)

m3 DW 9 DUP(0)

m4 DW 2 DUP(0)

Если возникнет необходимость изменить число N, то размеры массивов придется заново вычислять вручную. Хотелось бы в программе задавать числоN, а размеры массивов вычислять автоматически. Решение:

.DATA

N = 5

m1 DW N DUP(0)

m2 DW N+2 DUP(0)

m3 DW 2*N-1 DUP(0)

m4 DW N MOD 3 DUP(0)

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

.DATA

N1 = 5

N2 = N1+2

N3 = 2*N1-1

N4 = N1 MOD 3

m1 DW N1 DUP(0)

m2 DW N2 DUP(0)

m3 DW N3 DUP(0)

m4 DW N4 DUP(0)

Переменные времени ассемблирования являются 16-разрядными. Такие переменные могут участвовать в арифметических выражениях. Возможны следующие операции: + (сложение), – (вычитание), * (умножение), / (деление нацело), MOD (взятие остатка по модулю).

Константы задаются с помощью директивы EQU. Например, часто используемому сочетанию символов0Dh,0Ah,'$'можно дать имя, которое Ассемблер будет заменять его определением.

CRLFT EQU 0Dh,0Ah,'$'

Далее в программе изменять это определение нельзя.

11.2. Счетчик адреса.

Когда начинается новая программная секция, специальная встроенная переменная Ассемблера — счетчик адреса — сбрасывается в нуль. По мере выделения новых участков памяти для переменных или команд счетчик адреса увеличивается. Посмотрим это на примере. Вот часть листинга небольшой программы.

1 0000 .Model small

2 0000 .STACK 100h

3 0000 .DATA

4 0000 01 02 a DB 1,2

5 0002 0003 0004 0005 b DW 3,4,5

6 0008 48 65 6C 6C 6F 24 c DB 'Hello$'

7 000E 0000000C d DD 12

8 0012 .CODE

9 0000 B8 0000s s: mov ax,@data

10 0003 8E D8 mov ds,ax

11 0005 8B 1E 0006r mov bx,b+4

12 0009 B8 4C00 mov ax,4C00h

13 000C CD 21 int 21h

14 END s

Во второй колонке — значение счетчика адреса. Проследите его изменение в зависимости от количества и типа данных (в секции .DATA) и в зависимости от размера команд (секция .CODE). Величинаb+4 вычисляется на этапе трансляции (мы видим слева 0006r).

А вот что мы увидим в отладчике.

-CPU Pentium-----------------------ds:0006 = 0005

cs:0000 B83919 mov ax,1939

cs:0003 8ED8 mov ds,ax

cs:0005►8B1E0600 mov bx,[0006]

cs:0009 B8004C mov ax,4C00

cs:000C CD21 int 21

Справа вверху в панели кода отображается адрес и содержимое ячейки, на которую ссылается текущая команда (команда, адрес которой в IP).

Счетчик адреса имеет символическое имя $ и это имя можно использовать в программе.

Перепишем программу из главы 6. Код, который не претерпел изменений, обозначим многоточием.

файл a4v0.asm

.MODEL small

.STACK 100h

.DATA

A DB 2,1,2, 13 DUP(1)

DimA = $ - A

B DB DimA DUP(0)

C DW DimA DUP(-1)

.CODE

start: mov ax, @data

mov ds,ax

mov si,OFFSET A

mov di,OFFSET B

mov bx,OFFSET C

sub dx,dx

mov cx,DimA

n: mov al,[si]

. . .

loop n

mov ax,4C00h

int 21h

END start

Поясним некоторые решения. В директиве A DB 2,1,2, 13 DUP(1) использована конструкция повторения DUP (DUPlicate — дублировать): тринадцать раз в память будет записана единица. В следующей строке введена переменная времени ассемблирования DimA (в исполняемом файле от нее и следов не останется). Ее значение вычисляется как разность текущего значения счетчика адреса (встроенная переменная $) и адреса массива A. Эта разность в точности равна количеству элементов массива A. В двух нижеследующих директивах переменная DimA используется как коэффициент повторения в DUP. Если мы захотим изменить в программе количество элементов в массиве A, то размер двух других массивов будет изменен автоматически. Также автоматически изменится непосредственный операнд в команде mov cx,DimA. В строке mov bx,OFFSET C на этапе ассемблирования вычисляется начальный адрес массива C, который ранее мы скрупулезно вычисляли вручную.

Запуск программы по-прежнему надо осуществлять под управлением отладчика, так как в программе не предусмотрен вывод результатов. Трансляция, компоновка и запуск на выполнение осуществляются командами:

с:\tasm\bin\tasm /zi/la/m a4v0

с:\tasm\bin\tlink /v a4v0

pause

с:\tasm\bin\td a4v0.exe

Изучите листинг этой программы.

11.3. Директивы повторения

Таких директив три: REPT, IRP, IRPC. Сначала изучим директиву REPT.

REPT количество_повторений

блок

ENDM

Пример. Сгенерировать 12 первых нечетных положительных чисел (разместить в байтовом массиве). В программе поместить вALпятый элемент массива.

.MODEL small

.STACK 100h

.DATA

odd_num LABEL byte

I = -1

REPT 12

I = I + 2

DB I

ENDM

.CODE

s: mov ax,@data

mov ds,ax

mov al, odd_num + 5 * TYPE odd_num

exit

END s

Таким образом таблица с нечетными числами будет создана на этапе ассемблирования.

Для того чтобы в программе можно было обращаться к области памяти, содержащей таблицу, в секции данных введена метка odd_numс помощью директивыLABEL. В директиве указан тип помеченных данных — байт. В секции кода в регистрALзагружается пятый элемент таблицы (нумерация, как и в языке Си, идет с нуля). Функция времени ассемблированияTYPEвозвращает количество байтов, отводимое под один элемент данных. Для байтов возвращается 1, для слов — 2, для двойных слов 4 и т.д. Поэтому, если мы заменим в секции данных типBYTEна типWORD(и директивыDB— наDW), то в секции кода нужно только заменитьALнаAX.

Упражнение. Изучите листинг программы. Выполните ее по шагам в TD.

Пример. Сгенерировать на этапе ассемблирования строку "abcde…xyz".

.MODEL small

.STACK 100h

.DATA

abc LABEL byte

L = 'a'

REPT 26

DB L

L = L + 1

ENDM

.CODE

s:

END s

В отладчике перейдите в панель кода и после Ctrl+Gвведите имяabc. Вы увидите расположенные в памяти буквы алфавита.

Задача. Сгенерировать на этапе ассемблирования строку "abcde…xyzAB…YZ". Вывести ее на экран посредством функции 09hпрерывания 21h.

Задача. Сгенерировать на этапе ассемблирования 12 первых чисел ряда Фибоначчи. Разместить их в словах.

11.4. Условное ассемблирование

В языке Ассемблера имеется возможность генерировать те или иные команды в зависимости от выполнения некоторых условий. Мы уже видели условный оператор IFNB, использованный при написании макрокоманды exit.

В языке Ассемблера есть несколько разновидностей условных операторов. Наиболее общим является следующий

IF условие

условный блок

ELSE

альтернативный условный блок

ENDIF

Ветвь ELSE и альтернативный условный блок могут отсутствовать. Если нужно большее количество условных блоков, то ELSE заменяется на

ELSEIF условие

В условии можно использовать выражения и операторы сравнения: EQ (равно), NE (не равно), LT (меньше), LE (меньше или равно), GT (больше), GE (больше или равно). Из результатов сравнения можно образовывать логические выражения с помощью операторов: NOT,AND,OR, XOR.

Пример. Генерировать таблицу: из первых 40 нечетных чисел поместить в таблицу только те, которые делятся на 3, но не делятся на 5. Приведем фрагмент программы

I = -1

REPT 40

I = I + 2

IF I MOD 3 EQ 0 AND I MOD 5 NE 0

DB I

ENDIF

ENDM

Если бы задача была сформулирована чуть иначе: генерировать таблицу первых 40 нечетных чисел, которые делятся на 3, но не делятся на 5. Тогда пришлось бы воспользоваться оператором

WHILEвыражение

блок

ENDM

Блок повторяется, пока выражениене станет равным нулю. Решение:

I = -1

K = 40

WHILE K

I = I + 2

IF I MOD 3 EQ 0 AND I MOD 5 NE 0

DB I

K = K - 1

ENDIF

ENDM

Упраженение. Почему для этой программы при трансляции выдаются сообщения об ошибках? Какое можно предложить исправление?

IRP— блок повторений с переменным числом параметров (IndefiniteRepeatBlock). Его формат:

IRP param, <value1, value2,…>

блок

ENDM

На первом шаге генерируется блок, в котором вместо paramподставляется значениеvalue1, затем блок, в котором вместоparamподставляетсяvalue2, и т.д. до исчерпания списка. Элементы списка значений могут быть числами, символами, строками.

Пример. Создать массив слов, содержащих квадраты первых десяти простых чисел.

IRP V,<1,2,3,5,7,11,13,17,19,23>

DW V*V

ENDM

(Можно было, конечно, и вручную такую таблицу рассчитать, но пусть лучше Ассемблер трудится.)

Пример. Поместить в стек регистры AX,BX,CX,DX.

IRP reg, <ax, bx, cx, dx>

push reg

ENDM

Будут сгенерированы команды

push ax

push bx

push cx

push dx

Такая конструкция полезна для MASM. ВTASMможно написать

push ax bx cx dx (имена регистров разделены пробелом)

и будет сгенерирована упомянутая последовательность команд. (Аналогичная конструкция имеется для команды pop)

Имеется разновидность IRP: директиваIRPC—IRPofCharacters— блок повторения символов.

Пример. Заполнить массив байтов символами 'p', 'r', 'o', 'g'. Можно для этого воспользоватьсяIRP:

IRP sym, <'p','r','o','g'>

DB sym

ENDM

Но проще так:

Соседние файлы в папке Лекции