Ушел с форума
Автор FAQ
 Аватар для Mikl___
16373 / 7685 / 1080
Регистрация: 11.11.2010
Сообщений: 13,759
10.11.2013, 18:47  [ТС]
ГЛАВА 6
СИНТАКСИС АССЕМБЛЕРА
(часть 3/3)


Директивы эквивалентности и присваивания
Директива эквивалентности
Допустим, Вы пишете на языке ассемблера компьютерную игрушку. Через какое-то время Вам понадобилось изменить правила игры и повысить или понизить порог очков (100), после превышения которого партия считается оконченной. Число 100 упоминается несколько раз в разных местах Вашего файла, и постоянно менять все операторы довольно хлопотно. Замену нельзя выполнить автоматической командой текстового редактора «найти и заменить», так как число 100 может встречаться в разных местах программы и обозначать не только предел набранных очков. Поэтому лучше всего описать число 100 как константу и в дальнейшем обращаться к ней по имени. В языке ассемблера используют константы, которые подобно переменным имеют имена. Единственное их отличие от переменных заключается в том, что им нельзя присвоить новое значение во время выполнения программы. Имя константы может быть более выразительным и в ряде случаев более коротким, чем ее значение. При многократном использовании такой константы в программе экономится время набора текста программы. Изменение значения именованной константы связано с изменением только одного оператора, тогда как в случае использования числовых значений этой константы такое исправление пришлось бы делать многократно.
Константы в языке ассемблера описывают с помощью директивы EQU (EQUAL, равно).
Синтаксис директивы: <имя> EQU <операнд>
Обязательно должны быть указаны имя и операнд, причем только один. Директивой EQU автор программы заявляет, что указанному операнду он дает указанное имя и требует, чтобы все вхождения данного имени в текст программы ассемблер заменял на этот операнд. Например, если есть директива STAR EQU ‘*’, то ассемблер будет рассматривать предложение N DB STAR как предложение N DB ‘*’, другими словами, STAR и ‘*’ — это одно и то же. Директива EQU носит чисто информационный характер и по нему ассемблер ничего не записывает в конечную программу. Поэтому директиву EQU можно ставить в любое место программы.
Операнд — имя
Если в правой части директивы указано имя регистра, переменной, константы и тому подобное, тогда имя слева объявляется синонимом данного имени и все последующие вхождения в текст программы этого имени-синонима ассемблер будет заменять на имя, указанное справа.
Пример:
Assembler
1
2
3
A DW ?
B EQU A
C DW B ; эквивалентно C DW A
Имена-синонимы обычно используются для введения более удобных и наглядных обозначений.
Операнд — константное выражение
Пример:
Assembler
1
2
3
N EQU 100
K EQU 2*N-1;К=199
P EQU ’A’
Если в правой части директивы EQU стоит константное выражение, тогда указанное слева имя принято называть именем константы. Значением этой константы объявляется значение выражения. N — это константа со значением 100, K — со значением 199, P — со значением 41h (это код буквы ‘A’ в системе ASCII). Все последующие вхождения в текст программы имени константы ассемблер будет заменять на значение этой константы.
Например, директива
X DB N DUP(?)
эквивалентна директиве
X DB 100 DUP(?)
Случаи, когда полезно применение констант, такие же, как в языках высокого уровня. Например, в качестве констант рекомендуется описывать размеры массивов, поскольку в таком случае легко настроить программу на работу с массивом любого другого размера — для этого достаточно внести изменение лишь в директиву EQU, описывающую константу. Если в константном выражении используются имена других констант, то они (эти константы) должны быть описаны раньше данной директивы EQU, иначе ассемблер, просматривающий текст программы сверху вниз, не сможет вычислить значение этого выражения.
Операнд — любой другой текст
Пример:
Assembler
1
2
3
S EQU ’Вы ошиблись’
LX EQU X+(N-1)
WP EQU WORD PTR
В данном случае считается, что указанное имя обозначает операнд в том виде, как он записан (операнд не вычисляется). Именно на этот текст и будет заменяться каждое вхождение данного имени в программе. Например, следующие предложения будут эквивалентны предложениям справа:
Assembler
1
2
3
ANS DB S,’!’ ANS DB ’Вы ошиблись!’
NEG LX NEG X+(N-1)
INC WP [BX] INC WORD PTR [BX]
Такой вариант директивы EQU обычно используется для того, чтобы ввести более короткие обозначения для часто встречающихся длинных текстов. Текст, указанный в правой части директивы EQU, должен быть сбалансирован по скобкам и кавычкам и не должен содержать вне скобок и кавычек символа «;». Поскольку текст не вычисляется, то в нем можно использовать как имена, описанные до этой директивы EQU, так и имена, описанные после нее.
Директива присваивания «=»
Синтаксис директивы: <имя> = <константное выражение>
Эта директива определяет константу с именем, указанным в левой части, и с числовым значением, равным значению выражения справа. В отличие от констант, определенных по директиве EQU, данная константа может менять свое значение, обозначая в разных частях текста программы разные числа.
Пример:
Assembler
1
2
3
4
K=10
A DW K ;эквивалентно A DW 10
K=K+4
B DW K ;эквивалентно B DW 14
Подобного рода константы используют ради «экономии имен»: если в разных частях программы используются разные константы и области использования этих констант не пересекаются, тогда, чтобы не придумывать новые имена, этим константам можно дать одно и тоже имя.
Целочисленные выражения
Операнды являются элементарными компонентами, из которых формируется часть машинной команды, обозначающая объекты, над которыми выполняется операция. В более общем случае операнды могут входить в более сложные образования, называемые выражениями. Целочисленные выражения представляют собой комбинации целочисленных значений и операторов, рассматриваемые как единое целое. Результатом целочисленных вычислений выражения может быть адрес некоторой ячейки памяти или некоторое константное (абсолютное) значение. В процессе вычисления выражения получается 32-битное число, в диапазоне от 0 до 0FFFFFFFFh.
  • Арифметические операторы с учетом порядка их выполнения — от старшего к младшему: скобки «(» и «)»; одноместные (унарные) «+» и «-» (знак числа); оператор умножения «*», целочисленного деления «/», получения остатка от деления «MOD»; двухместные (бинарные) «+» и «-» (операторы сложения и вычитания).
    Пример:
    Assembler
    1
    2
    3
    4
    
    TAB_SIZE EQU 50 ;размер массива в байтах
    SIZE_EL EQU 2 ;размер элементов
    ;вычисляется число элементов массива и заносится в CX
    MOV CX,TAB_SIZE/SIZE_EL ;оператор «/»
    Порядок выполнения операторов учитывается в сложных выражениях, состоящих из нескольких арифметических операторов.
    Assembler
    1
    2
    3
    4
    
    4 + 5 * 2 ;Сначала умножение, затем сложение
    121 MOD 5 ;Сначала остаток от деления, затем вычитание
    -5 + 2 ;Сначала унарный минус, затем сложение
    (4 + 2)* 6 ;Сначала сложение в скобках, затем умножение
    Выражение Значение, которое подставит компилятор
    16/5 3
    –(3+4)*(6–1) –35
    –3+4*6–1 20
    25 mod 3 1
    Таблица 6.2.4
  • Операторы сдвига SHL, SHR выполняют сдвиг выражения на указанное количество разрядов. Если указанное число отрицательное, то SHL будет заменен на SHR, а сдвиг произведен на модуль числа.
    Пример:
    Assembler
    1
    2
    
    MASK_B EQU 10111011B
    MOV AL,MASK_B SHR 3 ;AL=00010111B
  • Операторы сравнения EQ, NE, LT, LE, GT, GE (возвращают значение «истина» или «ложь») предназначены для формирования логических выражений.
    Пример:
    Assembler
    1
    2
    3
    4
    5
    
    TAB_SIZE EQU 30 ;размер таблицы
    MOV AL,TAB_SIZE GE 50 ;сравнение размера таблицы с 50
    ;и загрузка в AL в случае меньшего значения 0
    CMP AL,0 ;если TAB_SIZE < 50, то
    JE M1 ;переход на M1
  • Логические операторы NOT AND OR, XOR выполняют над выражениями побитовые операции.
    Пример:
    Assembler
    1
    2
    3
    
    FLAGS EQU 10010011B
    MOV AL,FLAGS XOR 01B ;AL=10010010 b; пересылка в AL
    ;поля FLAGS с инвертированным правым битом
  • Индексный оператор [ ]. Транслятор воспринимает квадратные скобки как указание сложить значение перед скобками с выражением, находящимся внутри скобок.
    Пример:
    Assembler
    1
    
    MOV EAX,MAS[ESI] ;пересылка слова по адресу MAS+[ESI] в регистр EAX
  • Оператор переопределения типа PTR применяется для временного переопределения или уточнения типа метки или переменной, определяемой выражением. Тип может принимать одно из следующих значений: BYTE, WORD, DWORD, QWORD, TBYTE, NEAR, FAR.
  • Оператор переопределения сегмента «:» (двоеточие) заставляет вычислять физический адрес относительно конкретно задаваемой сегментной составляющей: «имя сегментного регистра», «имя сегмента» из соответствующей директивы SEGMENT или «имя группы».
  • Оператор именования типа структуры «.» (точка).
  • Оператор получения сегментной составляющей адреса выражения SEG возвращает физический адрес сегмента для выражения, в качестве которого могут выступать метка, переменная, имя сегмента, имя группы или некоторое символическое имя.
  • Оператор получения смещения выражения OFFSET позволяет получить значение смещения выражения в байтах относительно того сегмента, в котором выражение определено.
Выполнение операторов ассемблера при вычислении выражений осуществляется в соответствии с их приоритетами. Операции с одинаковыми приоритетами выполняются последовательно слева направо. Изменение порядка выполнения возможно путем расстановки круглых скобок, которые имеют наивысший приоритет.
В таблице указаны операторы ассемблера в порядке убывания старшинства.
Операторы ассемблера в порядке убывания старшинства
 Операторы с равным старшинством
1 (), [], <>, LENGTH, SIZE, WIDTH, MASK
2 .
3 :
4 PTR, OFFSET, SEG, TYPE, THIS
5 HIGH, LOW
6 Одноместные (унарные) + и -
7 *, /, MOD, SHL, SHR
8 Двухместные (бинарные) + и -
9 EQ, NE, LT, LE, GT, GE
10 NOT
11 AND
12 OR, XOR
13 SHORT, TYPE
Таблица 6.2.5
Константные выражения
Значениями константных выражений всегда являются 32-битовые целые числа (исключениями являются директивы DQ, DF, DP, DT, которыми можно явно указывать 32-битовые и более числа).
К простейшим константным выражениям относятся:
  • числа от –231 до 232–1;
  • символ (значением такого выражения является код символа);
  • строка из двух символов (значением является слово-число, составленное из кодов этих символов);
  • имя константы (значением такого выражения является значение константы).
К константным выражениям применимы следующие арифметические операторы (k, k1 и k2 означают любые константные выражения):
  • одноместные плюс и минус +k, –k;
  • операторы сложения и вычитания k1+k2, k1–k2;
  • оператор умножения k1*k2, целочисленного деления k1/k2, получения остатка от деления k1 MOD k2.
Пример: K EQU 30
X DB (3*K-1)/2 DUP(?) ;массив из 44 байтов
Операндами арифметических операторов должны быть константные выражения. Язык ассемблер разрешает вычитать один адрес из другого, в результате Вы получите число, а не адрес.
Пример: X DW 1,2,3,4,5
Y DB ?
SIZE_X EQU Y-X ;SIZE_X=10
Вычитание адресов используется обычно для определения расстояния (числа байтов) между этими адресами. Результатом действия арифметических операторов на константные выражения будет 32-битное число. Например: 2*80000000h=00000000h а не 100000000h.
Адресные выражения
Значениями адресных выражений являются 32-битовые адреса.
К простейшим адресным выражениям относятся:
  • метка (имя команды) и имя переменной, описанное в директиве DB, DW или DD (значениями таких выражений являются адреса меток и имен);
  • счетчик размещения; он записывается как $ и обозначает адрес того предложения, в котором он встретился. В разных предложениях $ обозначает разные адреса. Например, если адрес переменной A равен 400100h, то имеем:
A DD $ ;эквивалентно A DD 400100h
B DD $ ;эквивалентно B DD 400104h
Чаще всего счетчик размещения используется для вычисления размера памяти занимаемой каким-то массивом.
Пример: X DW 40 DUP(?)
SIZE_X EQU $-X ;SIZE_X = 80
Здесь $ обозначает адрес первого байта за массивом X, из этого адреса и вычитается начальный адрес массива.

Мнемоника команд MMX, SSE, SSE2
Когда разберёшься как по какому принципу строятся мнемонические команды — тогда всё станет легко. Вот что присутствует в мнемонике:
SIMD для работы с вещественными числами:
[h] — horizontal операции
op — код операции
[op] — код операции2 для сложных инструкций
[L|h] — обозначает какая часть приёмника/источника подвержена операции op: low|high
[[L|h]] — если присутствует, то обозначает куда будет помещён результат операции op в зависимости от предыдущей мнемоники.
Возможно: L->h, h->L
[a|u] — aligned|unaligned. Говорит о требованиях к выравниванию операнда(ов) в памяти: a — выравнивание на границу в 16 байт требуется, u — не требуется
[nt] — non temporal. Говорит о некэшируемости операндов в памяти
[s|p] — scalar/packed операция op над данными (для h префикса только p)
s|d — single/double precision. Размерность данных в операндах.
(float/double)
[2] — «to». Возникает при операциях op конвертации.
[s|p] — scalar/packed вид данных операнда. Возникает 2-й раз в операциях конвертации после «2»
[s|d] — single/double precision. Размерность данных в операндах.
(float/double). Возникает 2-й раз в операциях конвертации после «2» и вида данных операции op
[[h|L]] — high|low. Присутствует, если используется мнемоника DUP
(смотри ниже). Указывает расположение данных в операндах источниках для выполнения операции op
[dup] — duplicate. Может возникнуть при дублировании частей операндов источников в операнде приёмнике после выполнении операции op
Примеры: addps, haddps, addsubpd, movhlps, andps, movaps, movntpd, movshdup...
SIMD для работы с целыми числами:
[p] — packed. Присутствует всегда за исключением малого количества некоторых операций op
[h] — horizontal операции
op — код операции
[op] — код операции2 в сложных операциях
[s|us] — signed|unsigned saturation. Тип насыщение при операции op: знаковое|беззнаковое. Если отсутствует, то без насыщения (wrap around арифметика)
[L|h] — low|high. Обозначает, какая часть приёмника/источника подвержена операции op
[nt] — non temporal. Говорит о некэшируемости операндов в памяти
[b|w|d|q|dq] — byte|word|dword|qword|dqword. Размер упакованных операндов источников
[[2]] — «to». Может возникнуть при операции op над данными при разных типах операндов источника и приёмника: MMX и XMM регистров. «2» говорит о направлении действия операции op над данными. Возможно: Q2DQ, DQ2Q
[[b|w|d|q|dq]] — byte|word|dword|qword|dqword. Размер упакованных данных операции op. Осуществляется преобразование от меньшей разрядности операций (смотри предыдущую мнемонику) к большей (см. эту). Возможно от b->w, w->d, d->q... Если отсутствует, то размер результата упакованных данных остаётся неизменным (т.е. см. предыдущую мнемонику)
[a|u] — aligned|unaligned. Говорит о требованиях к выравниванию операнда(ов) в памяти: a — выравнивание на границу в 16 байт требуется, u — не требуется
Примеры: paddb, phsubw, psubusb, punpckhbw, pand, movntdqa, movdqu...
Контрольные вопросы
  1. Какие из следующих имен не могут быть идентификатором?:
    1. C,
    2. $50,
    3. @$_Z,
    4. 34B7,
    5. AX
  2. Какова длина в байтах для элементов данных, определенных директивами:
    1. DW,
    2. DD,
    3. DT,
    4. DB,
    5. DQ?
  3. Перечислите допустимые спецификаторы, которые могут встречаться при описании чисел в ассемблере.
  4. Определите символьную строку по имени TITLE1, содержащую константу RGB Electronics.
  5. Является ли запись A5h правильным шестнадцатеричным числом?
  6. Как временно исключить какой-либо фрагмент программы из общего текста программы не удаляя этот фрагмент?
  7. Запишите константное выражение, в котором вычисляется остаток от деления 10 на 3.
  8. Почему при написании программ на языке ассемблер не стоит использовать числовые адреса памяти для доступа к переменным?
  9. Определите следующие числовые значения в элементах данных от FLDA до FLDE:
    1. четырёхбайтного элемента, содержащего шестнадцатеричный эквивалент десятичного числа 115,
    2. однобайтового элемента, содержащего шестнадцатеричный эквивалент десятичного числа 25,
    3. двухбайтового элемента, содержащего неопределенное значение,
    4. однобайтового элемента, содержащего двоичный эквивалент десятичного числа 25,
    5. директивы DW, содержащей последовательные значения 16, 19, 20, 27, 30.
  10. Приведите пример правильной вещественной константы, содержащей показатель степени.
  11. Нужно ли заключать строковую константу в одинарные кавычки?
  12. В чем разница между DB ‘26’ и DB 26.
  13. Назовите максимальную длину идентификатора.
  14. Определите ассемблерный шестнадцатеричный объектный код для:
    1. DB –26,
    2. DW 2645,
    3. DD 25733,
    4. DQ –2573300.
  15. Представьте следующие символьные цепочки в шестнадцатеричном коде:
    1. SAM JONES;
    2. –75.61;
    3. Hello, how are you?
  16. Верно ли, что название идентификаторов в языке ассемблер не зависят от регистра символов?
  17. Приведите пример многострочного комментария.
  18. Как сохраняется в памяти строка символов? Как подсчитать размер занимаемой памяти для отдельной строки?
  19. Верно ли, что для записи директив можно использовать как прописные, так и строчные латинские буквы, а также их сочетание?
  20. Что такое константа? Чем константа отличается от переменной?
  21. Назовите основные части ассемблерной команды. Верно ли, что метка в коде программы должна заканчиваться двоеточием, а метка данных нет?
Изображения
 
6
Закрытая тема Создать тему
Опции темы

Новые блоги и статьи
[golang] Двоичная куча, min-heap
alhaos 20.05.2026
Двоичная куча Двоичная куча — структура данных, которая всегда держит самый важный элемент наготове. Представьте очередь к хилеру в игре, и очередь из игроков в приоритете те у кого меньше. . .
[golang] Breadth-First Search
alhaos 19.05.2026
BFS (Breadth-First Search) — это базовый алгоритм обхода графа в ширину, который поуровнево исследует все связанные вершины. Он начинает с выбранной точки и проверяет всех соседей, прежде чем. . .
[golang] Алгоритм «Хак Госпера»
alhaos 17.05.2026
Алгоритм «Хак Госпера» Хак Госпера (Gosper's Hack) — алгоритм нахождения следующего по величине числа с тем же количеством установленных бит. Придуман Биллом Госпером в 1970-х, опубликован в. . .
Рисование бинарного древа до 6-го колена на js, svg.
russiannick 17.05.2026
<svg width="335" height="240" viewBox="0 0 335 240" fill="#e5e1bb"> <style> <!]> </ style> <g id="bush"> </ g> </ svg> function fn(){ let rost;/ / высота древа let xx=165,yy=210,w=256;
FSharp: interface of module
DevAlt 16.05.2026
Интерфейс модуля F# позволяет управлять доступностью членов, содержащихся в реализации модуля. По-умолчанию все члены модуля доступны: module Foo let x = 10 let boo () = printfn "boo" . . .
Хитросплетение родственных связей пантеона греческих богов.
russiannick 14.05.2026
Однооконник, позволяющий узреть и изучить отдельных героев древней Греции. <!DOCTYPE html> <html lang="ru"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible". . .
[golang] Угол между стрелками часов
alhaos 12.05.2026
По заданным значениям часа и минуты необходимо определить значение меньшего угла между стрелками аналогового циферблата часов. import "math" func angleClock(hour int, minutes int) float64 { . . .
Debian 13: Установка Lazarus QT5
ВитГо 09.05.2026
Эта инструкция моя компиляция инструкций volvo https:/ / www. cyberforum. ru/ blogs/ 203668/ 10753. html и его же старой инструкции по установке Lazarus с gtk2. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru