|
Часть2.
Введение в язык ассемблера
ПРИДНЕПРОВСКИЙ ФИЛИАЛ
СОВЕТСКО-БОЛГАРО-ФИНСКОГО ПРЕДПРИЯТИЯ
"Новые информационные технологии"
СИСТЕМА ПРОГРАММИРОВАНИЯ
НА МАКРОАССЕМБЛЕРЕ MS-DOS
Справочное руководство
Часть 2. Введение в язык ассемблера
(редакция 1, январь 1989)
Днепропетровск 1989г.
Содержание
1. Общие сведения о языке................................. 4
2. Первичные элементы языка ассемблера.................... 6
2.1. Алфавит.............................................. 6
2.2. Идентификаторы, переменные, метки, имена,
ключевые слова....................................... 6
2.3. Типы данных.......................................... 8
2.3.1. Целые числа........................................ 8
2.3.2. Действительные числа............................... 8
2.3.3. Десятичные числа................................... 9
2.3.4. Знаковые и строковые константы..................... 9
2.4. Предложения..........................................10
2.5. Комментарии..........................................10
3. Регистры процессора и способы адресации................12
4. Выражения..............................................14
4.1 Операнды выражений....................................14
4.2. Операторы............................................17
4.3. Особенности вычисления выражений.....................24
4.3.1. Приоритеты операций................................24
4.3.2. Ссылки вперед......................................24
4.3.3. Контроль типов.....................................25
Приложение 1. Ключевые слова языка ассемблера.............26
Приложение 2. Регистры и адресация процессора 8088........27
1. Общие сведения о языке.
Настоящее руководство содержит сведения о первичных
элементах языка ассемблера системы MS-DOS и может
представлять интерес для пользователей, впервые приступающих
к изучению языка ассемблера.
Язык ассемблера системы MS-DOS реализован при помощи
макроассемблера MASM (см. "Система программирования на
макроассемблере MS-DOS. Часть 1. Пакет макроассемблера
MS-DOS", п.2) и представляет собой базовый язык семейства
микропроцессоров INTEL 8086/80186/80286. Он включает в себя
инструкции процессоров 8086, 8088, 80186 и 80286 и как
дополнительные возможности - инструкции арифметики с
плавающей точкой процессоров 8087 и 80287, работающих в
режиме сопроцессора.
Синтаксис инструкций процессора предоставляет
программисту широкий выбор типов данных: целые числа, строки
знаков, упакованные десятичные числа, числа с плавающей
точкой, структуры и записи.
Язык ассемблера имеет мощный набор директив, который
позволяет полностью использовать сегментированную
архитектуру процессоров 8086, 80186 и 80286.
В языке имеются директивы условного ассемблирования,
обеспечивающие выборочное исключение частей исходного текста
из процесса ассемблирования и, с другой стороны, возможность
подключения фрагментов исходного текста из других файлов.
Ассемблер имеет набор макродиректив, использование
которых позволяет относительно просто повторять общие блоки
предложений несколько раз или заменять макроимена в исходном
тексте целыми последовательностями предложений.
Макроассемблер MASM генерирует переместимый объектный
код для процессоров 8086, 8088, 80186 и 80286. Формируемые
объектные модули в целом совместимы с объектными модулями,
созданными компиляторами языков высокого уровня.
В настоящем руководстве приняты следующие условные
обозначения.
Конструкция, заключенная в двойные квадратные скобки
[[ ]], может отсутствовать.
Из нескольких конструкций, разделенных символом | ,
может быть выбрана только одна.
Текст, состоящий из букв русского алфавита на
регистре строчных букв и других символов, разделенных
символом - , обозначает нетерминальные элементы и при
кодировании должен замещаться требуемыми по смыслу
конструкциями.
- 5 -
Многоточие ... обозначает возможность многократного
повторения предшествующей конструкции.
Обозначаемые буквами терминальные символы конструкций
даны в изображении регистра заглавных букв. При кодировании
это не является обязательным, кроме тех случаев, когда это
оговорено особо.
- 6 -
2. Первичные элементы языка ассемблера.
Все ассемблерные программы состоят из одного или более
предложений и комментариев. Предложение и комментарий
представляют собой комбинацию знаков, входящих в алфавит
языка, а также чисел и идентификаторов, которые тоже
формируются из знаков алфавита.
2.1. Алфавит.
Макроассемблер распознает следующий набор знаков:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
a b c d e f g h i j k l m n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9
? @ _ $ : . [ ] ( ) < > { }
+ / * & % ! ' ~ | \ = # ^ ; , ` "
2.2. Идентификаторы, переменные,
метки, имена, ключевые слова.
Конструкции языка ассемблера формируются из
идентификаторов и ограничителей.
Идентификатор представляет собой набор букв, цифр и
символов _ , ?, $ или @, не начинающийся с цифры.
Идентификатор должен полностью размещаться на одной строке и
может содержать от 1 до 31 символа (точнее, используются
только первые 31 символ идентификатора, остальные
игнорируются) . Следует заметить, что символ _ , хотя и
допускается в качестве компоненты идентификатора,
ассемблером игнорируется. Поэтому, например, идентификаторы
A_B и AB совпадают.
Друг от друга идентификаторы отделяются пробелом или
ограничителем, которым считается любой недопустимый в
идентификаторе символ.
- 7 -
Посредством идентификаторов представляются следующие
объекты программы:
1. Переменные.
2. Метки.
3. Имена.
Переменные идентифицируют хранящиеся в памяти
данные. Все переменные имеют три атрибута:
1. СЕГМЕНТ, соответствующий тому сегменту, который
ассемблировался, когда была определена переменная.
2. СМЕЩЕНИЕ, являющееся смещением данного поля памяти
относительно начала сегмента.
3. ТИП, определяющий число байтов, подвергающихся
манипуляциям при работе с переменной.
Метка является частным случаем переменной, когда
известно, что определяемая ею память содержит машинный код.
На нее можно ссылаться посредством скачков (переходов) или
вызовов. Метка имеет два атрибута: СЕГМЕНТ и СМЕЩЕНИЕ. Метка
также может быть определена через другую метку директивой
EQU.
Именами считаются символы, определенные директивой EQU
и имеющие значением символ или число. Значения имен не
фиксированы в процессе ассемблирования, но при выполнении
программы именам соответствуют константы. С переменными дело
обстоит наоборот (если значением переменной считать
содержимое идентифицируемой ею области памяти).
Примеры имен:
REGS EQU AX
DIGIT EQU 18
Следующая директива определяет не имя:
VARIABLE EQU LB
.............
LB: HLT
Некоторые идентификаторы, называемые ключевыми
словами, имеют фиксированный смысл и должны употребляться
только в соответствии с этим. Ключевыми словами являются:
1. Директивы ассемблера.
2. Инструкции процессора.
3. Имена регистров.
4. Операторы выражений.
Полный список ключевых слов языка ассемблера приведен
в Приложении 1.
Следует помнить, что обычно ассемблер не различает
строчные и заглавные буквы, и идентификаторы могут включать
в себя буквы обоих регистров. Например, идентификаторы AbS и
abS считаются совпадающими. Различие между строчными и
заглавными буквами может быть установлено опциями /ML и /MX
MASM, что может понадобиться, например, для совместимости с
- 8 -
программами на регистро-чувствительных языках высокого
уровня.
2.3. Типы данных.
В этом разделе описываются типы и формы представления
данных, которые могут быть использованы в выражениях,
директивах и инструкциях языка ассемблера.
2.3.1. Целые числа.
Синтаксис:
цифры
цифрыB
цифрыQ
цифрыO
цифрыD
цифрыH
Латинский символ, который может кодироваться на обоих
регистрах, задает основание счисления числа: B - двоичное, Q
и O - 8-ричное, D - десятичное, H - 16-ричное.
16-ричные числа не должны начинаться с буквенных
16-ричных цифр (например, вместо некорректного ABh следует
употреблять 0ABh). 16-ричные цифры от A до F могут
кодироваться на обоих регистрах.
Первая форма целого числа использует умалчиваемое
основание, которое может устанавливаться директивой .RADIX.
Если директива .RADIX не используется, полагается D.
2.3.2. Действительные числа.
Синтаксис:
цифрыR
[[+|-]]цифры.цифры[[E[[+|-]]цифры]]
Первый формат задает 16-ричное кодированное
- 9 -
представление содержимого памяти, содержащей действительное
число. Действительное число может кодироваться
последовательностью из 8, 12 или 20 16-ричных цифр (возможно
добавление предшествующих 0, т.к. первой должна быть
десятичная цифра). Каждое число имеет знак, зависимую
экспоненту и мантиссу, которые хранятся как поля бит в самом
числе. Точный размер и смысл каждого бита зависит от числа
бит в действительном числе.
Кодированные действительные числа могут использоваться
в директивах DD, DQ и DT. Число 16-ричных цифр должно быть 8
для DD, 16 для DQ и 20 для DT (с предшествующим 0 - 9, 17
или 21 соответственно).
Вторым форматом задается действительное число с
плавающей точкой. Цифры должны быть десятичными. Такие числа
могут использоваться в директивах DD, DQ и DT.
2.3.3. Десятичные числа.
Синтаксис:
[[+|-]]цифры
Этот вид соответствует упакованному формату десятичных
чисел, который включает в себя 1 знаковый байт и 9 значимых
байтов. Каждый значимый байт содержит 2 десятичные цифры.
Допустимо кодирование до 18 включительно цифр. Старший бит
знакового байта имеет значение 0 для положительных чисел и 1
- для отрицательных.
Упакованные десятичные числа имеют то же
представление, что и целые десятичные числа (п.2.3.1) за
исключением того, что они могут иметь знак и использоваться
только в директиве DT.
2.3.4. Знаковые и строковые константы.
Синтаксис:
'знаки'
"знаки"
Знаковая константа состоит из одного знака алфавита
языка. Строковая константа включает в себя 2 или более
знака.
В отличие от других компонент языка, строковые
константы чувствительны к регистру.
- 10 -
Символы ' и " в теле константы должны кодироваться
дважды.
2.4. Предложения.
Синтаксис:
[[имя]] мнемоника [[операнды]][[;комментарии]]
Предложения определяют структуру и функции программы.
Они могут начинаться с любой позиции и содержать не более
128 символов.
Предложение не может содержать внутри себя комбинации
символов CARRIAGE-RETURN/LINE-FEED, т.е. не может быть
продолжено на другую строку. Однако, все предложения, кроме
последнего, должны заканчиваться этой комбинацией символов.
Все предложения языка ассемблера делятся на директивы
ассемблера и инструкции процессора.
Директивы ассемблера действуют лишь в период
компиляции программы и позволяют устанавливать режимы
компиляции, задавать структуру сегментации программы,
определять содержимое полей данных, управлять печатью
листинга программы, а также обеспечивают условную компиляцию
и некоторые другие функции. В результате обработки директив
макроассемблером объектный код не генерируется.
Инструкции процессора представляют собой мнемоническую
форму записи машинных команд, непосредственно выполняемых
микропроцессором. Все инструкции в соответствии с
выполняемыми ими функциями делятся на 5 групп:
1. Инструкции пересылки данных.
2. Арифметические, логические и операции сдвига.
3. Операции со строками.
4. Инструкции передачи управления.
5. Инструкции управления процессором.
Подробнее о директивах ассемблера и инструкциях
процессора см. "Система программирования на макроассемблере
MS-DOS. Часть 3. Элементы языка ассемблера".
2.5. Комментарии.
Часть строки исходного текста после символа ; (если он
не является элементом знаковой константы или строки знаков)
считается комментарием и ассемблером игнорируется.
Комментарии вносятся в программу как поясняющий текст
и могут содержать любые знаки до ближайшей комбинации
- 11 -
символов CARRIAGE-RETURN/LINE-FEED, т.е. до конца строки.
Для создания комментариев, занимающих несколько строк,
может быть использована директива COMMENT.
- 12 -
3. Регистры процессора и способы адресации.
Семейство микропроцессоров 8086/80186/80286 имеет
одинаковый набор регистров и сходные режимы адресации
памяти, поэтому для простоты изложения в настоящем разделе
описываются регистры и адресация процессора 8088.
Все регистры процессора 8088, кроме случаев,
оговоренных особо, занимают 2 байта.
Существуют 5 файлов регистров (Приложение 2):
1. Регистры общего назначения: AX, BX, CX и DX. Они
могут быть использованы для хранения данных или
элементов адреса в адресных выражениях. Каждый из
этих регистров можно рассматривать как совокупность
двух регистров, занимающих его старший и младший
байты. Например, регистр AH соответствует старшему
байту, а регистр AL - младшему байту регистра AX и
т.п. как показано в Приложении 2.
2. Регистры указателя: SP и BP. Обычно регистр SP
используется в операциях со стеком, а регистр BP -
как базовый регистр в адресных выражениях (что,
впрочем, не является обязательным).
3. Индексные регистры: SI и DI. Они обычно
используются в операциях со строками для адресации
источника (SI) и приемника (DI).
4. Регистры сегмента: CS, DS, SS и ES. Условно
программа на языке ассемблера состоит из 4-х
сегментов, каждый из которых адресуется своим
регистром сегмента:
- сегмент кода, содержащий инструкции программы
(адресуется регистром CS);
- сегмент данных, содержащий используемые
программой поля данных (адресуется регистром DS);
- сегмент стека, содержащий стек пользователя
(адресуется регистром SS);
- экстра сегмент, содержащий данные, общие для
нескольких программ (адресуется регистром ES).
5. Указатель инструкции (IP) и флаги. Регистр IP
вместе с регистром CS, если он используется для
адресации кода программы, используется процессором
для выборки с целью исполнения очередной инструкции
программы. Регистр флагов состоит из 9 бит,
расположение и назначение которых показаны в
Приложении 2. Значения флагов отражают результаты
выполнения процессором машинных инструкций и могут
анализироваться, например, инструкциями условного
перехода.
- 13 -
Описанные выше назначения регистров не являются строго
обязательными, но при отсутствии особых указаний принимаются
по умолчанию и способствуют освобождению исходного текста от
излишних спецификаций.
Кроме того, существуют еще несколько правил умолчания
(с более низким приоритетом, чем у указанных выше):
1. Регистр BP обычно содержит смещение относительно
содержимого регистра SS.
2. Регистры BX, SI и DI обычно содержат смещения
относительно содержимого регистра DS.
3. Регистр DI всегда содержит смещение относительно
содержимого регистра ES, если он используется в
инструкциях обработки строк.
Полный физический адрес памяти процессора 8088
содержит 20 бит, что позволяет адресовать 1М памяти.
Процессор 8088 реализует четырехкомпонентную схему
адресации (см. Приложение 2), при которой полный
20-разрядный адрес образуется из 4-х источников:
1. Регистр сегмента.
2. Базовый регистр.
3. Индексный регистр.
4. Непосредственное смещение.
20-разрядный физический адрес формируется путем
сложения содержимого одного из регистров сегмента,
умноженного на 16 (для получения 20-разрядного числа),
содержимого базового и индексного регистров, а также
смещения, представленного целым числом в пределах от 0 до
65535.
Поскольку базовый и индексный регистры и смещение
представляют собой 16-разрядные числа, они могут адресовать
память в пределах 64К относительно адреса, задаваемого
регистром сегмента.
В зависимости от спецификаций и местоположения
источников образования полного адреса в языке ассемблера
различают следующие способы адресации:
1. Непосредственная, когда требуемые данные
расположены непосредственно в команде, а источники
образования адреса отсутствуют.
2. Регистровая, когда данные расположены в регистре.
3. Прямая, когда в команде явно указан адрес сегмента
и смещение относительно его начала.
4. Косвенная, при которой присутствуют один или
несколько из указанных выше источников формирования
адреса. Если опущена спецификация смещения,
используется смещение 0. При отсутствии
спецификации какого-либо регистра применяются
правила умолчания или, если это невозможно, регистр
не используется.
Более подробно способы кодирования адресных операндов
описаны в п.4.1.
- 14 -
4. Выражения.
В языке ассемблера выражения могут быть использованы в
инструкциях или директивах и состоят из операндов и
операторов.
Операнды представляют значения, регистры или позиции
памяти, используемые нужным образом по контексту программы.
Они описаны в п.4.1.
Операторы выполняют арифметические, логические,
побитовые и другие операции над операндами выражений.
Операторы описаны в п.4.2.
4.1. Операнды выражений.
Операнд выражения представляет собой константу, метку,
переменную или другой символ, используемый в программе для
представления значения, регистра или адреса памяти.
Операнды бывают следующих типов:
1. Константа. Синтаксис:
число | строка | выражение
Константой считается число, строковая константа,
символ или выражение, преобразуемое в фиксированное
значение. В отличие от других операндов, константы
представляют значения, используемые в выражениях раньше
(предпочтительней) адресов памяти. Например, в следующей
инструкции 1 рассматривается ассемблером как число 1, а не
как адрес памяти:
MOV AX,1
Символ считается константой, если он определен
директивой EQU или оператором знакового равенства (=).
2. Операнд прямой памяти. Синтаксис:
сегмент : смещение
- 15 -
Операнд прямой памяти реализует прямой способ
адресации. В качестве сегмента может использоваться регистр
сегмента, имя сегмента или имя группы. Смещение лолжно быть
целым числом в пределах от 0 до 65535.
Операнд прямой памяти представляет абсолютный адрес
памяти.
3. Переместимый операнд. Синтаксис:
символ
Переместимый операнд представляет адрес памяти
(сегмент и смещение). В отличие от операнда прямой памяти,
переместимый операнд "привязан" к началу сегмента или группы
и не имеет точного значения до обработки программы LINK.
4. Указатель позиции. Синтаксис:
$
Этот операнд представляет текущую позицию в текущем
сегменте и имеет те же атрибуты, что и метка типа NEAR.
5. Регистр (см. п.3).
6. Базированный операнд. Синтаксис:
смещение [BP]
смещение [BX]
Базированный операнд представляет адрес памяти по
отношению к содержимому базового регистра: BP или BX.
Смещением может быть непосредственное значение или
операнд прямой памяти. Если смещение опущено, полагается 0.
Если указан регистр BP, физический адрес вычисляется
относительно регистра SS, а если BX - относительно DS.
Следующие формы записи базированных операндов
эквивалентны:
[смещение][BP]
[BP+смещение]
[BP].смещение
[BP]+смещение
7. Индексный операнд. Синтаксис:
смещение [SI]
смещение [DI]
Индексный операнд представляет адрес памяти по
- 16 -
отношению к содержимому индексного регистра: SI или DI.
Смещением может быть непосредственное значение или
операнд прямой памяти. Если смещение опущено, полагается 0.
Физический адрес вычисляется относительно регистра DS.
Следующие формы записи индексных операндов
эквивалентны:
[смещение][DI]
[DI+смещение]
[DI].смещение
[DI]+смещение
8. Базо-индексный операнд. Синтаксис:
смещение [BP] [SI]
смещение [BX] [DI]
Базо-индексный операнд представляет адрес памяти
относительно суммы содержимого базового и индексного
регистров.
Смещением может быть непосредственное значение или
операнд прямой памяти. Если смещение опущено, полагается 0.
Если указан регистр BP, физический адрес вычисляется
относительно регистра SS, а если BX - относительно DS.
Следующие формы записи базо-индексных операндов
эквиваленты:
[смещение][BP][DI]
[BP+DI+смещение]
[BP+DI].смещение
[DI]+смещение+[BP]
Недопустимо лишь сочетание одновременно двух базовых
или двух индексных регистров.
9. Структура. Синтаксис:
переменная.поле
Этот операнд представляет адрес одного члена
структуры. Переменная должна быть именем структуры или
операндом памяти, значением которого является адрес
структуры. Поле должно присутствовать в этой структуре.
Точка является оператором поля структуры (п.4.2).
Адрес вычисляется относительно сегмента или группы, в
которых определена структура.
10. Запись. Синтаксис:
имя-записи <[[значение]],...>
Этот операнд ссылается к значению типа запись. Имя
записи должно быть определено в исходном файле как
переменная типа запись директивой RECORD. В скобках < >
указываются значения полей этой записи по порядку. Значения
- 17 -
могут включать в себя выражения и символы, преобразуемые в
константы. Если значение поля опущено, предполагается
умалчиваемое значение для этого поля.
Значение этого операнда является константой.
Пример:
ENCODE RECORD HI:4,MID:3,LO:3
REC1 ENCODE <3,2,1>
MOV AX,REC1
Согласно объявлению запись ENCODE включает в себя 3
поля общей длиной 10 бит. После выполнения фрагмента
содержимое регистра AX будет 0000000011010001b.
11. Поле записи. Синтаксис:
имя-поля-записи
Этот операнд представляет позицию поля соответствующей
записи. Операнд вычисляется по отношению к младшим битам
поля и может быть использован только как константа.
Пример:
ENCODE RECORD HI:4,MID:3,LO:3
REC1 ENCODE <3,2,1>
...
MOV CL,HI ; offset HI (6) -> CL
MOV DX,REC1
ROR DX,CL ; rotate to right by 6
MOV REC1,DX
Согласно объявлению запись ENCODE включает в себя 3
поля общей длиной 10 бит. После выполнения фрагмента
содержимое поля REC1 будет 1111000000001001b.
4.2. Операторы.
Ассемблер обеспечивает выполнение арифметических,
побитовых и операторов отношения, позволяющих различными
способами манипулировать с операндами выражений. Кроме того,
имеются операторы атрибутов, выполняющие действия над
атрибутами операндов.
В дополнение к этому для операций над операндами могут
быть использованы оператор DUP и специальные макрооператоры,
которые в настоящем руководстве не описываются.
Ниже даны описания используемых в выражениях
операторов.
1. Арифметические операторы. Синтаксис:
выражение-1 * выражение-2
выражение-1 / выражение-2
- 18 -
выражение-1 MOD выражение-2
выражение-1 + выражение-2
выражение-1 - выражение-2
+ выражение
- выражение
Эти операторы обеспечивают выполнение основных
арифметических действий. Причем, здесь MOD - остаток от
деления выражения-1 на выражение-2, а знаком / обозначается
деление нацело.
Для всех операторов, кроме бинарных + и -, оба
выражения должны быть целыми числами. Бинарные + и - могут
быть использованы для прибавления к (вычитания от)
переместимому операнду памяти целого числа. Бинарный - может
использовать два переместимых операнда памяти, если значение
выражения указывает в тот же сегмент.
Результатом арифметического оператора является
абсолютное значение.
2. Операторы сдвига. Синтаксис:
выражение SHR счетчик
выражение SHL счетчик
Операторы SHR и SHL сдвигают значение выражения
соответственно вправо и влево на число разрядов,
определяемое счетчиком. Биты, сдвигаемые за пределы
выражения, теряются. Если значение счетчика превышает 15,
результатом выполнения оператора сдвига будет 0, когда
значение выражения занимает 2 байта. Если значением
выражения является 1 байт, для получения нулевого результата
достаточен сдвиг на 8 разрядов.
Не следует смешивать операторы SHR и SHL с
одноименными инструкциями процессора.
3. Операторы отношений. Синтаксис:
выражение-1 EQ выражение-2
выражение-1 NE выражение-2
выражение-1 LT выражение-2
выражение-1 LE выражение-2
выражение-1 GT выражение-2
выражение-1 GE выражение-2
Мнемонические коды отношений расшифровываются
следующим образом:
EQ - равно
NE - не равно
LT - меньше
LE - меньше или равно
GT - больше
GE - больше или равно
Операторы отношений вырабатывают значение 0FFFFh при
- 19 -
выполнении условия и 0000h в противном случае.
Выражения должны иметь абсолютные значения.
Операторы EQ и NE рассматривают свои аргументы как
16-битовые числа. Поэтому, например, выражение -1 EQ 0FFFFh
истинно, т.к. используется знаковый разряд (бит 15).
Остальные операторы трактуют свои аргументы как
17-битовые числа, в которых старший бит определяет знак.
Поэтому здесь 0FFFFh - не -1, а максимальное положительное
число - 65535.
Операторы отношений обычно используются в директивах
условного ассемблирования и инструкциях условного перехода.
4. Операции с битами. Синтаксис:
NOT выражение
выражение-1 AND выражение-2
выражение-1 OR выражение-2
выражение-1 XOR выражение-2
Мнемоники операций расшифровываются следующим образом:
NOT - инверсия
AND - логическое И
OR - логическое ИЛИ
XOR - исключающее логическое ИЛИ
Операции выполняются над каждыми соотвествующими
битами выражений. Выражения должны иметь абсолютные значения.
5. Оператор индекса. Синтаксис:
[[выражение-1]] [выражение-2]
Оператор индекса [] складывает указанные выражения
подобно тому, как это делает оператор +, с той разницей, что
первое выражение необязательно.
Выражение-1 может быть целым числом, абсолютным
символом или переместимым операндом. При его отсутствии
предполагается 0. Если выражение-1 является переместимым
операндом, выражение-2 должно быть целым числом или
абсолютным символом. В противном случае выражение-2 может
быть, кроме того, еще и переместимым операндом.
6. Оператор PTR:
тип PTR выражение
При помощи оператора PTR переменная или метка,
задаваемая выражением, может трактоваться как переменная или
метка указанного типа.
Тип может быть задан одним из следующих имен или
значений:
- 20 -
Имя типа Значение
-------- --------
BYTE 1
WORD 2
DWORD 4
QWORD 8
TBYTE 10
NEAR 0FFFFh
FAR 0FFFEh
Выражение может включать в себя любые операнды.
Типы BYTE, WORD, DWORD, QWORD и TWORD могут быть
использованы только с операндами памяти, а типы NEAR и FAR -
только с метками.
Оператор PTR обычно используется для точного
определения размера, или расстояния, ссылки. Если PTR не
используется, ассемблер подразумевает умалчиваемый тип
ссылки. Кроме того, оператор PTR используется для
организации доступа к объекту, который при другом
способе вызвал бы генерацию сообщения об ошибке (например,
для доступа к старшему байту переменной размера WORD).
В п.4.3 обсуждается, как оператор PTR может быть
использован для того, чтобы избежать ошибок, связанных со
строгим контролем типов.
7. Оператор переключения сегментов. Синтаксис:
регистр-сегмента : выражение
имя-сегмента : выражение
имя-группы : выражение
Оператор переключения сегмента (:) обеспечивает
вычисление адреса данной переменной или метки относительно
содержимого указанного регистра сегмента, начала сегмента
или начала группы. Если задано имя сегмента или имя группы,
это имя должно быть предварительно присвоено регистру
сегмента директивой ASSUME и определено в директивах SEGMENT
или GROUP.
Выражение может быть абсолютным символом или
переместимым операндом.
По умолчанию физический адрес операндов памяти
вычисляется относительно содержимого регистров CS, DS, SS
или ES в зависимости от инструкции и типа операнда. Все
метки по умолчанию понимаются как NEAR. Эти умалчиваемые
действия при необходимости могут быть изменены оператором
переключения сегмента.
8. Оператор имени поля структуры. Синтаксис:
переменная.поле
Этот оператор (.) используется для обозначения поля в
- 21 -
переменной типа структура. Оператор эквивалентен + в
базированных и индексных операндах.
9. Оператор SHORT :
SHORT метка
Этот оператор присваивает указанной метке тип SHORT.
Такая метка может быть использована в инструкции JMP для
передачи управления не далее, чем на 127 байтов. Инструкции,
использующие короткие метки типа SHORT, требуют для своего
размещения на 1 байт меньше.
10. Оператор THIS :
THIS тип
Этот оператор порождает операнд с атрибутами СЕГМЕНТ и
СМЕЩЕНИЕ, соответствующими текущему значению указателя
позиции, и специфицированным типом. В качестве типа могут
кодироваться BYTE, WORD, DWORD, QWORD, TBYTE, NEAR или FAR.
Оператор THIS обычно используется вместе с директивами
EQU или знакового равенства (=) для порождения меток и
переменных (подобно использованию для этих целей директивы
LABEL).
Примеры:
TAG EQU THIS BYTE
CHECK = THIS NEAR
11. Операторы HIGH и LOW :
HIGH выражение
LOW выражение
Операторы HIGH и LOW вычисляют соответственно старшие
и младшие 8 битов значения выражения. Выражение может иметь
любое значение.
12. Оператор SEG :
SEG выражение
Этот оператор вычисляет значение атрибута СЕГМЕНТ
выражения. Выражение может быть меткой. переменной, именем
сегмента, именем группы или другим символом.
13. Оператор OFFSET :
OFFSET выражение
- 22 -
Этот оператор вычисляет значение атрибута СМЕЩЕНИЕ
выражения. Выражение может быть меткой, переменной, именем
сегмента или другим символом. Для имени сегмента вычисляется
смещение от начала этого сегмента до последнего
сгенерированного в этом сегменте байта.
При использовании оператора переключения сегмента (:)
оператор OFFSET вычисляет число байтов между элементом
выражения и началом указанного сегмента или группы. Этим
способом можно генерировать допустимые смещения для
элементов группы.
14. Оператор TYPE :
TYPE выражение
Оператор TYPE порождает число, представляющее тип
выражения. Если выражение является переменной, оператор
вычисляет размер переменной в байтах. Если выражение
является меткой, оператор формирует значение 0FFFFh для
метки типа NEAR и 0FFFEh для метки типа FAR. Вычисляемое
значение может быть использовано для спецификации в
операторе PTR, например:
JMP (TYPE get_loc) PTR destiny
15. Оператор .TYPE :
.TYPE выражение
Этот оператор формирует 1 байт, определяющий режим и
сферу выражения. Если выражение некорректно, все биты этого
байта равны 0. Возможные значения битов приведены в
следующей таблице:
____________________________________________________________
| | | |
| бит | 0 | 1 |
|_____|________________________|___________________________|
| | | |
| 0 | не связано с программой| связано с программой |
|_____|________________________|___________________________|
| | | |
| 1 | не связано с данными | связано с данными |
|_____|________________________|___________________________|
| | | |
| 5 | не определено | определено |
|_____|________________________|___________________________|
| | | |
| 7 | локальная или общая | внешняя сфера (EXTRN) |
| | сфера (PUBLIC) | |
|_____|________________________|___________________________|
Остальные биты результирующего байта всегда равны 0.
Оператор .TYPE обычно используется в условных
- 23 -
директивах.
16. Оператор LENGTH :
LENGTH переменная
Этот оператор вычисляет число элементов типа BYTE,
WORD, DWORD или TBYTE для переменной. Выбираемый элемент
зависит от типа переменной.
Только для переменных, определенных оператором DUP,
оператор LENGTH формирует значения, большие 1. Формируемое
число всегда определяется первым из операторов DUP и не
зависит от их вложенности.
Пример:
ARRAY DW 100 DUP(1)
TABLE DW 100 DUP(1,10 DUP(?))
...
MOV CX,LENGTH ARRAY ; load 100
MOV CX,LENGTH TABLE ; load 100
17. Оператор SIZE :
SIZE переменная
Оператор SIZE определяет число байтов памяти,
выделенных переменной. Оператор SIZE можно рассматривать как
комбинацию операторов LENGTH и TYPE.
18. Оператор WIDTH :
WIDTH имя-поля-записи | запись
Этот оператор вычисляет длину записи или поля записи в
битах.
19. Оператор MASK :
MASK имя-поля-записи | запись
Этот оператор формирует маску битов для представления
позиций заданного поля в записи. Бит маски равен 1, если он
соответствует биту поля, и 0 - в противном случае.
Пример:
RTYPE RECORD F1:3,F2:6,F3:7
...
M1=MASK F1 ; 11100000 00000000b
M2=MASK F2 ; 111111000000b
M3=MASK F3 ; 1111111b
M=MASK RTYPE ; 0FFh
- 24 -
4.3. Особенности вычисления выражений.
4.3.1. Приоритеты операций.
При вычислении значения выражения операции выполняются
в соответствии со следующим списком приоритетов (в порядке
убывания):
1. LENGTH, SIZE, WIDTH, MASK, (), [], <>.
2. Оператор имени поля структуры (.).
3. Оператор переключения сегмента (:).
4. PTR, OFFSET, SEG, TYPE, THIS.
5. HIGH, LOW.
6. Унарные + и -.
7. *, /, MOD, SHR, SHL.
8. Бинарные + и -.
9. EQ, NE, LT, LE, GT, GE.
10. NOT.
11. AND.
12. OR, XOR.
13. SHORT, .TYPE.
4.3.2. Ссылки вперед.
Хотя ассемблер и допускает ссылки вперед (т.е. к
еще необъявленным объектам программы), такие ссылки могут
при неправильном использовании приводить к ошибкам.
Пример ссылки вперед:
JMP TARGET
...
TARGET: ...
Всякий раз, когда ассемблер обнаруживает
неопределенное имя на 1-м проходе, он предполагает, что это
ссылка вперед. Если указано только имя, ассемблер делает
предположения о его типе и используемом регистре сегмента, в
соответствии с которыми и генерируется код. В приведенном
выше примере предполагается, что TARGET - метка типа NEAR и
для ее адресации используется регистр CS, в результате чего
генерируется инструкция JMP, занимающая 3 байта. Если бы,
скажем, в действительности тип ссылки оказался FAR,
ассемблеру нужно было бы генерировать 5-байтовую инструкцию,
что уже невозможно, и формировалось бы сообщение об ошибке.
Во избежание подобных ситуаций рекомендуется
придерживаться следующих правил:
- 25 -
1. Если ссылка вперед является переменной, вычисляемой
относительно регистров ES, SS или CS, следует
использовать оператор переключения сегмента. Если
он не использован, делается попытка вычисления
адреса относительно регистра DS.
2. Если ссылка вперед является меткой инструкции в
команде JMP и отстоит не далее, чем на 128 байтов,
можно использовать оператор SHORT. Если этого не
делать, метке будет присвоен тип FAR, что не
вызовет ошибки, но на 2-м проходе ассемблер для
сокращения размера содержащей ссылку инструкции
вынужден будет вставить дополнительную и ненужную
инструкцию NOP.
3. Если ссылка вперед является меткой инструкции в
командах CALL или JMP, следует использовать
оператор PTR для определения типа метки. Иначе
ассемблер устанавливает тип NEAR, и, если в
действительности тип метки окажется FAR, будет
выдано сообщение об ошибке.
4. Если ссылка вперед является именем сегмента с
оператором переключения сегмента (:), можно
использовать директиву GROUP для связи имени
сегмента с именем группы, а затем использовать
директиву ASSUME для связи имени группы с регистром
сегмента. Пример:
DGROUP GROUP STACK
ASSUME SS:DGROUP
CODE: SEGMENT
...
MOV AX, STACK:STACKTOP
Если имя сегмента не связано с группой, ассемблер
может игнорировать переключение сегмента и
использовать умалчиваемый регистр сегмента, что
обычно приводит к ошибкам на 2-м проходе.
4.3.3. Контроль типов.
Ассемблер выполняет строгий синтаксический контроль
инструкций, включающий проверку точного кодирования типов
операндов памяти. Любой переместимый операнд, используемый в
инструкции, которая оперирует с данными некоторого
предполагаемого типа, должен либо иметь тот же тип, либо
предусматривать преобразование типа оператором PTR.
Пример некорректного кодирования:
STRING DB "A MESSAGE"
...
MOV AX,STRING[1]
Пример правильного кодирования:
...
MOV AX, WORD PTR STRING[1]
- 26 -
Приложение 1. Ключевые слова языка ассемблера.
.186 DI .ERRNZ LENGTH .SALL
.286c DL ES .LFCOND SEG
.286p DQ EVEN .LIST SEGMENT
.287 DS EXITM LOCAL .SFCOND
.8086 DT EXTRN LOW SHL
.8087 DW FAR LT SHORT
= DWORD GE MACRO SHR
AH DX GROUP MASK SI
AL ELSE GT MOD SIZE
AND END HIGH NAME SP
ASSUME ENDIF IF NE SS
AX ENDM IF1 NEAR STRUC
BH ENDP IF2 NOT SUBTTL
BL ENDS IFB OFFSET TBYTE
BP EQ IFDEF OR .TFCOND
BX EQU IFDIF ORG THIS
BYTE .ERR IFE %OUT TITLE
CH .ERR1 IFIDN PAGE TYPE
CL .ERR2 IFNB PROC .TYPE
COMMENT .ERRB IFNDEF PTR WIDTH
.CREF .ERRDEF INCLUDE PUBLIC WORD
CS .ERRDIF IRP PURGE .XALL
CX .ERRE IRPC QWORD .XCREF
DB .ERRIDN LABEL .RADIX .XLIST
DD .ERRNB .LALL RECORD XOR
DH .ERRNDEF LE REPT
MOV PUSH PUSHF POP POPF
XCHG XLAT LEA LDS LES
LAHF SAHF IN OUT ADD
ADC INC AAA DAA SUB
SBB DEC NEG CMP AAS
DAS MUL IMUL AAM DIV
IDIV AAD CBW CWD NOT
AND OR XOR TEST RCL
RCR SAL SAR ROL ROR
MOVS MOVSB CMPS CMPSB CMPSW
SCAS SCASB SCASW LODS STOS
STOSB STOSW JA JNBE JAE
JNB JB JNAE JC JE
JZ JG JNLE JGE JNL
JL JNGE JLE JNG JMP
JNC JNE JNZ JNO JNP
JPO JNS JO JP JPE
JS JCXZ CALL RET LOOP
LOOPE LOOPZ LOOPNE LOOPNZ REP
REPE REPZ REPNE REPNZ INT3
INT INTO IRET STC CLC
CMC STD CLD STI CLI
HLT WAIT ESC LOCK NOP
- 27 -
Приложение 2. Регистры и адресация
процессора 8088.
15 8 7 0
_________________________________________________
| | |
AX | AH | AL |
|_______________________|_______________________|
| | |
BX | BH | BL |
|_______________________|_______________________| Регистры данных
| | |
CX | CH | CL |
|_______________________|_______________________|
| | |
DX | DH | DL |
|_______________________|_______________________|
15 0
_________________________________________________
указатель | |
стека | SP |
|_______________________________________________| Регистры указателя
указатель | |
базы | BP |
|_______________________________________________|
15 0
________________________________________________
| |
источник | SI |
|_______________________________________________| Индексные регистры
| |
приемник | DI |
|_______________________________________________|
- 28 -
15 0
_________________________________________________
| |
код | CS |
|_______________________________________________|
| |
данные | DS |
|_______________________________________________| Регистры сегментов
| |
стек | SS |
|_______________________________________________|
| |
экстра | ES |
|_______________________________________________|
15 0
_________________________________________________
| |
| IP | Указатель команды
|_______________________________________________|
| | | | | | | | | | | | | | | | |
| | | | | O| D| I| T| S| Z| | A| | P| | C| Флаги
|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|__|
11 10 9 8 7 6 4 2 0
OF - переполнение ZF - нуль
DF - флаг направления AF - вспомогательный перенос
IF - разрешение прерывания PF - паритет
TF - ловушка CF - перенос
SF - знак
- 29 -
Условные обозначения:
B - базовый регистр
X - индексный регистр
S - смещение
(...) - содержимое регистра
ИА - исполнительный 16-разрядный адрес
ЛА - логический 16-разрядный адрес
ФА - физический 20-разрядный адрес
[...] - компонента может отсутствовать
{...|...} - обязательный выбор варианта
__________________________________________________
| | |
| Типы адресации | Местоположение данных |
|_____________________|__________________________|
| | |
| 1. Непосредственная | В команде |
|_____________________|__________________________|
| | |
| 2. Регистровая | В регистре |
|_____________________|__________________________|
| | |
| 3. Прямая | ИА - в команде |
|_____________________|__________________________|
| | |
| 4. Косвенная | ИА=(B)+[(X)]+[S] |
|_____________________|__________________________|
ЛА = ИА данных | (IP) инструкции процессора | (SP) элемента стека
| (SI) строки-источника | (DI) строки-приемника
ФА = ЛА + { (CS) | (DS) | (SS) | (ES) } * 16
© KOAP
Open Portal 2000
|