Что такое операнды в ассемблере
Операнды в языке ассемблера
Операнд – объект, над которым выполняется машинная команда.
Операнды ассемблера описываются выражениями с числовыми и текстовыми константами, метками и идентификаторами переменных с использованием знаков операций и некоторых зарезервированных слов.
Операнды могут комбинироваться с арифметическими, логическими, побитовыми и атрибутивными операторами для расчета некоторого значения или определения ячейки памяти, на которую будет воздействовать данная команда или директива.
Способы адресации операндов
Под способами адресации понимаются существующие способы задания адреса хранения операндов:
Операнд задается на микропрограммном уровне (операнд по умолчанию): в этом случае команда явно не содержит операнда, алгоритм выполнения команды использует некоторые объекты по умолчанию (регистры, признаки и т.д.).
Операнд задается в самой команде (непосредственный операнд): операнд является частью кода команды. Для хранения такого операнда в команде выделяется поле длиной до 32 бит. Непосредственный операнд может быть только вторым операндом (источником). Операнд-получатель может находиться либо в памяти, либо в регистре.
Операнд находится в одном из регистров (регистровый операнд): в коде команды указываются именами регистров. В качестве регистров могут использоваться:
Прямая адресация : эффективный адрес определяется непосредственно полем смещения машинной команды, которое может иметь размер 8, 16 или 32 бита.
Косвенная адресация в свою очередь имеет следующие виды:
Косвенная базовая (регистровая) адресация. При такой адресации эффективный адрес операнда может находиться в любом из регистров общего назначения, кроме sp/esp и bp/ebp (это специфические регистры для работы с сегментом стека). Синтаксически в команде этот режим адресации выражается заключением имени регистра в квадратные скобки [].
Данный способ адресации позволяет динамически назначить адрес операнда для некоторой машинной команды и применяется при организации циклических вычислений и при работе со структурами данных, массивами.
Косвенная базовая (регистровая) адресация со смещением предназначена для доступа к данным с известным смещением относительно некоторого базового адреса, используется для доступа к элементам структур, когда смещение элементов известно заранее, на стадии разработки программы, а базовый (начальный) адрес структуры должен вычисляться динамически, на стадии выполнения программы. Модификация содержимого базового регистра позволяет обратиться к одноименным элементам различных экземпляров однотипных структур данных.
Косвенная индексная адресация. Для формирования эффективного адреса используется один из регистров общего назначения, но обладает возможностью масштабирования содержимого индексного регистра.
Значение эффективного адреса второго операнда вычисляется выражением mas+( esi *4) и представляет собой смещение относительно начала сегмента данных.
Наличие возможности масштабирования существенно помогает в решении проблемы индексации при условии, что размер элементов массива постоянен и составляет 1, 2, 4 или 8 байт.
Данный вид адресации также может использоваться со смещением.
Косвенная базовая индексная адресация. Эффективный адрес формируется как сумма содержимого двух регистров общего назначения: базового и индексного. В качестве этих регистров могут применяться любые регистры общего назначения, при этом часто используется масштабирование содержимого индексного регистра.
В случае использования косвенной базовой индексной адресация со смещением эффективный адрес формируется как сумма трех составляющих: cодержимого базового регистра, cодержимого индексного регистра и значения поля смещения в команде.
При использовании подобного выражения для перехода нельзя забывать о длине самой команды, в которой это выражение используется, так как значение счетчика адреса соответствует смещению в сегменте кода данной, а не следующей за ней команды. В приведенном выше примере команда jmp занимает 2 байта. Длина этой и некоторых других команд может зависит от того, какие в ней используются операнды. Команда с регистровыми операндами будет короче команды, один из операндов которой расположен в памяти. В большинстве случаев эту информацию можно получить, зная формат машинной команды.
Операторы в языке ассемблера
Операнды являются элементарными компонентами, из которых формируется часть машинной команды, обозначающая объекты, над которыми выполняется операция. В более общем случае операнды могут входить как составные части в более сложные образования, называемые выражениями . Выражения представляют собой комбинации операндов и операторов , рассматриваемые как единое целое. Результатом вычисления выражения может быть адрес некоторой ячейки памяти или некоторое константное (абсолютное) значение.
Выполнение операторов ассемблера при вычислении выражений осуществляется в соответствии с их приоритетами. Операции с одинаковыми приоритетами выполняются последовательно слева направо. Изменение порядка выполнения возможно путем расстановки круглых скобок, которые имеют наивысший приоритет.
Характеристика основных операторов.
Операторы сдвига выполняют сдвиг выражения на указанное количество разрядов. Например,
Операторы сравнения (возвращают значение истина или ложь) предназначены для формирования логических выражений. Логическое значение истина соответствует логической единице, а ложь – логическому нулю. Логическая единица – значение бита равное 1, логический ноль – значение бита, равное 0.
Назначение операторов сравнения приведено в таблице
Оператор | Условие |
eq | == |
ne | != |
lt | |
ge | >= |
Логические операторы выполняют над выражениями побитовые операции. Выражения должны быть константными. Например,
Индексный оператор [ ]. Транслятор воспринимает наличие квадратных скобок как указание сложить значение выражения за [] со значением выражения, заключенным в скобки. Например,
Наличие индексного оператора указывает транслятору, что необходимо получить значение по вычисленному адресу.
Оператор переопределения типа ptr применяется для переопределения или уточнения типа метки или переменной, определяемых выражением. Тип может принимать одно из следующих значений.
Тип | Пояснение | Назначение |
byte | 1 байт | переменная |
word | 2 байта | переменная |
dword | 4 байта | переменная |
qword | 8 байт | переменная |
tword | 10 байт | переменная |
near | ближний указатель | функция |
far | дальний указатель | функция |
В примере для сравнения значения по адресу esi с константой необходимо явно указать, данные какого типа будут сравниваться.
Оператор переопределения сегмента : (двоеточие) вычисляет физический адрес относительно конкретно задаваемой сегментной составляющей, в качестве которой могут выступать:
Оператор именования типа структуры . (точка) также заставляет транслятор производить определенные вычисления, если встречается в выражении.
Оператор получения сегментной составляющей адреса выражения seg возвращает физический адрес сегмента для выражения, в качестве которого могут выступать метка, переменная, имя сегмента, имя группы или некоторое символическое имя.
Оператор получения смещения выражения offset позволяет получить значение смещения выражения в байтах относительно начала того сегмента, в котором выражение определено. Например,
Оператор type возвращает число байтов, соответствующее определению указанной переменной:
Оператор width возвращает размер в битах объекта типа RECORD или его поля.
Что такое операнды в ассемблере
Справочная система по языку Assembler
Структура машинной команды
Способы задания операндов команды
Операнд задается неявно на микропрограммном уровне. В этом случае команда явно не содержит операндов. Алгоритм выполнения команды использует некоторые объекты по умолчанию (регистры, флаги в eflags и т. д.).
Например, команды cli и sti неявно работают с флагом прерывания if в регистре eflags, а команда xlat неявно обращается к регистру al и строке в памяти по адресу, определяемому парой регистров ds:bx.
Операнд задается в самой команде (непосредственный операнд). Операнд находится в коде команды, то есть является ее частью. Для хранения такого операнда в команде выделяется поле длиной до 32 бит (см. рис. 1). Непосредственный операнд может быть только вторым операндом (источником). Операнд получатель может находиться либо в памяти, либо в регистре.
Например: mov ax,0ffffh пересылает в регистр ax шестнадцатеричную константу ffff. Команда add sum,2 складывает содержимое поля по адресу sum с целым числом 2 и записывает результат по месту первого операнда, то есть в память.
Операнд располагается в памяти. Это наиболее сложный и в то жe время наиболее гибкий способ задания операндов. Он позволяет реализовать следующие два основных вида адресации: прямую и косвенную.
Прямая адресация
Косвенная базовая (регистровая) адресация
Косвенная базовая (регистровая) адресация со смещением
Косвенная индексная адресация со смещением
Косвенная базовая индексная адресация
Косвенная базовая индексная адресация со смещением
Этот вид адресации является дополнением косвенной индексной адресации. Эффективный адрес формируется как сумма трех составляющих: cодержимого базового регистра, cодержимого индексного регистра и значения поля смещения в команде.
К примеру, команда mov eax,[esi+5][edx] пересылает в регистр eax двойное слово по адресу: (esi) + 5 + (edx).
Команда add ax,array[esi][ebx] производит сложение содержимого регистра ax с содержимым слова по адресу: значение идентификатора array + (esi) + (ebx).
Что такое операнды в ассемблере
Справочная система по языку Assembler
Структура программы на ассемблере
Синтаксис ассемблера
Рис. 1. Формат предложения ассемблера
Рис. 2. Формат директив
Рис. 3. Формат команд и макрокоманд
Практически каждое предложение содержит описание объекта, над которым или при помощи которого выполняется некоторое действие. Эти объекты называются операндами.
Их можно определить так:
операнды — это объекты (некоторые значения, регистры или ячейки памяти), на которые действуют инструкции или директивы, либо это объекты, которые определяют или уточняют действие инструкций или директив.
Операнды могут комбинироваться с арифметическими, логическими, побитовыми и атрибутивными операторами для расчета некоторого значения или определения ячейки памяти, на которую будет воздействовать данная команда или директива.
Рис. 4. Синтаксис описания адресных операндов
Результатом вычисления выражения может быть адрес некоторой ячейки памяти или некоторое константное (абсолютное) значение.
Рис. 7. Синтаксис операторов сравнения
Таблица 1. Операторы сравнения
Рис. 9. Синтаксис индексного оператора
Заметим, что в литературе по ассемблеру принято следующее обозначение: когда в тексте речь идет о содержимом регистра, то его название берут в круглые скобки. Мы также будем придерживаться этого обозначения.
К примеру, в нашем случае запись в комментариях последнего фрагмента программы mas + (si) означает вычисление следующего выражения: значение смещения символического имени mas плюс содержимое регистра si.
Рис. 13. Синтаксис оператора получения смещения
Как и в языках высокого уровня, выполнение операторов ассемблера при вычислении выражений осуществляется в соответствии с их приоритетами (см. табл. 2). Операции с одинаковыми приоритетами выполняются последовательно слева направо. Изменение порядка выполнения возможно путем расстановки круглых скобок, которые имеют наивысший приоритет.
Таблица 2. Операторы и их приоритет
Директивы сегментации
Синтаксическое описание сегмента на ассемблере представляет собой конструкцию, изображенную на рис. 14:
Рис. 14. Синтаксис описания сегмента
Рис. 15. Директива ASSUME
На уроке 3 мы рассматривали пример программы с директивами сегментации. Эти директивы изначально использовались для оформления программы в трансляторах MASM и TASM. Поэтому их называют стандартными директивами сегментации.
В листинге 1 приведен пример программы с использованием упрощенных директив сегментации:
Синтаксис директивы MODEL показан на рис. 16.
Рис. 16. Синтаксис директивы MODEL
Обязательным параметром директивы MODEL является модель памяти. Этот параметр определяет модель сегментации памяти для программного модуля. Предполагается, что программный модуль может иметь только определенные типы сегментов, которые определяются упомянутыми нами ранее упрощенными директивами описания сегментов. Эти директивы приведены в табл. 3.
Таблица 3. Упрощенные директивы определения сегмента
Формат директивы (режим MASM) | Формат директивы (режим IDEAL) | Назначение |
.CODE [имя] | CODESEG[имя] | Начало или продолжение сегмента кода |
.DATA | DATASEG | Начало или продолжение сегмента инициализированных данных. Также используется для определения данных типа near |
.CONST | CONST | Начало или продолжение сегмента постоянных данных (констант) модуля |
.DATA? | UDATASEG | Начало или продолжение сегмента неинициализированных данных. Также используется для определения данных типа near |
.STACK [размер] | STACK [размер] | Начало или продолжение сегмента стека модуля. Параметр [размер] задает размер стека |
.FARDATA [имя] | FARDATA [имя] | Начало или продолжение сегмента инициализированных данных типа far |
.FARDATA? [имя] | UFARDATA [имя] | Начало или продолжение сегмента неинициализированных данных типа far |
При использовании директивы MODEL транслятор делает доступными несколько идентификаторов, к которым можно обращаться во время работы программы, с тем, чтобы получить информацию о тех или иных характеристиках данной модели памяти (см. табл. 5). Перечислим эти идентификаторы и их значения (табл. 4).
Таблица 4. Идентификаторы, создаваемые директивой MODEL
Имя идентификатора | Значение переменной |
@code | Физический адрес сегмента кода |
@data | Физический адрес сегмента данных типа near |
@fardata | Физический адрес сегмента данных типа far |
@fardata? | Физический адрес сегмента неинициализированных данных типа far |
@curseg | Физический адрес сегмента неинициализированных данных типа far |
@stack | Физический адрес сегмента стека |
Таблица 5. Модели памяти
Таблица 6. Модификаторы модели памяти
Значение модификатора | Назначение |
use16 | Сегменты выбранной модели используются как 16-битные (если соответствующей директивой указан процессор i80386 или i80486) |
use32 | Сегменты выбранной модели используются как 32-битные (если соответствующей директивой указан процессор i80386 или i80486) |
dos | Программа будет работать в MS-DOS |
Описанные нами стандартные и упрощенные директивы сегментации не исключают друг друга. Стандартные директивы используются, когда программист желает получить полный контроль над размещением сегментов в памяти и их комбинированием с сегментами других модулей.
Упрощенные директивы целесообразно использовать для простых программ и программ, предназначенных для связывания с программными модулями, написанными на языках высокого уровня. Это позволяет компоновщику эффективно связывать модули разных языков за счет стандартизации связей и управления.
Что такое операнды в ассемблере
При изучении данной темы мы рассмотрим всего три типа операндов, которые могут встречаться в любой команде: непосредственно заданное значение (immediate), регистр (register) и память (memory). Из всех перечисленных здесь типов только последний (память) довольно труден для освоения. Список условных обозначений возможных типов операндов, взятых из руководства фирмы Intel по процессору Pentium, приведен в табл. 1. Довайте изучим его, поскольку с этого момента мы будем активно пользоваться этими обозначениями при описании синтаксиса команд процессоров Intel.
Таблица 1. Условное обозначение типов операндов.
Один из 8-разрядных регистров общего назначения: АН, AL, BH, BL, CH, CL, DH, DL
Один из 16-разрядных регистров общего назначения: АХ, BX, СХ, DX, SI, DI, SP, BP
Один из 32-разрядных регистров общего назначения: ЕАХ, ЕВХ, ЕСХ, EDX, ESI, EDI, ESP, EBP
Произвольный регистр общего назначения
Один из 16-разрядных сегментных регистров: CS, DS, SS, ES, FS, GS
Непосредственно заданное 8-разрядное значение (байт)
Непосредственно заданное 16-разрядное значение (слово)
Непосредственно заданное 32-разрядное значение (двойное слово)
Непосредственно заданное 8-, 16- или 32-разрядное значение
8-разрядный операнд, в котором закодирован один из 8-разрядных регистров общего назначения или адрес байта в памяти
16-разрядный операнд, в котором закодирован один из 16-разрядных регистров общего назначения или адрес слова в памяти
32-разрядный операнд, в котором закодирован один из 32-разрядных регистров общего назначения или адрес двойного слова в памяти
Адрес 8-, 16- или 32-разрядного операнда в памяти
Команда MOV копирует данные из операнда-источника в операнд-получатель. Она относится к группе команд пересылки данных (data transfer) и используется в любой программе. Команда MOV является двуместной (т.е. имеет два операнда): первый операнд определяет получателя данных (destination), а второй — источник данных (source):
При выполнении этой команды изменяется содержимое операнда-получателя, а содержимое операнда-источника не меняется. Принцип пересылки данных справа налево соответствует принятому в операторах присваивания языков высокого уровня, таких как C ++:
Практически во всех командах ассемблера операнд-получатель находится слева, а операнд-источник— справа.
В команде MOV могут использоваться самые разные операнды. Кроме того, необходимо учитывать следующие правила и ограничения:
1. Оба операнда должны иметь одинаковую длину.
2. В качестве одного из операндов обязательно должен использоваться регистр (т.е. пересылки типа «память-память» в команде MOV не поддерживаются).
4. Нельзя переслать непосредственно заданное значение в сегментный регистр.
Ниже приведены варианты использования команды MOV с разными операндами (кроме сегментных регистров):
Сегментные регистры в команде MOV обычно используются только в программах, написанных для реального или виртуального режимов работы процессора. При этом могут существовать следующие ее формы (следует учитывать, что регистр CS нельзя указывать в качестве получателя данных):
Пересылка типа «память—память». С помощью одной команды MOV нельзя напрямую переслать операнд из одной области памяти в другую. Поэтому вначале нужно загрузить исходное значение в один из регистров общего назначения, а затем переслать его в нужное место памяти.
При записи целочисленной константы в переменную или загрузке ее в регистр нужно не забывать про ее минимальную длину в байтах.
Команда MOVZX (Move With Zero-Extend, или Переместить и дополнить нулями) копирует содержимое исходного операнда в больший по размеру регистр получателя данных. При этом оставшиеся неопределенными биты регистра-получателя (как правило, старшие 16 или 24 бита) сбрасываются в ноль. Эта команда используется только при работе с беззнаковыми целыми числами. Существует три варианта команды MOVZX:
Условные обозначения операндов этой команды приведены в табл. 1. В каждом из приведенных трех вариантов первый операнд является получателем, а второй — источником данных. В качестве операнда-получателя может быть задан только 16- или 32-разрядный регистр. На рис. 8 показано, как 8-разрядный исходный операнд загружается с помощью команды MOVZX в 16-разрядный регистр.
Рис. 8. Иллюстрация работы команды MOVZX.
В приведенном ниже примере используются все три варианта команды MOVZX с разными размерами операндов.
movzx eax, bx ; EAX = 0000A69Bh
movzx edx, bl ; EDX = 0000009Bh
movzx cx, bl ; CX = 009Bh
А в следующем примере в качестве исходного операнда используются переменные разной длины, расположенные в памяти, но полученный результат будет идентичен предыдущему примеру.
short word1 = 0xA69B;
MOVSX r 32, r / m 16
Рис. 9. Иллюстрация работы команды MOVSX.
В приведенном ниже примере используются все три варианта команды MOVSX с разными размерами операндов.
movsx eax, bx ; EAX = FFFFA69Bh
movsx edx, bl ; EDX = FFFFFF9Bh
movsx cx, bl ; CX = FF9Bh