Tooprogram.ru

Компьютерный справочник
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Метки в ассемблере

Клуб программистов

Delphi programming

Подписаться на рассылку:

Assembler&Win32. Курс молодого бойца. Урок 6.

Символьные метки

Одно из преимуществ ассемблера заключается в использовании символьных меток и меток данных (переменных). По сути оба типа меток — это символьные метки. На этом уроке я вам объясню, как надо пользоваться символьными метками и метками данных.
Начну с более сложного — меток данных. В секции с данными с помощью директив db, dw, dd, dq вы резервируете память под данные соответствующего размера. Но надо неким образом получить доступ к этим данным. Для этого существуют символьные метки переменных. По существу метка возвращает смещение, на котором она находится. Метка виртуальна — в шестнадцатеричных кодах у неё нет эквивалента, она создана только для удобства программиста. При использовании метки под ней подразумевается некоторое смещение, на которую она указывает.
Пример:
.data
PARAM dd 11223344h

.code
mov eax, [PARAM]
mov [PARAM], ebx
По определению это правильный метод использования меток. После данных операций регистр eax будет равен 11223344. Но парадокс у операций:

mov eax, PARAM
mov PARAM, ebx

тот же самый результат и никаких ошибок при компиляции не возникает. Самое главное чтобы совпадали размеры. Но мой вам совет лучше всегда пользуйтесь квадратными скобками. Примеры

.data
PARAM dw 1122h
PARAM1 db 12h
PARAM2 dd 12345678h

mov eax,0
mov ebx, 0
mov ecx,0
mov edx, 0
mov al, byte ptr [PARAM]
mov bl, [PARAM1]
mov ecx,[PARAM2]
mov dx, word ptr [PARAM2]
mov bh, byte ptr [PARAM2]

После всех манипуляций состояние регистров будет таким:
AL = 22
BL = 12
ECX = 12345678
DX = 5678
BH = 78

Ещё один пример:

PARAM1 dd 12345678h

.code
mov ax, 8888h
mov word ptr [PARAM1], ax
mov ebx, [PARAM1]
mov ecx, 0
mov edx, 0
mov cx, word ptr [PARAM1+2]
mov [PARAM1], 089ABCDEFh
mov dx, word ptr [PARAM1]

После всех манипуляций состояние регистров будет таким:
EBX = 12348888
CX = 1234
DX = CDEF

Думаю здесь всё понятно. Размер копируемых данных по умолчанию равен размеру директивы, которая стоит после метки.
Символьные метки отличаются от меток данных тем, что их можно описывать в любом месте программы. После символьной метки надо ставить двоеточие (как в других языках высокого уровня). Они также возвращают смещение, на котором стоят. Они используются при прыжках (о них расскажу позже), или с командой call. Команда call передаёт управление команде, которая находится на смещении, на которое указывает данная метка. Их также можно использовать вместо меток данных. Но при получении значения или его изменении надо обязательно указывать размер данных.
Пример:
.data
metka:
PARAM1 dd 12345678h

.code
mov ecx, 0
mov ebx, 0
mov ax, 0BEDAh
mov word ptr [metka],ax
mov bx, word ptr [metka]
mov cx, word ptr [metka+2]
После этих манипуляций состояние регистров будет такое:
CX = 1234
BX = BEDA

Получение смещения метки.
Для получения смещения метки есть специальный префикс offset. Вы, наверное, видели использование этого префикса в нашей первой программе. Вот пример использования префикса offset:
.data
PARAM1 dd 12345678h

.code
mov eax, offset PARAM1
После этого в регистре eax будет находиться смещение метки PARAM1. При использовании префикса назначением также может быть ячейка памяти, у следующих команд будет тот же результат что и в первом случае:
mov [PARAM1], offset PARAM1
mov eax, [PARAM1]
Альтернативой префиксу offset является команда lea. Пример:
.data
metka:
PARAM1 dd 12345678h

.code
lea eax, metka
После этого в регистре eax будет находиться смещение метки metka. В команде lea можно получать смещение метки данных. Следующий пример будет иметь тот же результат что и предыдущий:
.data
metka:
PARAM1 dd 12345678h

.code
lea eax, PARAM1

Подходит к концу шестой урок. На следующем уроке мы узнаем, что такое прыжок: безусловный и условный.

Метки в ассемблере

Большая часть данной главы будет носить справочный характер. Почему я привожу справочный материал в середине книги, а не в ее начале? Просто я убежден, что справка в начале книги может отбить всякую охоту читать дальше. Многое из того, что я привожу в данной главе. Вы уже знаете и, следовательно, Вам интересно будет читать материал этой главы.

1. Метка с двоеточием после имени определяет адрес следующей за меткой команды.

2. Директива LABEL позволяет определить явно тип метки. Значение же определенной таким образом метки равно адресу команды или данных, стоящих далее. Например,
LABEL L1 DWORD.

3. Выражение ИМЯ PROC определяет метку, переход на которую обычно происходит по команде CALL. Блок кода, начинающийся с такой метки, называют процедурой. Впрочем, переход на такую метку можно осуществлять и с помощью JMP, как, впрочем, и команду CALL можно использовать для перехода на обычную метку. В этом, несомненно, состоит сила и гибкость ассемблера.

4. В строке за меткой может стоять директива резервирования данных, например: ERR DB ‘Ошибка’ или NUM DWORD 0. С точки зрения языка высокого уровня таким образом мы определяем глобальную переменную. С точки же зрения ассемблера нет никакой разницы между командой и данными, поэтому между меткой, определяющей команду, и меткой, определяющей данные, нет никакой разницы. Раз уж речь пошла о данных, перечислю их типы:
BYTE (DB) — байт,
WORD (DW) — 2 байта,
DWORD (DD) — 4 байта,
FWORD (DF) — 6 байт,
QWORD (DQ) — 8 байт,
TBYTE (DT) — 10 байт.

5. С помощью директивы EQU в терминах языков высокого уровня определяются константы. Например — MES EQU «ERROR!», LAB EQU 145Н. С помощью EQU значение данной метке может быть присвоено только один раз. С правой стороны от EQU может стоять выражение с использованием арифметических, логических и битовых операций. Вот эти операции: «+», «-«, «*», «/», «MOD»-ocтaток от деления, «AND», «OR», «NOT», «XOR», «SHR», «SHL». Используются также операции сравнения: EQ, GE, GT, LE, LT, NE. Выражение с операцией сравнения считается логическим и принимает значение 0, если условие не выполняется, и 1 — если выполняется. С помощью директивы «=» можно присваивать только целые значения, но зато производить переприсваивание. Заметим, что выражение может являться операндом команды: MOV EAX,16*16-1.

6. Метка «$» всегда определяет текущий адрес.

7. В MASM метки, стоящие в процедуре, автоматически считаются локальными и, следовательно, имена меток в процедурах могут дублироваться. В TASM все метки по умолчанию считаются глобальными. Чтобы сделать метки, стоящие в процедуре локальными, они должны иметь префикс @@, а в начале программы следует указать директиву LOCALS (см. предыдущую главу).

1. Директива STRUC позволяет объединить несколько разнородных данных в одно целое. Эти данные называются полями. Вначале при помощи STRUC определяется шаблон структуры, затем с помощью директивы можно определить любое количество структур. Рассмотрим пример:

Доступ к полям структуры осуществляется посредством точки: COMP1.RE.

2. Объединение. Объединение определяется при помощи ключевого слова UNION. От структуры объединение отличается только тем, что все поля располагаются в структуре с нулевым смещением, т.е. накладываются друг на друга.

Читать еще:  Что такое регистр в ассемблере

1. Условное ассемблирование дает возможность при трансляции обходить тот или иной участок программы. Существует три вида условного ассемблирования.
Условие считается не выполненным, если выражение принимает значение 0 и выполненным, если выражение отлично от нуля.

2. Ассемблеры MASM и TASM поддерживают также несколько условных специальных директив, назовем некоторые из них.

б) Операторы IF1 и IF2 проверяют первый и второй проход при ассемблировании.

в) Оператор IFDEF — проверяет, определено ли в программе символическое имя, IFDEFN — обратный оператор. И другие IF операторы. Они имеются в любом справочнике по ассемблеру.

г) Имеется целый набор директив, начинающихся с .ERR. Например, .ERRE выражение — вызовет прекращение трансляции и сообщение об ошибке, если выражение станет равным 0.

Условное ассемблирование понадобится нам в конце главы для написания программы, транслируемой как в MASM, так и TASM.

1. С упрощенным вызовом процедур в MASM Вы уже познакомились. Это директива INVOKE. Процедура должна быть заранее определена с использованием ключевого слова PROTO. Например:
Здесь h — дескриптор окна, откуда вызывается сообщение, TheMsg — строка сообщения, TitleW — заголовок окна, MB_OK — тип сообщения. ADDR в данном случае синоним OFFSET.

2. Оказывается, в синтаксисе TASM тоже имеется свой упрощенный вызов.
PASCAL — тип вызова, точнее порядок следования параметров. Можно поставить параметр C, тогда порядок будет обратным.

1. Повторение, заданное опеделенное число раз. Используется макродиректива REPT. Например:
Будет сгенерировано 100 директив DB 10. С этой директивой удобно использовать оператор «=», который позволяет изменять значение переменной многократно, т.е. использовать выражение типа А = А + 5.

2. Директива IRP.
Блок будет вызываться столько раз, сколько параметров в списке. Например:
Приведет к генерации следующих строк:

3. Директива IRPC.

Пример:
Данный фрагмент эквивалентен следующей последовательности:

Амперсант (&) в последнем примере используется для того, чтобы задать вычисление параметра блока повторения даже внутри кавычек. Амперсант — это макрооперация, которая работает в блоке повторения, поскольку блоки повторения представляют собой один из типов макрокоманды.

Общий вид макроопределения. Определив блок один раз, можно использовать его в программе многократно. Причем в зависимости от значений параметров заменяемый участок может иметь разные значения. Если заданный участок предполагается многократно использовать, например в цикле, макроопределение имеет несомненные преимущества перед процедурой, т.к. несколько убыстряет выполнение кода. Пример: Данное макроопределение приводит к обмену содержимым между параметрами.

ЕХС EAX,EBX эквивалентно PUSH EAXPOP EAX; ЕХС MEM1,ESI — PUSH MEM1POP ESI и т. д. Заметим, что если первый параметр будет непосредственно числом, то это приведет к загрузке данного числа во второй операнд.

Важным вопросом в связи с макроопределениями является проблема меток. Действительно, если мы будем применять в макроопределении обычные метки, то при использовании его более чем один раз возникнет коллизия. Коллизия эта разрешается при помощи объявления локальных меток. Для этого используется ключевое слово LOCAL. Например,

Данное макроопределение можно использовать сколь угодно много раз — при каждой подстановке ассемблер будет генерировать уникальную метку. Для выхода из макроопределения (т.е. для прекращения генерации макроопределения) применяется директива EXITM. Она может понадобиться, если в макроопределении Вы используете условные конструкции типа IF..ENDIF.

Некоторые другие директивы транслятора ассемблера

1. Кроме объявлений с использованием директив PUBLIC и EXTERN, возможно объявление при помощи директивы GLOBAL, которая действует, как PUBLIC и EXTERN одновременно.

2. PURGE имя макроса. Отменяет загрузку макроса. Используется при работе с библиотекой макросов, чтобы не перегружать память 38 .

3. LENGTHOF — определяет число элементов данных. SIZEOF — определяет размер данных (отсутствуют в TASM).

4. Директивы задания набора команд.
.8086 — разрешены только команды микропроцессора 8086. Данная директива работает по умолчанию.
.186 — разрешены команды 186.
.286 и .286Р — разрешены команды 286-ого микропроцессора. Добавка «P» здесь и далее означает разрешение команд защищенного режима.
.386 и .386P — разрешение команд 386-ого микропроцессора.
.486 и .486Р — разрешение команд 486-ого процессора.
.586 и .586Р — разрешены команды Р5 (Pentium).
.686 и .686Р — разрешены команды Pб (Pentium Pro, Pentium II).
.8087 — разрешены команды арифметического сопроцессора 8087.
.287 — разрешены команды арифметического сопроцессора 287.
.387 — разрешены команды арифметического сопроцессора 387.
.MMX — разрешены команды расширения ММХ.

5. Директивы управления листингом.
NAME — задать имя модуля.
TITLE — определяет заголовок листинга.
По умолчанию и имя модуля, и заголовок листинга совпадают с именем файла.
SUBTTL — определяет подзаголовок листинга.
PAGE — определяет размеры страницы листинга: длина, ширина. Директива PAGE без аргументов начинает новую страницу листинга.
.LIST — выдавать листинг.
.XLIST — запретить выдачу листинга.
.SALL — подавить печать макроопределений.
.SFCOND — подвить печать условных блоков с ложными условиями.
.LFCOND — печатать условные блоки с ложными условиями.
.CREF — разрешить листинг перекрестных ссылок.
.XCREF — запретить листинг перекрестных ссылок.

38 В операционной системе MS DOS это было существенно.

1. Условные конструкции.

Рассмотрим следующий фрагмент, содержащий условную конструкцию и соответствующий ей ассемблерный код. эквивалентен следующему ассемблерному коду: Весьма удобная штука, но не увлекайтесь: на мой взгляд, это сильно расслабляет.

Есть некоторое отличие в том, как два ассемблера транслируют директивы .IF и .WHILE. Транслятор TASM32 производит автоматически оптимизацию на предмет выравнивания по границе учетверенного слова, добавляя дополнительно команды NOP. Это несколько ускоряет выполнение программы, но увеличивает ее объем. Мне ближе позиция MASM.

Сейчас мы рассмотрим вопрос о написании программ, которые одинаково транслировались бы и в MASM, и в TASM. Для этого прекрасно подходит условное ассемблирование. Удобнее всего использовать IFDEF и возможности трансляторов задавать символьную константу, все равно — TASM или MASM. И в ML, и в TASM32 определен ключ /D, позволяющий задавать такую константу.

На Рис. 2.6.1 представлена программа, транслируемая и в MASM, и TASM. Программа весьма проста, но рассмотрения ее вполне достаточно для создания более сложных подобных совместимых программ.

Трансляция в MASM:

Трансляция в TASM:

Как видите, все сводится к проверке, определена символьная константа MASM или нет (ключ /DMASM). Еще одна сложность — добавка в конце имени @N. Эту проблему мы обходим, используя оператор «=», с помощью которого переопределяем имена (см. секцию «работаем в TASM»).

Структура программы на ассемблере

Программирование на уровне машинных команд — это тот минимальный уровень, на котором возможно составление программ. Система машинных команд должна быть достаточной для того, чтобы реализовать требуемые действия, выдавая указания аппаратуре вычислительной машины.

Каждая машинная команда состоит из двух частей:

  • операционной — определяющей, «что делать»;
  • операндной — определяющей объекты обработки, «с чем делать».

Машинная команда микропроцессора, записанная на языке ассемблера, представляет собой одну строку, имеющую следующий синтакический вид:

метка команда/директива операнд(ы) ;комментарии

При этом обязательным полем в строке является команда или директива.

Метка, команда/директива и операнды (если имеются) разделяются по крайней мере одним символом пробела или табуляции.

Читать еще:  Структура ассемблерной строки

Если команду или директиву необходимо продолжить на следующей строке, то используется символ обратный слеш: .

По умолчанию язык ассемблера не различает заглавные и строчные буквы в написании команд или директив.

Примеры строк кода:

Метки

Метка в языке ассемблера может содержать следующие символы:

  • все буквы латинского алфавита;
  • цифры от 0 до 9;
  • спецсимволы: _, @, $, ?.

В качестве первого символа метки может использоваться точка, но некоторые компиляторы не рекомендуют применять этот знак. В качестве меток нельзя использовать зарезервированные имена Ассемблера (директивы, операторы, имена команд).

Первым символом в метке должна быть буква или спецсимвол (но не цифра). Максимальная длина метки – 31 символ. Все метки, которые записываются в строке, не содержащей директиву ассемблера, должны заканчиваться двоеточием : .

Команды

Команда указывает транслятору, какое действие должен выполнить микропроцессор. В сегменте данных команда (или директива) определяет поле, рабочую область или константу. В сегменте кода команда определяет действие, например, пересылка (mov) или сложение (add).

Директивы

Ассемблер имеет ряд операторов, которые позволяют управлять процессом ассемблирования и формирования листинга. Эти операторы называются директивами . Они действуют только в процессе ассемблирования программы и, в отличие от команд, не генерируют машинных кодов.

Операнды

Операнд – объект, над которым выполняется машинная команда или оператор языка программирования.
Команда может иметь один или два операнда, или вообще не иметь операндов. Число операндов неявно задается кодом команды.
Примеры:

  • Нет операндов ret ;Вернуться
  • Один операнд inc ecx ;Увеличить ecx
  • Два операнда add eax,12 ;Прибавить 12 к eax

Метка, команда (директива) и операнд не обязательно должны начинаться с какой-либо определенной позиции в строке. Однако рекомендуется записывать их в колонку для большего удобства чтения программы.

В качестве операндов могут выступать

  • идентификаторы;
  • цепочки символов, заключенных в одинарные или двойные кавычки;
  • целые числа в двоичной, восьмеричной, десятичной или шестнадцатеричной системе счисления.
Идентификаторы

Идентификаторы – последовательности допустимых символов, использующиеся для обозначения таких объектов программы, как коды операций, имена переменных и названия меток.

Правила записи идентификаторов.

  • Идентификатор может состоять из одного или нескольких символов.
  • В качестве символов можно использовать буквы латинского алфавита, цифры и некоторые специальные знаки: _, ?, $, @.
  • Идентификатор не может начинаться символом цифры.
  • Длина идентификатора может быть до 255 символов.
  • Транслятор воспринимает первые 32 символа идентификатора, а остальные игнорирует.
Комментарии

Комментарии отделяются от исполняемой строки символом ; . При этом все, что записано после символа точка с запятой и до конца строки, является комментарием. Использование комментариев в программе улучшает ее ясность, особенно там, где назначение набора команд непонятно. Комментарий может содержать любые печатные символы, включая пробел. Комментарий может занимать всю строку или следовать за командой на той же строке.

Структура программы на ассемблере

Программа, написанная на языке ассемблера, может состоять из нескольких частей, называемых модулями . В каждом модуле могут быть определены один или несколько сегментов данных, стека и кода. Любая законченная программа на ассемблере должна включать один главный, или основной, модуль, с которого начинается ее выполнение. Модуль может содержать сегменты кода, сегменты данных и стека, объявленные при помощи соответствующих директив. Перед объявлением сегментов нужно указать модель памяти при помощи директивы .MODEL.

Пример «ничего не делающей» программы на языке ассемблера:

В данной программе представлена всего одна команда микропроцессора. Эта команда RET . Она обеспечивает правильное окончание работы программы. В общем случае эта команда используется для выхода из процедуры.
Остальная часть программы относится к работе транслятора.
.686P — разрешены команды защищенного режима Pentium 6 (Pentium II). Данная директива выбирает поддерживаемый набор команд ассемблера, указывая модель процессора. Буква P, указанная в конце директивы, сообщает транслятору о работе процессора в защищенном режиме.
.MODEL FLAT, stdcall — плоская модель памяти. Эта модель памяти используется в операционной системе Windows. stdcall — используемое соглашение о вызовах процедур.
.DATA — сегмент программы, содержащий данные.
.CODE — блок программы, содержащей код.
START — метка. В ассемблере метки играют большую роль, что не скажешь о современных языках высокого уровня.
END START — конец программы и сообщение транслятору, что начинать выполнение программы надо с метки START .
Каждый модуль должен содержать директиву END , отмечающую конец исходного кода программы. Все строки, которые следуют за директивой END , игнорируются. Если опустить директиву END , то генерируется ошибка.
Метка, указанная после директивы END , сообщает транслятору имя главного модуля, с которого начинается выполнение программы. Если программа содержит один модуль, метку после директивы END можно не указывать.

Метки в ассемблере

Большая часть данной главы будет носить справочный характер. Почему я привожу справочный материал в середине книги, а не в ее начале? Просто я убежден, что справка в начале книги может отбить всякую охоту читать дальше. Многое из того, что я привожу в данной главе. Вы уже знаете и, следовательно, Вам интересно будет читать материал этой главы.

1. Метка с двоеточием после имени определяет адрес следующей за меткой команды.

2. Директива LABEL позволяет определить явно тип метки. Значение же определенной таким образом метки равно адресу команды или данных, стоящих далее. Например,
LABEL L1 DWORD.

3. Выражение ИМЯ PROC определяет метку, переход на которую обычно происходит по команде CALL. Блок кода, начинающийся с такой метки, называют процедурой. Впрочем, переход на такую метку можно осуществлять и с помощью JMP, как, впрочем, и команду CALL можно использовать для перехода на обычную метку. В этом, несомненно, состоит сила и гибкость ассемблера.

4. В строке за меткой может стоять директива резервирования данных, например: ERR DB ‘Ошибка’ или NUM DWORD 0. С точки зрения языка высокого уровня таким образом мы определяем глобальную переменную. С точки же зрения ассемблера нет никакой разницы между командой и данными, поэтому между меткой, определяющей команду, и меткой, определяющей данные, нет никакой разницы. Раз уж речь пошла о данных, перечислю их типы:
BYTE (DB) — байт,
WORD (DW) — 2 байта,
DWORD (DD) — 4 байта,
FWORD (DF) — 6 байт,
QWORD (DQ) — 8 байт,
TBYTE (DT) — 10 байт.

5. С помощью директивы EQU в терминах языков высокого уровня определяются константы. Например — MES EQU «ERROR!», LAB EQU 145Н. С помощью EQU значение данной метке может быть присвоено только один раз. С правой стороны от EQU может стоять выражение с использованием арифметических, логических и битовых операций. Вот эти операции: «+», «-«, «*», «/», «MOD»-ocтaток от деления, «AND», «OR», «NOT», «XOR», «SHR», «SHL». Используются также операции сравнения: EQ, GE, GT, LE, LT, NE. Выражение с операцией сравнения считается логическим и принимает значение 0, если условие не выполняется, и 1 — если выполняется. С помощью директивы «=» можно присваивать только целые значения, но зато производить переприсваивание. Заметим, что выражение может являться операндом команды: MOV EAX,16*16-1.

6. Метка «$» всегда определяет текущий адрес.

7. В MASM метки, стоящие в процедуре, автоматически считаются локальными и, следовательно, имена меток в процедурах могут дублироваться. В TASM все метки по умолчанию считаются глобальными. Чтобы сделать метки, стоящие в процедуре локальными, они должны иметь префикс @@, а в начале программы следует указать директиву LOCALS (см. предыдущую главу).

Читать еще:  Разрешить небезопасные приложения gmail

1. Директива STRUC позволяет объединить несколько разнородных данных в одно целое. Эти данные называются полями. Вначале при помощи STRUC определяется шаблон структуры, затем с помощью директивы можно определить любое количество структур. Рассмотрим пример:

Доступ к полям структуры осуществляется посредством точки: COMP1.RE.

2. Объединение. Объединение определяется при помощи ключевого слова UNION. От структуры объединение отличается только тем, что все поля располагаются в структуре с нулевым смещением, т.е. накладываются друг на друга.

1. Условное ассемблирование дает возможность при трансляции обходить тот или иной участок программы. Существует три вида условного ассемблирования.
Условие считается не выполненным, если выражение принимает значение 0 и выполненным, если выражение отлично от нуля.

2. Ассемблеры MASM и TASM поддерживают также несколько условных специальных директив, назовем некоторые из них.

б) Операторы IF1 и IF2 проверяют первый и второй проход при ассемблировании.

в) Оператор IFDEF — проверяет, определено ли в программе символическое имя, IFDEFN — обратный оператор. И другие IF операторы. Они имеются в любом справочнике по ассемблеру.

г) Имеется целый набор директив, начинающихся с .ERR. Например, .ERRE выражение — вызовет прекращение трансляции и сообщение об ошибке, если выражение станет равным 0.

Условное ассемблирование понадобится нам в конце главы для написания программы, транслируемой как в MASM, так и TASM.

1. С упрощенным вызовом процедур в MASM Вы уже познакомились. Это директива INVOKE. Процедура должна быть заранее определена с использованием ключевого слова PROTO. Например:
Здесь h — дескриптор окна, откуда вызывается сообщение, TheMsg — строка сообщения, TitleW — заголовок окна, MB_OK — тип сообщения. ADDR в данном случае синоним OFFSET.

2. Оказывается, в синтаксисе TASM тоже имеется свой упрощенный вызов.
PASCAL — тип вызова, точнее порядок следования параметров. Можно поставить параметр C, тогда порядок будет обратным.

1. Повторение, заданное опеделенное число раз. Используется макродиректива REPT. Например:
Будет сгенерировано 100 директив DB 10. С этой директивой удобно использовать оператор «=», который позволяет изменять значение переменной многократно, т.е. использовать выражение типа А = А + 5.

2. Директива IRP.
Блок будет вызываться столько раз, сколько параметров в списке. Например:
Приведет к генерации следующих строк:

3. Директива IRPC.

Пример:
Данный фрагмент эквивалентен следующей последовательности:

Амперсант (&) в последнем примере используется для того, чтобы задать вычисление параметра блока повторения даже внутри кавычек. Амперсант — это макрооперация, которая работает в блоке повторения, поскольку блоки повторения представляют собой один из типов макрокоманды.

Общий вид макроопределения. Определив блок один раз, можно использовать его в программе многократно. Причем в зависимости от значений параметров заменяемый участок может иметь разные значения. Если заданный участок предполагается многократно использовать, например в цикле, макроопределение имеет несомненные преимущества перед процедурой, т.к. несколько убыстряет выполнение кода. Пример: Данное макроопределение приводит к обмену содержимым между параметрами.

ЕХС EAX,EBX эквивалентно PUSH EAXPOP EAX; ЕХС MEM1,ESI — PUSH MEM1POP ESI и т. д. Заметим, что если первый параметр будет непосредственно числом, то это приведет к загрузке данного числа во второй операнд.

Важным вопросом в связи с макроопределениями является проблема меток. Действительно, если мы будем применять в макроопределении обычные метки, то при использовании его более чем один раз возникнет коллизия. Коллизия эта разрешается при помощи объявления локальных меток. Для этого используется ключевое слово LOCAL. Например,

Данное макроопределение можно использовать сколь угодно много раз — при каждой подстановке ассемблер будет генерировать уникальную метку. Для выхода из макроопределения (т.е. для прекращения генерации макроопределения) применяется директива EXITM. Она может понадобиться, если в макроопределении Вы используете условные конструкции типа IF..ENDIF.

Некоторые другие директивы транслятора ассемблера

1. Кроме объявлений с использованием директив PUBLIC и EXTERN, возможно объявление при помощи директивы GLOBAL, которая действует, как PUBLIC и EXTERN одновременно.

2. PURGE имя макроса. Отменяет загрузку макроса. Используется при работе с библиотекой макросов, чтобы не перегружать память 38 .

3. LENGTHOF — определяет число элементов данных. SIZEOF — определяет размер данных (отсутствуют в TASM).

4. Директивы задания набора команд.
.8086 — разрешены только команды микропроцессора 8086. Данная директива работает по умолчанию.
.186 — разрешены команды 186.
.286 и .286Р — разрешены команды 286-ого микропроцессора. Добавка «P» здесь и далее означает разрешение команд защищенного режима.
.386 и .386P — разрешение команд 386-ого микропроцессора.
.486 и .486Р — разрешение команд 486-ого процессора.
.586 и .586Р — разрешены команды Р5 (Pentium).
.686 и .686Р — разрешены команды Pб (Pentium Pro, Pentium II).
.8087 — разрешены команды арифметического сопроцессора 8087.
.287 — разрешены команды арифметического сопроцессора 287.
.387 — разрешены команды арифметического сопроцессора 387.
.MMX — разрешены команды расширения ММХ.

5. Директивы управления листингом.
NAME — задать имя модуля.
TITLE — определяет заголовок листинга.
По умолчанию и имя модуля, и заголовок листинга совпадают с именем файла.
SUBTTL — определяет подзаголовок листинга.
PAGE — определяет размеры страницы листинга: длина, ширина. Директива PAGE без аргументов начинает новую страницу листинга.
.LIST — выдавать листинг.
.XLIST — запретить выдачу листинга.
.SALL — подавить печать макроопределений.
.SFCOND — подвить печать условных блоков с ложными условиями.
.LFCOND — печатать условные блоки с ложными условиями.
.CREF — разрешить листинг перекрестных ссылок.
.XCREF — запретить листинг перекрестных ссылок.

38 В операционной системе MS DOS это было существенно.

1. Условные конструкции.

Рассмотрим следующий фрагмент, содержащий условную конструкцию и соответствующий ей ассемблерный код. эквивалентен следующему ассемблерному коду: Весьма удобная штука, но не увлекайтесь: на мой взгляд, это сильно расслабляет.

Есть некоторое отличие в том, как два ассемблера транслируют директивы .IF и .WHILE. Транслятор TASM32 производит автоматически оптимизацию на предмет выравнивания по границе учетверенного слова, добавляя дополнительно команды NOP. Это несколько ускоряет выполнение программы, но увеличивает ее объем. Мне ближе позиция MASM.

Сейчас мы рассмотрим вопрос о написании программ, которые одинаково транслировались бы и в MASM, и в TASM. Для этого прекрасно подходит условное ассемблирование. Удобнее всего использовать IFDEF и возможности трансляторов задавать символьную константу, все равно — TASM или MASM. И в ML, и в TASM32 определен ключ /D, позволяющий задавать такую константу.

На Рис. 2.6.1 представлена программа, транслируемая и в MASM, и TASM. Программа весьма проста, но рассмотрения ее вполне достаточно для создания более сложных подобных совместимых программ.

Трансляция в MASM:

Трансляция в TASM:

Как видите, все сводится к проверке, определена символьная константа MASM или нет (ключ /DMASM). Еще одна сложность — добавка в конце имени @N. Эту проблему мы обходим, используя оператор «=», с помощью которого переопределяем имена (см. секцию «работаем в TASM»).

Ссылка на основную публикацию
Adblock
detector