Безусловные переходы
Предыдущее обсуждение выявило некоторые детали механизма перехода. Команды перехода модифицируют регистр указателя команды EIP/IP и, возможно, сегментный регистр кода CS. Что именно должно подвергнуться модификации, зависит:
от типа операнда в команде безусловного перехода (ближний или дальний);
от модификатора, который указывается перед адресом перехода в команде перехода и может принимать следующие значения (сам адрес при прямом переходе находится непосредственно в команде, а при косвенном — в регистре или ячейке памяти):
NEAR PTR — прямой переход на метку внутри текущего сегмента кода, при этом модифицируется только регистр EIP/IP (в зависимости от заданного типа сегмента кода use16 или use32) на основе указанного в команде адреса (метки) или выражения, использующего символ извлечения значения счетчика адреса команд ($);
FAR PTR — прямой переход на метку в другом сегменте кода, при этом адрес перехода задается в виде непосредственного операнда или адреса (метки) и состоит из 16-разрядного селектора и 16/32-разрядного смещения, которые загружаются, соответственно, в регистры CS и EIP/IP;
WORD PTR — косвенный переход на метку внутри текущего сегмента кода, при этом модифицируется (значением смещения размером 16 или 32 бита из памяти по указанному в команде адресу или из регистра) только регистр EIP/IP;
DWORD PTR — косвенный переход на метку в другом сегменте кода, при этом модифицируются (значением из памяти — и только из памяти, из регистра нельзя) оба регистра, CS и EIP/IP (первое слово/двойное слово адреса перехода, представляющее собой смещение, загружается в EIP/IP; второе/третье слово — в CS).
Команда безусловного перехода
Синтаксис команды безусловного перехода без сохранения информации о точке
jmp [модификатор] адрес_перехода
Здесь адрес_перехода представляет метку или адрес области памяти, в которой находится указатель перехода.
Всего в системе команд процессора есть несколько кодов машинных команд безусловного перехода JMP. Их различия определяются дальностью перехода и способом задания целевого адреса. Дальность перехода определяется местоположением операнда адрес_перехода. Этот адрес может находиться в текущем сегменте кода или в некотором другом сегменте. В первом случае переход называется внутрисегментным, или близким, во втором — межсегментным, или дальним.
Внутрисегментный переход предполагает, что изменяется только содержимое регистра EIP/IP. Можно выделить три варианта внутрисегментного использования команды JMP:
-прямой короткий переход;
Прямой короткий внутрисегментный переход применяется, когда расстояние от команды JMP до адреса перехода не превышает -128 или +127 байт. В этом случае транслятор ассемблера формирует машинную команду безусловного перехода длиной всего два байта (размер обычной команды внутрисегментного безусловного перехода составляет три байта). Первый байт в этой команде — код операции, значение которого говорит о том, что процессор должен особым образом трактовать второй байт команды. Значение второго байта вычисляется транслятором как разность между значением смещения команды, следующей за JMP, и значением адреса перехода. При осуществлении прямого короткого перехода нужно иметь в виду следующий важный момент, связанный с местоположением адреса перехода и самой команды JMP. Если адрес перехода расположен до команды JMP, то ассемблер формирует короткую команду безусловного перехода без дополнительных указаний. Если адрес перехода расположен после команды JMP, транслятор не может сам определить, что переход короткий, так как у него еще нет информации об адресе перехода. Для оказания помощи компилятору в формировании команды короткого безусловного перехода в дополнение к ранее упомянутым модификаторам используют модификатор SHORT PTR:
jmp short ptr ml
. ;не более 35-40 команд (127 байт)
. ;не более 35-40 команд (-128 байт)
Прямой внутрисегментный переход отличается от прямого короткого внутрисегментного перехода тем, что длина машинной команды JMP в этом случае составляет три байта. Увеличение длины связано с тем, что поле адреса перехода в машинной команде JMP расширяется до двух байтов, а это, в свою очередь, позволяет производить переходы в пределах 64 Кбайт относительно следующей за JMP команды:
. расстояние более 128 байт и менее 64 Кбайт
Косвенный внутрисегментный переход подразумевает «косвенность» задания адреса перехода. Это означает, что в команде указывается не сам адрес перехода, а место, где он «лежит». Приведем несколько примеров, в которых двухбайтовый адрес перехода выбирается либо из регистра, либо из области памяти:
jmp bx ;адрес перехода в регистре bх
jmp addr_ml ;адрес перехода в ячейке памяти addrjnl
Еще несколько вариантов косвенного внутрисегментного перехода:
<10>jmpaddr[si];адрес перехода в слове памятиaddr+(si)
В этом примере одна команда JMP (строка 10) может выполнять переходы на разные метки. Выбор конкретной метки перехода определяется содержимым регистра SI. Операнд команды JMP определяет адрес перехода косвенно после вычисления выражения addr+(SI).
<8> jmp near ptr [si ] ;адрес перехода в ячейке памяти addr
В данном случае указание модификатора NEAR PTR обязательно, так как, в отличие от предыдущего способа, адрес ячейки памяти addr с адресом перехода транслятору передается неявно (строки 3, 7 и 8), и, не имея информации о метке, он не может определить, какой именно переход осуществляется — внутрисегментный или межсегментный. Межсегментный переход предполагает другой формат машинной команды JM Р. При осуществлении межсегментного перехода кроме регистра EIP/IP
модифицируется также регистр CS. Аналогично внутрисегментному переходу, межсегментный переход поддерживают два варианта команд безусловного перехода:
прямой и косвенный.
Команда прямого межсегментного перехода имеет длину пять байтов, из которых два байта составляют значение смещения и два байта — значение сегментной составляющей адреса:
jmp far ptr m2 ;здесь far обязательно
jmp ml ;здесь far необязательно
Рассматривая этот пример, обратите внимание на модификатор FAR PTR в команде JMP. Его необходимость объясняется все той же логикой работы однопроходного транслятора. Если описание метки (метка ml) встречается в исходном тексте программы раньше, чем соответствующая ей команда перехода, то задание модификатора необязательно, так как транслятор все знает о данной метке и сам формирует нужную пятибайтовую форму команды безусловного перехода. В случае, когда команда перехода встречается до описания соответствующей метки, транслятор не имеет еще никакой информации о метке, и модификатор FAR PTR в команде JMP опускать нельзя, так как транслятор не знает, какую форму команды формировать — трехбайтную или пятибайтную. Без специального указания модификатора транслятор будет формировать трехбайтную команду внутрисегментного перехода.
Команда косвенного межсегментного перехода в качестве операнда имеет адрес области памяти, в которой содержатся смещение и сегментная часть целевого адреса перехода:
addrjnl dd ml ;в поле addr_ml значения смещения
;и адреса сегмента метки ml
Как вариант косвенного межсегментного перехода необходимо отметить косвенный регистровый межсегментный переход. В этом виде перехода адрес перехода указывается косвенно — в регистре. Это очень удобно для программирования динамических переходов, в которых адрес перехода может изменяться на стадии выполнения программы:
addr_ml dd ml ;в поле addr_ml значения смещения
;и адреса сегмента метки ml
jmp dword ptr[bx]
Таким образом, модификаторы SHORT PTR, NEAR PTR и WORD PTR применяются для организации внутрисегментных переходов, a FAR PTR и DWORD PTR — межсегментных.
Для полной ясности нужно еще раз подчеркнуть, что если тип сегмента — use32, то в тех местах, где речь шла о регистре IP, можно использовать регистр EIP и, соответственно, размеры полей смещения увеличить до 32 битов.
Тут вы можете оставить комментарий к выбранному абзацу или сообщить об ошибке.
Урок 5
На прошлом уроке для того, чтобы сделать задержку и считать символ с клавиатуры, мы были вынуждены использовать цикл. Сегодня мы более подробно познакомимся с непоследовательным выполнением команд. Большинство программ содержат ряд циклов, в которыхнесколько команд повторяются до достижения определенного требования, и различные проверки, определяюшие, какие из нескольких действий следует выполнять. Обычным требованием является проверка — должна ли программа завершить выполнение. Эти требования включают передачу управления по адресу команды, которая не находится непосредственно за выполняемой в текущий момент командой. Передача управления может осуществляться вперед для выполнения новой группы команд или назад для повторения уже выполненных команд. Некоторые команды могут передавать управление, изменяя нормальную последовательность шагов непосредственной модификацией значения смещения в командном указателе. Ниже приведены четыре способа передачи управления (все будут рассмотрены в этой главе):
Заметим, что имеется три типа адресов: SHORT, NEAR и FAR. Адресация SHORT используется при циклах, условных пеpеходах и некоторых безусловных переходах. Адресация NEAR и FAR используется для вызовов процедур (CALL) и безусловных переходов, которые не квалифицируются , как SHORT. Все три типа передачи управления воздействуют на содержимое регистра IP; тип FAR также изменяет регистр CS.
Команда JMP
Одной из команд, обычно используемых для передачи управле ния является команда JMP. Эта команда выполняет безусловный переход, т.е. обеспечивает передачу управления при любых обстоятельствах. Команда JMP для перехода в пределах -128 до +127 байт имеет тип SHORT. Ассемблер генерирует в этом случае однобайтовый операнд в пределах от 00 до FF. Команда JMP, превосходящая эти пределы, получает тип FAR, для которого генерируется другой машинный код и двухбайтовый операнд. Ассемблер в первом просмотре исходной программы определяет длину каждой команды. Однако, команда JMP может быть длиной два или три байта. Если к моменту просмотра команды JMP ассемблер уже вычислил значение опеpанда (при переходе назад):
то он генерирует двухбайтовую команду. Если ассемблер еще не вычислил значение операнда (при переходе вперед)
то он не знает тип перехода NEAR или FAR, и автоматически генерирует 3-х байтовую команду. Для того, чтобы указать ассемблеру на необходимость генерации двухбайтовой команды, следует использовать оператор SHORT:
В качестве полезного упражнения, введите программу, проассемблируйте ее, скомпануйте и переведите в COM-формат. Определение данных не требуется, поскольку непосредственные операнды генерируют все необходимые данные. Используйте отладчик DEBUG для пошагового выполнения COM-модуля и просмотрите несколько повторений цикла. Когда регистр AX будет содержать 08, BX и CX увеличатся до шест. 24 (дес. 36) и шест. 80 (дес. 128), соответственно. Для выхода из отладчика используйте команду Q.
команда LOOP
Команда JMP в примере на рис. 7.1 реализует бесконечный цикл. Но более вероятно подпрограмма должна выполнять определенное число циклов. Команда LOOP, которая служит для этой цели, использует начальное значение в регистре CX. В каждом цикле команда LOOP автоматически уменьшает содержимое регистра CX на 1. Пока значение в CX не равно нулю, управление передается по адресу, указанному в операнде, и если в CX будет 0, управление переходит на слудующую после LOOP команду. Аналогично команде JMP, операнд команды LOOP определяет расстояние от конца команды LOOP до адреса метки A20, кото рое прибавляется к содержимому командного указателя. Для команды LOOP это расстояние должно быть в пределах от -128 до +127 байт. Если операнд превышает эти границы, то ассемб лер выдаст сообщение «Relative jump out of range» (превышены границы перехода). Дополнительно существует две разновидности команды LOOP — это LOOPE (или LOOPZ) и LOOPNE (или LOOPNZ). Обе команды также уменьшают значение регистра CX на 1. Команда LOOPE передает управление по адресу операнда, если регистр CX имеет ненулевое значение и флаг нуля установлен (ZF=1). Команда LOOPNE передает управление по адресу операнда, если регистр CX имеет ненулевое значение и флаг нуля сброшен (ZF=0).
Регистр флагов (Flags)
Следующий материал данной главы требует более детального ознакомления с флаговым регистром. Этот pегистр содержит 16 бит флагов, которые управляются различными командами для индикации состояния операции. Во всех случаях флаги сохраня ют свое значение до тех пор, пока другая команда не изменит его. Флаговый регистр содержит следующие девять используемых бит (звездочками отмечены неиспользуемые биты):
Рассмотрим эти флаги в последовательности справа налево.
CF (Carry Flag)
флаг переноса. Содержит значение «переносов» (0 или 1) из старшего разряда при арифметичес ких операциях и некоторых операциях сдвига и циклического сдвига (см. гл.12).
PF (Parity Flag)
флаг четности. Проверяет младшие восемь бит pезультатов операций над данными. Нечетное число бит приводит к установке этого флага в 0, а четное — в 1. Не следует путать флаг четности с битом контроля на четность.
AF (Auxiliary Carry Flag)
дополнительный флаг переноса. Устанавливается в 1, если арифметическая операция приводит к переносу четвертого бита справа (бит номер 3) в регистро вой однобайтовой команде. Данный флаг имеет отношение к арифметическим операциям над символами кода ASCII и к десятичным упакованным полям.
ZF (Zero Flag)
флаг нуля. Устанавливается в качестве результата aрифметических команд и команд сравнения. Как это ни странно, ненулевой результат приводит к установке нулевого значения этого флага, а нулевой — к установке единичного значения. Кажущееся несоответствие является, однако, логически правильным, так как 0 обозначает «нет» (т.е. результат не равен нулю), а единица обозначаeт «да» (т.е. результат равен нулю). Команды условного перехода JE и JZ проверяют этот флаг.
SF (Sign Flag)
знаковый флаг. Устанавливается в соответ ствии со знаком результата (старшего бита) после арифмети ческих опеpаций: положительный результат устанавливает 0, а отрицательный — 1. Команды условного перехода JG и JL проверяют этот флаг.
TF (Trap Flag)
флаг пошагового выполнения. Этот флаг вам уже приходилось устанавливать, когда использовалась ко манда Т в отладчике DEBUG. Если этот флаг установлен в еди ничное cостояние, то процессор переходит в режим пошагового выполнения команд, т.е. в каждый момент выполняется одна команда под пользовательским управлением.
IF (Interrupt Flag)
флаг прерывания. При нулевом состоя нии этого флага прерывания запрещены, при единичном — разрешены.
DF (DIrection Flag)
флаг направления. Используется в строковых операциях для определения направления передачи данных. При нулевом состоянии команда увеличивает содержимое регистров SI и DI, вызывая передачу данных слева направо, при нулевом — уменьшает содержимое этих регистров, вызывая передачу данных справа налево.
OF (Overflow Flag)
флаг переполнения. Фиксирует арифме тическое переполнение, т.е. перенос в/из старшего (знаково го) бита при знаковых арифметических операциях. В качестве примера: команда CMP сравнивает два операнда и воздействуте на флаги AF, CF, OF, PF, SF, ZF. Однако, нет необходимости проверять все эти флаги по отдельности. В сле- дующем примере проверяется содержит ли регистр BX нулевое значение:
Если BX содержит нулевое значение, команда CMP устанавливает флаг нуля ZF в единичное состояние, и возможно изменяет (или нет) другие флаги. Команда JZ (перехлд если нуль) проверяет только флаг ZF. При единичном значении ZF, обозначающее нулевой признак, команда передает управление на адрес, указанный в ее операнде, т.е. на метку B50. В предыдущих примерах было показано, что команда LOOP уменьшает на единицу содержимое регистра CX и проверяет его: если не ноль, то управление передается по адресу, указанному в операнде. Таким образом, передача управления зависит от конкретного состояния. Ассемблер поддерживает большое количество команд условного перехода, которые осуществляют передачу управления в зависимости от состояний флагового регистра. Например, при сравнении содержимого двух полей последующий переход зависит от значения флага. Команду LOOP в программе на рис.7.2 можно заменить на две команды: одна уменьшает содержимое регистра CX, а другая выполняет условный переход:
Команды DEC и JNZ действуют аналогично команде LOOP: уменьшают содержимое регистра CX на 1 и выполняет переход на метку A20, если в CX не ноль. Команда DEC кроме того устанавливает флаг нуля во флаговом регистре в состояние 0 или 1. Команда JNZ затем проверяет эту установку. В рассмот ренном примере команда LOOP хотя и имеет огпаниченное исполь зование, но более эффективна, чем две команды: DEC и JNZ. Аналогично командам JMP и LOOP операнд в команде JNZ cодержит значение расстояния между концом команды JNZ и адресом A20, которое прибавляется к командному указателю. Это расстояние должно быть в пределах от -128 до +127 байт. В случае перехода за эти границы ассемблер выдаст сообщение «Relative jump out of range» (превышены относительные грани цы перехода).
Знаковые и беззнаковые данные
Рассматривая назначение команд условного перехода следует пояснить характер их использования. Типы данных, над которы ми выполняются арифметические операции и операции сравнения определяют какими командами пользоваться: беззнаковыми или знаковыми. Беззнаковые данные используют все биты как биты данных; характерным примером являются символьные строки: имена, адреса и натуральные числа. В знаковых данных самый левый бит представляет собой знак, причем если его значение равно нулю, то число положительное, и если единице, то отрицательное. Многие числовые значения могут быть как положительными так и отрицательными. В качестве примера предположим, что регистр AX содержит 11000110, а BX — 00010110. Команда
сравнивает содержимое регистров AX и BX. Если данные беззнаковые, то значение в AX больше, а если знаковые — то меньше.
Условные переходы
Переходы для беззнаковых данных
Любую проверку можно кодировать одним из двух мнемоничес ких кодов. Например, JB и JNAE генерирует один и тот же объектный код, хотя положительную проверку JB легче понять, чем отрицательную JNAE.
Переходы для знаковых данных
Команды перехода для условия равно или ноль (JE/JZ) и не равно или не ноль (JNE/JNZ) присутствуют в обоих списках для беззнаковых и знаковых данных. Состояние равно/нуль происходит вне зависимости от наличия знака.
Специальные арифметические проверки
Еще одна команда условного перехода проверяет равно ли содержимое регистра CX нулю. Эта команда необязательно должна pасполагаться непосредственно за командой арифметики или сравнения. Одним из мест для команды JCXZ может быть начало цикла, где она проверяет содержит ли регистр CX ненулевое значение. Не спешите пока заучивать эти команды наизусть. Запомните только, что для беззнаковых данных есть переходы по состоя ниям равно, выше или ниже, а для беззнаковых — равно, больше или меньше. Переходы по проверкам флагов переноса, переполнения и паритета имеют особое назначение. Ассемблер транслирует мнемонические коды в объектный код независимо от того, какую из двух команд вы применили. Однако, команды JAE и JGE являясь явно одинаковыми, проверяют различные флаги.
Операнды в языке ассемблера
Операнд – объект, над которым выполняется машинная команда.
Операнды ассемблера описываются выражениями с числовыми и текстовыми константами, метками и идентификаторами переменных с использованием знаков операций и некоторых зарезервированных слов.
Операнды могут комбинироваться с арифметическими, логическими, побитовыми и атрибутивными операторами для расчета некоторого значения или определения ячейки памяти, на которую будет воздействовать данная команда или директива.
Способы адресации операндов
Под способами адресации понимаются существующие способы задания адреса хранения операндов:
Операнд задается на микропрограммном уровне (операнд по умолчанию): в этом случае команда явно не содержит операнда, алгоритм выполнения команды использует некоторые объекты по умолчанию (регистры, признаки и т.д.).
Операнд задается в самой команде (непосредственный операнд): операнд является частью кода команды. Для хранения такого операнда в команде выделяется поле длиной до 32 бит. Непосредственный операнд может быть только вторым операндом (источником). Операнд-получатель может находиться либо в памяти, либо в регистре.
Операнд находится в одном из регистров (регистровый операнд): в коде команды указываются именами регистров. В качестве регистров могут использоваться:
- 32-разрядные регистры ЕАХ, ЕВХ, ЕСХ, EDX, ESI, EDI, ESP, EBP;
- 16-разрядные регистры АХ, ВХ, СХ, DX, SI, DI, SP, ВР;
- 8-разрядные регистры АН, AL, BH, BL, CH, CL, DH, DL;
- сегментные регистры CS, DS, ,SS, ES, FS, GS.
- прямую адресацию;
- косвенную адресацию.
Прямая адресация : эффективный адрес определяется непосредственно полем смещения машинной команды, которое может иметь размер 8, 16 или 32 бита.
Ассемблер заменяет sum на соответствующий адрес, хранящийся в сегменте данных (по умолчанию адресуется регистром ds ) и значение, хранящееся по адресу sum , помещает в регистр eax .
Косвенная адресация в свою очередь имеет следующие виды:
- косвенная базовая (регистровая) адресация;
- косвенная базовая (регистровая) адресация со смещением;
- косвенная индексная адресация;
- косвенная базовая индексная адресация.
Косвенная базовая (регистровая) адресация. При такой адресации эффективный адрес операнда может находиться в любом из регистров общего назначения, кроме sp/esp и bp/ebp (это специфические регистры для работы с сегментом стека). Синтаксически в команде этот режим адресации выражается заключением имени регистра в квадратные скобки [].
Данный способ адресации позволяет динамически назначить адрес операнда для некоторой машинной команды и применяется при организации циклических вычислений и при работе со структурами данных, массивами.
Косвенная базовая (регистровая) адресация со смещением предназначена для доступа к данным с известным смещением относительно некоторого базового адреса, используется для доступа к элементам структур, когда смещение элементов известно заранее, на стадии разработки программы, а базовый (начальный) адрес структуры должен вычисляться динамически, на стадии выполнения программы. Модификация содержимого базового регистра позволяет обратиться к одноименным элементам различных экземпляров однотипных структур данных.
Косвенная индексная адресация. Для формирования эффективного адреса используется один из регистров общего назначения, но обладает возможностью масштабирования содержимого индексного регистра.
Значение эффективного адреса второго операнда вычисляется выражением mas+( esi *4) и представляет собой смещение относительно начала сегмента данных.
Наличие возможности масштабирования существенно помогает в решении проблемы индексации при условии, что размер элементов массива постоянен и составляет 1, 2, 4 или 8 байт.
Данный вид адресации также может использоваться со смещением.
Косвенная базовая индексная адресация. Эффективный адрес формируется как сумма содержимого двух регистров общего назначения: базового и индексного. В качестве этих регистров могут применяться любые регистры общего назначения, при этом часто используется масштабирование содержимого индексного регистра.
Эффективный адрес второго операнда формируется как esi+edx . Значение по этому адресу помещается в регистр eax.
В случае использования косвенной базовой индексной адресация со смещением эффективный адрес формируется как сумма трех составляющих: cодержимого базового регистра, cодержимого индексного регистра и значения поля смещения в команде.
Операндом является порт ввода-вывода.
Помимо адресного пространства оперативной памяти микропроцессор поддерживает адресное пространство ввода-вывода, которое используется для доступа к устройствам ввода-вывода. Объем адресного пространства ввода-вывода составляет 64 Кбайт. Для любого устройства компьютера в этом пространстве выделяются адреса. Конкретное значение адреса в пределах этого пространства называется портом ввода-вывода. Физически порту ввода-вывода соответствует аппаратный регистр (не путать с регистром микропроцессора), доступ к которому осуществляется с помощью специальных команд ассемблера in и out .
Регистры, адресуемые с помощью порта ввода-вывода, могут иметь разрядность 8, 16 или 32 бит, но для конкретного порта разрядность регистра фиксирована. В качестве источника информации или получателя применяются регистры-аккумуляторы eax , ax , al . Выбор регистра определяется разрядностью порта. Номер порта может задаваться непосредственным операндом в командах in и out или значением в регистре dx . Последний способ позволяет динамически определить номер порта в программе.
Счетчик адреса – специфический вид операнда. Он обозначается знаком $. Специфика этого операнда в том, что когда транслятор ассемблера встречает в исходной программе этот символ, он подставляет вместо него текущее значение счетчика адреса (регистр EIP ). Значение счетчика адреса представляет собой смещение текущей машинной команды относительно начала сегмента кода, адресуемого сегментным регистром CS . При обработке транслятором очередной команды ассемблера счетчик адреса увеличивается на длину сформированной машинной команды. Обработка директив ассемблера не влечет за собой изменения счетчика. В качестве примера использования в команде значения счетчика адреса можно привести следующий фрагмент:
При использовании подобного выражения для перехода нельзя забывать о длине самой команды, в которой это выражение используется, так как значение счетчика адреса соответствует смещению в сегменте кода данной, а не следующей за ней команды. В приведенном выше примере команда jmp занимает 2 байта. Длина этой и некоторых других команд может зависит от того, какие в ней используются операнды. Команда с регистровыми операндами будет короче команды, один из операндов которой расположен в памяти. В большинстве случаев эту информацию можно получить, зная формат машинной команды.
Структурные операнды используются для доступа к конкретному элементу сложного типа данных, называемого структурой.
Записи (аналогично структурному типу) используются для доступа к битовому полю некоторой записи. Для доступа к битовому полю записи используется директива RECORD .
Операторы в языке ассемблера
Операнды являются элементарными компонентами, из которых формируется часть машинной команды, обозначающая объекты, над которыми выполняется операция. В более общем случае операнды могут входить как составные части в более сложные образования, называемые выражениями . Выражения представляют собой комбинации операндов и операторов , рассматриваемые как единое целое. Результатом вычисления выражения может быть адрес некоторой ячейки памяти или некоторое константное (абсолютное) значение.
Выполнение операторов ассемблера при вычислении выражений осуществляется в соответствии с их приоритетами. Операции с одинаковыми приоритетами выполняются последовательно слева направо. Изменение порядка выполнения возможно путем расстановки круглых скобок, которые имеют наивысший приоритет.
| Приоритет | Оператор |
| 1 | length, size, width, mask, ( ), [ ], < > |
| 2 | . |
| 3 | : |
| 4 | ptr, offset, seg, 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 |
Характеристика основных операторов.
Арифметические операторы . К ним относятся унарные операторы + и —, бинарные + и —, операторы умножения *, целочисленного деления /, получения остатка от деления mod. Например,
Операторы сдвига выполняют сдвиг выражения на указанное количество разрядов. Например,
Операторы сравнения (возвращают значение истина или ложь) предназначены для формирования логических выражений. Логическое значение истина соответствует логической единице, а ложь – логическому нулю. Логическая единица – значение бита равное 1, логический ноль – значение бита, равное 0.
Если значение size больше или равно 50, то результат в аl равен 1, в противном случае — 0. Команда cmp сравнивает значение аl с нулем и устанавливает соответствующие флаги в EFLAGS . Команда je на основе анализа этих флагов передает или не передает управление на метку m1 .
Назначение операторов сравнения приведено в таблице
| Оператор | Условие |
| eq | == |
| ne | != |
| lt | < |
| le | <= |
| gt | > |
| ge | >= |
Логические операторы выполняют над выражениями побитовые операции. Выражения должны быть константными. Например,
Индексный оператор [ ]. Транслятор воспринимает наличие квадратных скобок как указание сложить значение выражения за [] со значением выражения, заключенным в скобки. Например,
Наличие индексного оператора указывает транслятору, что необходимо получить значение по вычисленному адресу.
Оператор переопределения типа ptr применяется для переопределения или уточнения типа метки или переменной, определяемых выражением. Тип может принимать одно из следующих значений.
| Тип | Пояснение | Назначение |
| byte | 1 байт | переменная |
| word | 2 байта | переменная |
| dword | 4 байта | переменная |
| qword | 8 байт | переменная |
| tword | 10 байт | переменная |
| near | ближний указатель | функция |
| far | дальний указатель | функция |
В примере для сравнения значения по адресу esi с константой необходимо явно указать, данные какого типа будут сравниваться.
Оператор переопределения сегмента : (двоеточие) вычисляет физический адрес относительно конкретно задаваемой сегментной составляющей, в качестве которой могут выступать:
- имя сегментного регистра,
- имя сегмента из соответствующей директивы SEGMENT
- имя группы.
Для выборки на выполнение очередной команды микропроцессор анализирует содержимое сегментного регистра CS , в котором содержится физический адрес начала сегмента кода. Для получения адреса конкретной команды микропроцессор складывает промасштабированное (умноженное на 16) значение сегментного регистра CS с содержимым регистра EIP . Запись CS:EIP содержит адрес текущей выполняемой команды. Аналогично обрабатываются операнды в машинных командах.
Оператор именования типа структуры . (точка) также заставляет транслятор производить определенные вычисления, если встречается в выражении.
Оператор получения сегментной составляющей адреса выражения seg возвращает физический адрес сегмента для выражения, в качестве которого могут выступать метка, переменная, имя сегмента, имя группы или некоторое символическое имя.
Оператор получения смещения выражения offset позволяет получить значение смещения выражения в байтах относительно начала того сегмента, в котором выражение определено. Например,
Оператор определения длины массива length возвращает число элементов, определенных операндом dup . Если операнд dup отсутствует, то оператор length возвращает значение 1.Например,
Оператор type возвращает число байтов, соответствующее определению указанной переменной:
Оператор size возвращает произведение длины length и типа type и используется при ссылках на переменную с операндом dup .
Для предыдущего примера
Оператор short –модификация атрибута near в команде jmp, если переход не превышает границы +127 и -128 байт. Например,
В результате ассемблер сокращает машинный код операнда от двух до одного байта. Эта возможность оказывается полезной для коротких переходов вперед, так как в этом случае ассемблер не может сам определить расстояние до адреса перехода и резервирует два байта при отсутствии оператора short .
Оператор width возвращает размер в битах объекта типа RECORD или его поля.