Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Пильщиков

.pdf
Скачиваний:
156
Добавлен:
09.05.2015
Размер:
6.35 Mб
Скачать

30 Программирование на языке ассемблера IBM PC Глава 1

М+1 не следует понимать как сложение содержимого ячейки с именем М ( т. е. числа 2) с числом 1. В Я А запись вида <имя>±к означает, что к адресу указанного имени надо прибавить (или отнять) число к, в результате чего получится некоторый новый адрес, и вот уже по этому адресу и осуществляется доступ к памяти. Таким образом, данная запись означает сложение/вычитание адресов.

Операнд - строка

Возможно еще одно сокращение в директиве DB: если в ней несколько соседних операндов - символы, то их можно объединить в одну строку. Например, следующие две директивы эквивалентны:

S DB ' а ' , ' Ь ' , ' С S DB ' а Ь с '

Отметим, что и в этом случае тип имени равен 1 (TYPE S = BYTE), т. к. любая из этих директив является сокращением следующих трех директив:

sDB ' а ' DB ' Ь '

DB ' с '

а здесь ясно видно, что имя S обозначает только первый байт.

Вопрос о том, объединять соседние символы в одну строку или нет, а если объединять, то какие именно, решает сам автор программы. Например, нашу директиву можно записать и так:

S DB ' a b ' , ' с ' или S DB ' а ' , ' b e '

Операнд - конструкция повторения DUP

Рассмотрим еще одно возможное сокращение в записи директивы DB. Довольно часто в директиве приходится указывать одинаковые операнды. Например, если мы хотим описать байтовый массив R из 8 элементов с начальным значением О для каждого из них, то это можно сделать так:

R DB 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0

Так вот, эту директиву можно записать и короче:

R DB 8 DOP(O)

Здесь в качестве операнда использована так называемая конструкция повторения, в которой сначата указывается коэффициент повторения, затем - служебное слово DUP (duplicate, копировать), а за ним в круглых скобках - повторяемая величина.

В общем случае эта конструкция имеет следующий вид:

k DUP ( р 1 # р 2 , . . . , р п )

где к - константное выражение с положительным значением, п>=1, pj - любой допустимый операнд директивы DB (в частности, это может быть снова кон-

Язык ассемблера. Начальные сведения 32

30

 

струкция повторения). Данная запись является сокращением для к раз повторенной последовательности указанных в скобках операндов:

Например, директивы слева эквивалентны директивам справа:

(Тип имен X и Y - BYTE.)

Отметим, что вложенность конструкций DUP можно использоваться для наглядного описания многомерных массивов. Например, директиву

A DB 20 DUP(30 DUP( 7 ) )

можно рассматривать как описание байтовой матрицы А размера 20x30, в которой элементы расположены в памяти следующим образом: первые 30 байтов - это элементы первой строки матрицы, следующие 30 бантов - это элементы второй строки и т. д.

2 3 2 . Директива DW

Директивой DW (define word, определить слово) описываются переменные размером в слово. Она аналогична директиве DB, поэтому лишь вкратце рассмотрим допустимые виды ее операндов.

Операнд ?

Возможный пример:

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

ТУРЕ А - WORD = 2.

i.:-

Константное выражение со значением от -3276S до 65535

Возможные примеры:

В DW 1234h

С DW - 2

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

"ДИАЛОГ-МИФИ"

32 Программирование на языке ассемблера IBM PC Глава 1

Как и в случае директивы DB, неотрицательные числа записываются в память как числа без знака, а отрицательные числа - в дополнительном коде. Поэтому числа, которые могут быть заданы как операнды директивы DW, должны принадлежать отрезку [-215, 216-1].

Но здесь имеется и отличие от директивы DB. Напомним, что в ПК числа размером в слово хранятся в памяти в "перевернутом" виде. Так вот, па ЯА такие числа записываются в нормачьном, неперевернутом виде, а "переворачиванием" их занимается сам ассемблер, поэтому по нашим двум директивам память заполнится следующим образом:

С учетом этого при программировании на ЯА можно в общем-то забыть о "перевернутом" представлении чисел в памяти ПК.

Частным случаем рассматриваемого вида операнда директивы DW может быть строка из одного или двух символов, например:

s i

DW

' 0 1 '

S2

DW

' 1 '

Если указана строка из двух символов, тогда ассемблер берет коды указанных символов (в нашем случае - 30h (код '0') и 31h (код '1')) и образует из них числослово (303 lh), которое и считается начальным значением описываемой переменной (S1). Но как и любое число размером в слово, данное значение будет записано в память в "перевернутом" виде. Если же в правой части директивы DW указан один символ, тогда к нему слева приписывается символ с кодом 0 и дальнейшие действия ассемблера будут такими же, как и в случае двухсимвольной строки. Поэтому по нашим двум директивам память будет заполнена следующим образом:

В связи с тем, что операнды-строки записываются в память в "перевернутом" виде, что в общем-то не характерно для строк, то подобные операнды редко указываются в директиве DW.

Адресное выражение

Вкачестве операнда директивы DW может быть указано адресное выражение,

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

С DB ? D DW С

Язык ассемблера. Начальные сведения

33

В этом случае ассемблер записывает в слово, выделенное под переменную D, адрес переменной С, который становится начальным значением переменной D.

Несколько операндов, конструкция повторения

В правой части директивы DW можно указать любое число операндов, а также конструкцию повторения. Возможный пример:

Е DW 4 0 0 0 0 , 3 D U P ( ? )

2.3.3.Директива DD

По директиве DD (define double word, определить двойное слово) описываются переменные, под которые отводятся двойные слова. Поэтому имена этих переменных имеют тип 4 или DWORD (значением этой стандартной константы как раз является число 4). В остальном эта директива похожа на две предыдущие.

Допустимые типы операндов этой директивы таковы.

Операнд ?

Пример:

A DD ?

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

Целое число со значение от -2п до 232-1

Пример:

ВDD 123456h

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

Константное выражение (со значением от -2'5 до 2-1)

Обратите внимание на диапазон возможных значений выражения - он в два ра-

за меньше диапазона

чисел, которые можно

записать

в двойном слове. Дело

в том, что в ЯА все

выражения вычисляются

в области

16-битовых чисел, т. е.

результаты всех операций берутся по модулю 216 (lOOOOh). Поэтому построить выражение, значением которого являлось бы 32-битовое или даже 17-битовое число, не удастся. Единственное исключение - это явно задать в директиве DD "большое" число. Если же мы укажем хотя бы одну операцию, то ответ тут же будет взят по модулю 216. Например, по директиве

X DD 8000h+8002h

начальным значением переменной X станет число 2, а не число 10002h.

"ДИАЛОГ-МИФИ"

34 Программирование на языке ассемблера IBM PC Глава 1

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

Адресное выражение

Такой операнд задает абсолютный адрес. Как это делается, будет рассмотрено позже, в гл. 7.

Несколько операндов, конструкция повторения

Возможный пример:

DW 33 DUP(?), 12345h •

2.4.Директивы эквивалентности и присваивания

Мы рассмотрели, как в ЯА описываются переменные. Теперь рассмотрим, как в этом языке описываются константы. Это делается с помощью директивы эквивалентности - директивы EQU (equal, равно), имеющей следующий синтаксис:

<имя> EQU <операнд>

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

Эта директива аналогична описанию константы в языке Паскаль:

c o n s t <имя> " <операнд>;

Директивой EQU автор программы заявляет, что указанному операнду он дает указанное имя, и требует, чтобы все вхождения этого имени в текст программы ассемблер заменял на этот операнд. Например, если есть директива

STAR EQU ' * '

то ассемблер будет рассматривать предложение

т DB STAR

как предложение

т DB ' * '

Другими словами, указать имя STAR и указать '*' - это одно и то же.

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

Теперь рассмотрим, каким может быть операнд директивы EQU и в каких случаях полезна эта директива.

Язык ассемблера. Начальные сведения

35

Операнд - имя

Если в правой части директивы указано имя регистра, переменной, константы и т. п., тогда имя слева объявляется синонимом данного имени и все последующие вхождения в текст программы этого имени-синонима ассемблер

. будет заменять на имя, указанное справа. Например:

. A DW ?

 

В EQU А

 

С DW В

; э к в и в а л е н т н о : С DW А

Имена-синонимы обычно используются для введения более удобных, наглядных обозначений. Например, само по себе имя регистра АХ ни о чем не говорит, но если мы используем этот регистр для вычисления какой-то суммы, то его можно обозначить SUM:

SUM EQU АХ

и далее использовать это более наглядное имя SUM.

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

Операнд - константное выражение

Примеры:

N EQU 100

К EQU 2*N-1 STAR EQU ' * '

Если в правой части директивы EQU стоит константное выражение, тогда указанное слева имя принято называть именем константы. Значением этой константы объяачястся значение выражения. Например, N - это константа со значением 100, К - со значением 199, a STAR - со значением 2Ah (это код звездочки в системе ASCII). Все последующие вхождения в текст программы имени константы ассемблер будет заменять на значение этой константы. Например, директива

X DB N DUP(?)

эквивалентна директиве

X DB 100 DUP(?)

Случаи, когда полезно применение констант, - такие же, как и в языках высокого уровня. Например, в качестве констант рекомендуется описывать размеры массивов, поскольку в таком случае легко настроить программу на работу с массивом другого размера - для этого достаточно внести изменение лишь в директиву EQU, описывающую константу.

Отметим, что если в константном выражении используются имена других констант, то они должны быть описаны раньше данной директивы EQU, иначе

"ДИАЛОГ-МИФИ"

36 Программирование на языке ассемблера IBM PC Глава 1

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

Операнд - любой другой текст

Примеры:

S EQD 'Вы ошиблись'

LX EQD X+(N-1)

WP EQD WORD PTR

В данном случае считается, что указанное имя обозначает операнд в том виде, как он записан (операнд не вычисляется). Именно на этот текст и будет заменяться каждое вхождение данного имени в программу. Например, следующие предложения слева эквивалентны предложениям справа

ANS DB S,

' 1 '

ANS DB

'Вы о ш и б л и с ь ' , ' 1 '

NEG LX

 

NEG

X+(N-1)

INC WP

[ВХ]

INC

WORD PTR [BX]

Такой вариант директивы EQU обычно используется для того, чтобы ввести более короткие обозначения для часто встречающихся длинных текстов. Введя короткое имя, мы далее в программе можем им пользоваться, а уж ассемблер сам будет его заменять на соответствующий текст.

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

Теперь рассмотрим еще одну директиву ЯА, похожую на директиву EQU, - директиву присваивания:

<имя> = <константное выражение>

Эта директива определяет константу с именем, указанным в левой части, и с числовым значением, равным значению выражения справа. Но в отличие от констант, определенных по директиве EQU, данная константа может менять свое значение, обозначая в разных частях текста программы разные числа. Например:

К=10

A DW К ; э к в и в а л е н т н о : A DW 10 К=К+4

В DB К ; э к в и в а л е н т н о : В DB 14

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

Язык ассемблера. Начальные сведения

37

(другими словами, поменять значение константы с таким именем). Однако главное применение таких констант - в макросредствах (см. гл. 11).

Теперь кое-что уточним.

Если с помощью директивы EQU можно определить имя, обозначающее не только число, но и другие конструкции, то по директиве присваивания можно определить только числовую константу. Кроме того, если имя указано в левой части директивы EQU, то оно не может появляться в левой части других директив (его нельзя переопределять). А вот имя, появившееся в левой части директивы присваивания, может снова появиться в начале другой такой директивы (но только такой!). Поэтому ошибочными являются все следующие три фрагмента программы:

К

EQD

1

К EQO 1

К>1

К

EQO

2

К=2

К EQD 2

Появление в языке констант, которые могут менять свои значения, вносит некоторую неопределенность. Рассмотрим, к примеру, фрагмент слева:

к-1

 

к-1

 

N EQU К

 

N

EQO К+10

A DW N

;А=1

С

DW N

; С - 1 1

К=2

 

К - 2

 

В DW N

;B=2

D

DW N

; D - 1 1

Какие начальные значения получат переменные А и В? Относительно значения переменной А сомнений нет - это 1. Но вот значением переменной В, оказывается, будет число 2, а не 1. Почему? Дело в том, что имя N объявлено синонимом имени К, поэтому все вхождения имени N ассемблер будет заменять на имя К. Значит, директива В DW N понимается как директива В DW К. Но в этом месте текста программы константа К имеет значение 2, поэтому данная директива воспринимается как В DW 2.

В то же время в примере справа переменные С и D получат одно и то же значение 11. Дело в том, что в директиве EQU указано, так сказать, настоящее константное выражение, и потому ассемблер вычисляет его сразу. Значение 11 этого выражения объявляется значением константы N, которая далее и будет обозначать это число.

Таким образом, необходимо внести следующее уточнение в действие директивы EQU: если в правой части директивы указано имя константы, то имя слева надо понимать не как имя константы (не как имя числа), а как синоним имени справа; если же в правой части указано любое другое константное выражение, тогда имя слева действительно становится именем константы (обозначением числа). Что же касается директивы присваивания, то ее правая часть всегда вычисляется сразу и полученное число тут же становится новым значением константы.

"ДИАЛОГ-МИФИ"

38 Программирование на языке ассемблера IBM PC Глава 1

2.5.Выражения

Операнды директив, как правило, описываются в виде выраженийВыражения используются и для описания операндов команд.

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

Вообще говоря, в ЯА для записи операндов директив и команд достаточно только чисел и имен. Более сложные выражения являются лишь удобной формой записи этих чисел и имен. Например, если имеется переменная X размером в слово и нужно описать переменную ТХ, начальным значением которой является тип (размер) этой переменной, то вместо директивы

ТХ DB 2

лучше использовать эквивалентную ей директиву

ТХ DB TYPE Х

поскольку она более универсальна и ее не надо менять, если изменится тип переменной X.

В ЯА выражения делятся на два класса - на константные и адресные, в зависимости от типа их значений. Если значением выражения является целое число, то оно называется консгантным выражением, а если значением является адрес, то это адресное выражение. Конечно, адрес - это тоже целое число (порядковый номер ячейки в памяти), но по смыслу адреса отличаются от просто чисел, и в ЯА они рассматриваются как самостоятельный тип данных.

Отметим, что выражений иных типов в ЯА нет, однако имеются объекты (например, строки и имена регистров), которые не относятся ни к константным, ни к адресным выражениям, но которые также используются для записи операндов команд и директив.

По структуре и назначению выражения, константные и адресные, можно разделить на простейшие выражения и операторы. Из простейших выражений строятся любые другие выражения. К простейшим выражениям относятся числа, имена констант, имена переменных и т. п. Термином "оператор" в ЯА принято обозначать то, что мы обычно называем функциями и операциями. Операторы ЯА делятся на одноместные (это аналог функций одного аргумента) и двухместные (это аналог бинарных операций); примером может служить TYPE X или А+1. С помощью операторов из простейших выражений строятся более сложные выражения.

Язык ассемблера. Начальные сведения

39

С простейшими выражениями и операторами мы будем знакомиться по ходу дела. Однако уже сейчас укажем старшинство всех операторов ЯА (в порядке убывания; в каждой строке указаны операторы одного старшинства):

1.О, [], LENGTH, SIZE, WIDTH, MASK

3.:

4.PTR, OFFSET, SEG, TYPE, THIS

5.HIGH, LOW

6.одноместные + и -

7.*, /, MOD, SHL, SHR

8.двухместные + и -

9.EQ, NE, LT, LE, GT, GE

10.NOT

11.AND

12.OR, XOR

13.SHORT, .TYPE

Операторы одного старшинства вычисляются слева направо. Например, А+В-С - это (А+В)-С.

2.5.1.Константные выражения

Значениями константных выражений всегда являются 16-битовые целые числа (единственным исключением является директива DD, в которой можно явно указывать 32-битовые числа). При этом, если значением (в математическом смысле) константного выражения является отрицательное число, то в формируемую машинную программу оно записывается в дополнительном коде.

Кпростейшим константным выражениям относятся:

число от -215 до 216-1 (числа вне этого диапазона рассматриваются как ошибка);

символ (значением такого выражения является код символа; например, значением выражения '0' будет число 30h);

строка из двух символов (значением является число-слово, составленное из

кодов этих символов; например, значением выражения '01' будет число

303 lh);

имя константы (значением такого выражения яатяется значение константы; например, если была директива К EQU 10, то значение К равно 10).

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

Среди константных операторов, т. е. операторов с числовым значением, пока отметим уже известный нам оператор TYPE и следующие арифметические операторы (k, kl и к2 означают любые константные выражения):

одноместные плюс и минус: +к,

операторы сложения и вычитания: kl+k2, kl-k2

операторы умножения и деления: kl*k2, kl/k2, kl MOD k2

(* - умножение, / - деление нацело, MOD - взятие остатка от деления)

"ДИАЛОГ-МИФИ"

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]