В программе, написанной на языке ассемблера, можно выделить два типа предложений:
– команды;
– директивы (псевдокоманды).
Директивы лишь управляют работой транслятора и не генерируют машинных кодов. Команды непосредственно выполняются микропроцессором и потому всегда генерируют машинные коды. Соответственно директивы не занимают место в памяти, а команды занимают. В языке ассемблера каждое новое предложение языка начинается с новой строки и занимает одну строку. Формат директив показан на рис.4.1, а формат команд на рис.4.2.
Рис. 4.1. Формат директивы
Рис. 4.2. Формат команды
При написании программы допустимо использовать следующие символы:
– все латинские буквы A…Z, a…z
– цифры 0…9
– специальные символы: _? $ @ & [ ],. \ / % # ' " + * ^ () < >! { }
Необходимо отметить, что при написании текста программ (в идентификаторах, директивах, командах, операндах) строчные и прописные буквы считаются эквивалентными. В тех местах, где допускается пробел, их число может быть любым – лишние пробелы транслятор проигнорирует.
Идентификаторы – это последовательности допустимых символов, использующиеся для обозначения имен переменных, имен директив и меток (таблица идентификаторов определяется транслятором при первом просмотре программы – см. разд.3.2). Идентификатор может состоять из одного или нескольких символов. В качестве символов можно использовать буквы латинского алфавита, цифры и некоторые специальные знаки: _,.,?, $, @. Идентификатор не может начинаться символом цифры. Если в идентификаторе имеется точка, то она должна быть обязательно первым символом. Длина идентификатора может составлять до 255 символов, хотя транслятор воспринимает лишь первые 32, а остальные игнорирует. Идентификатор не должен совпадать с ключевыми словами языка ассемблера (например, именами регистров или названиями команд).
Команды и директивы – это указания на выполнение определенных действий соответственно процессору или транслятору. Их количество и формат записи строго определены.
Комментарии необходимы для улучшения понятности программы. Они всегда начинаются с символа «;». При этом ассемблер полагает, что все символы, находящиеся справа от точки с запятой являются комментарием. Комментарий может содержать любые печатные символы (в том числе и русские буквы), включая пробел. Комментарий может занимать всю строку или следовать за командой на той же строке, как это показано в двух следующих примерах:
;Эта строка полностью является комментарием
ADD AX,BX;Комментарий на одной строке с командой
Комментарии появляются только в листингах трансляции исходного текста программы (см. рис.3.3) и не приводят к генерации машинных кодов, поэтому можно включать в программу любое количество комментариев, не влияя на эффективность ее выполнения.
Операнды – это объекты, над которыми или при помощи которых выполняются действия, задаваемые командами или директивами. В командах может быть не более двух операндов, в директивах число операндов может быть большим. Если в команде или директиве несколько операндов, то они перечисляются друг за другом через запятую без пробелов.
Большинство команд требует двух операндов, первый из которых является приемником, а второй – источником. Возможные сочетания операндов в двухоперандной машинной команде приведены в табл.4.1.
Таблица 4.1. Возможные сочетания операндов в команде
Приемник | Источник |
регистр | память |
память | регистр |
регистр | регистр |
регистр | непосредственный операнд |
память | непосредственный операнд |
С двумя операндами, находящимися в памяти, команды работать не могут (обмен память-память невозможен).
Рассмотрим, какие бывают операнды и как они могут задаваться в командах и директивах.
Операнд задается неявно на микропрограммном уровне. В этом случае команда явно не содержит операндов. Алгоритм выполнения команды использует некоторые объекты по умолчанию. Например, команда CLC сбрасывает в ноль флаг переноса CF, а команда CLD устанавливает в ноль флаг направления DF:
CLC;CF=0
CLD;DF=0
Операнд задается в самой команде (непосредственный операнд). Это может быть число, строка, имя (имя метки) или выражение, имеющее некоторое фиксированное (константное) значение. Непосредственный операнд находится в коде команды, то есть является ее частью и соответственно влияет на размер команды. Непосредственный операнд может быть только источником данных и не может быть приемником.
Целые числа в программах на языке ассемблера могут быть записаны в десятичной, двоичной, восьмеричной и шестнадцатеричной системах счисления (другие системы не допускаются). Для обозначения системы счисления в конце записи числа ставиться соответствующая буква:
– D (decimal) – десятичная система счисления (можно не записывать);
– B (binary) – двоичная система счисления;
– O (octal) или Q – восьмеричная система счисления;
– H (hexadecimal) – шестнадцатеричная система счисления.
Если число, записанное в шестнадцатеричном виде, начинается с «буквенной» цифры, то для того, чтобы не спутать его и идентификатором в начале числа пишется незначащий ноль, то есть, например, не A5H, а 0A5H.
Отдельные символы и символьные строки (последовательности символов) заключаются либо в одинарные, либо в двойные кавычки: 'А' или "А", 'А+b' или "А+В". Естественно, левая и правая кавычки должны быть одинаковыми: 'В" или "В' – ошибки. Транслятор интерпретирует символы, занесенные в кавычки, как ASCII коды (ASCII (англ. American Standard Code for Information Interchange) – американский стандартный код для обмена информацией), где каждому символу соответствует восьмибитный (однобайтный) код. Частично таблица кодов ASCII представлена в табл.4.2.
Таблица 4.2. Коды ASCII некоторых символов
Код в десятичном формате | Код в шестнадцатеричном формате | Символ |
Пробел | ||
2B | + | |
A | ||
B | ||
C | ||
D | ||
E | ||
F | ||
G | ||
H | ||
I | ||
4A | J | |
4B | K | |
4C | L | |
4D | M | |
4E | N | |
4F | O | |
P | ||
Q | ||
R | ||
S | ||
T | ||
U | ||
V | ||
W | ||
Z | ||
Y | ||
5A | Z | |
a | ||
b |
Окончание табл. 4.2
c | ||
d | ||
e | ||
f | ||
g | ||
h | ||
i | ||
6A | j | |
6B | k | |
6C | l | |
6D | m | |
6E | n | |
6F | o | |
p | ||
q | ||
r | ||
s | ||
t | ||
u | ||
v | ||
w | ||
z | ||
y | ||
7A | z |
Можно использовать русские символы (для них имеются свои ASCII коды). Большие и малые буквы не отождествляются ('А+В' и 'а+b' – разные строки). Каждый пробел является одним символом. Символ цифры не равен значению цифры. Примеры использования непосредственных операндов:
MOV AX,'АH'
MOV DL,0АH
ADD CX,-15D
Операнд находится в одном из регистров (регистровый операнд). Регистровый операнд – это просто имя регистра (примеры см. выше).
Операнд счетчик размещения. Специфический вид операнда, который обозначается символом «$». Когда транслятор встречает в исходной программе этот символ, то он подставляет вместо него текущее значение счетчика адреса (счетчика размещения) – смещение текущей машинной команды относительно начала сегмента кода (значение регистра IP). При обработке транслятором очередной команды ассемблера счетчик адреса увеличивается на длину сформированной машинной команды. Обработка директив ассемблера не влечет за собой изменения счетчика, так как директивы ассемблера не занимают места в памяти. В качестве примера использования в команде значения счетчика адреса можно привести следующий фрагмент:
JMP $+3;безусловный переход на команду MOV
СLD;длина команды СLD составляет 1 байт
MOV AL,12
В данном примере команда JMP занимает в памяти два байта, а команда СLD – один байт. Вместо счетчика адреса подставляется смещение (эффективный адрес) в сегменте кода текущей команды, то есть команды JMP, что нужно учитывать при определении перехода, тем более что длина команды зависит от того какие в ней используются операнды. Информацию о размере команды можно получить, анализируя соответствующую колонку (колонку со смещением каждой команды в сегмента кода) файла листинга (см. рис.3.3).
Операнд находится в памяти. Наиболее важный тип операнда, поскольку с данными из памяти приходится манипулировать практически любой программе. Ссылки на значения в памяти (адреса данных) могут задаваться различными способами, которые называются способами адресации.
Рассмотрим, какие бывают способы адресации: