ТОП 10:

Директивы управления программным счетчиком



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

 

org выражение

Устанавливает значение программного счетчика. Директива ORG с операндом 100h обязательно используется при написании файлов типа СОМ, которые загружаются в память после блока параметров размером l00h.

 

even

Директива EVEN делает текущее значение счетчика кратным двум, вставляя команду NOP, если оно было нечетным. Это увеличивает ско­рость работы программы, так как для доступа к слову, начинающемуся с нечетного адреса, процессор должен считать два слова из памяти. Если при описании сегмента не использовалось выравнивание типа BYTE, счетчик в начале сегмента всегда четный.

 

align значение

Округляет значение программного счетчика до кратного указанному значению. Значение может быть любым четным числом Если счетчик не кратен указанному числу, эта директива вставляет необходимое количество команд NOР.

Глобальные объявления

 

public язык метка. . .

Метка, объявленная директивой PUBLIC, становится доступной для других модулей программы. Так, можно объявлять имена процедур, переменные и константы, определенные директивой EQU. Необязатель­ный операнд языка (С, PASCAL, BASIC, FORTRAN, SYSCALL или STDCALL) указывает, что метка будет вызываться из модуля, написан­ного на соответствующем языке, и, при необходимости, изменяет ее (на­пример, добавляет _ перед первым символом метки).

 

comm расст язык метка:тип. . . ; для TASM

comm язык расст метка:тип. . . ; для MASM

Директива СОММ описывает общую переменную. Такие перемен­ные доступны из всех модулей, и их размещение в программе определя­ется на этапе компоновки. Обязательные аргументы директивы СОММ — метка (собственно имя общей переменной) и тип (BYTE, WORD, DWORD, FWORD, QWORD, TBYTE или имя структуры). Нео­бязательный операнд «расстояние» (NEAR или FAR) указывает, нахо­дится ли переменная в группе сегментов DGROUP (ближняя перемен­ная, для доступа достаточно смещения) или вне этих сегментов (дальняя переменная, для доступа потребуется сегментный адрес). Для моделей памяти TINY, SMALL и COMPACT по умолчанию значение этого операнда принимается за NEAR. И наконец, операнд «язык» дей­ствует аналогично такому же операнду для PUBLIC.

 

extrn язык метка:тип

Описывает метку, определенную в другом модуле (с помощью PUBLIC). Тип (BYTE, WORD, DWORD, FWORD, QWORD, TBYTE, имя структуры, FAR, NEAR, ABS) должен соответствовать типу метки в том модуле, в котором она была определена (тип ABS используется для констант из других модулей, определенных директивой EQU). Необязательный операнд языка действует так же, как и для директивы PUBLIC.

 

global язык метка:тип

Директива GLOBAL действует, как PUBLIC и EXTRN одновременно. Если указанная метка находится в этом же модуле, она становится доступной для других модулей, как если бы выполнилась директива PUBLIC. Если метка не описана — она считается внешней и выполняется действие, аналогичное действию директивы EXTRN.

Условное ассемблирование

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

 

if выражение

. . .

endif

Если значение выражения — ноль (ложь), весь участок программы между IF и ENDIF игнорируется. Директива IF может также сочетаться с ELSE и ELSEIF:

if выражение

. . .

else

. . .

endif

Если значение выражения — ноль, ассемблируется участок программы от ELSE до ENDIF, иначе — от IF до ELSE.

 

if выражение1

. . .

elseif выражение2

. . .

elself выражениеЗ

. . .

else

. . .

endif

В этом случае, если, например, выражение 2 не равно нулю, будет ассемблироваться участок программы между первой и второй директивой ELSEIF. Если все три выражения равны нулю, ассемблируется фрагмент от ELSE до ENDIF. Такая структура директив может использоваться в частном случае аналогично операторам switch/case языков высокого уровня, если выражения — проверки некоторой константы на равенство.

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

 

if $ gt 65535 ; если адрес вышел за пределы сегмента

.err

endif

Встретив директиву .ERR, ассемблер прекратит работу с сообщением об ошибке.

 

Выражения

При описании многих директив ассемблера использовались выражения. Выражение — это набор чисел, меток, или строк, связанных друг с другом операторами. Например: 2 + 2 — выраже­ние, состоящее из двух чисел (2 и 2) и оператора «+». Каждое выражение имеет значение, которое определяется как результат действия операторов: так, значение выражения 2 + 2 — число 4. Все выражения вычисляются в ходе ассемблирования программы, так что в полученном коде используются только значения.

Оператор «<>» (угловые скобки). Часть выражения, заключенная в угловые скобки, не вычисляется, а используется как строка символов, например:

 

message1 equ <foobar>

Оператор «()» (круглые скобки). Часть выражения, заключенная в круглые скобки, вычисляется в первую очередь.

 

mov аl, 2*(3+4) ; mov al, 14

Арифметические операторы: «+» (плюс), «–» (минус), «*» (умножение), «/» (целочисленное деление), MOD (остаток от деления). Эти операторы выполняют соответствующие арифметические действия.

 

mov al, 90 mod 7 ; mov al, 6

Кроме того, к арифметическим операторам относится унарный минус — минус, который ставят перед отрицательным числом.

Логические операторы: AND (И), NOT (HE), OR (ИЛИ), XOR (ис­ключающее ИЛИ), SHL (сдвиг влево), SHR (сдвиг вправо). Эти опера­торы выполняют соответствующие логические действия.

 

mov ax,1234h AND 4321h ; mov ax, 0220h

Операторы сравнения: EQ (равно), GЕ (больше или равно), GT (боль­ше), LE (меньше или равно), LT (меньше), NE (не равно). Результат дей­ствия каждого из этих операторов — единица, если условие выполняет­ся, и ноль — если не выполняется.

 

errnz $ gt 65535 ; если адрес больше 64 килобайт – ошибка

Операторы адресации:

SEG выражение — сегментный адрес.

OFFSET выражение — смещение.

THIS тип — текущий адрес (MASM и TASM).

Тип PTR выражение — переопределение тина.

LARGE выражение — 32-битное смещение (TASM).

SMALL выражение — 16-битное смещение (TASM).

SHORT выражение — 8-битное смещение.

 

SEG и OFFSET возвращают соответствующую часть адреса своего аргумента:

 

mov dx, offset msg ; занести в DX смещение переменной msg

THIS создает операнд, адресом которого является текущее значение счетчика:

 

mov al, this byte–1 ; занести в AX последний байт кода предыдущей команды

PTR создает аргумент, адресом которого является значение выражения, а тип указан явно:

 

mov dword ptr [si], 0 ; записать 4 байта нулей по адресу DS:SI

LARGE, SMALL и SHORT используются с командами передачи управления, если возникают двусмысленности при косвенных переходах:

 

jmp larqe dword ptr old_address ; переменная old_address содержит

; 32-битное смещение

jmp small dword ptr old_address ; переменная old_address содержит

; 16-битный сегментный адрес и

; 16-битное смещение

jmp short short_label ; метка short_label находится ближе,

; чем +128/-127 байт от этой команды, так что

; можно использовать короткую форму команды JMP

Другие операторы:

. (точка) — ссылка на элемент структуры.

: (двоеточие) — переопределение сегмента.

[] (квадратные скобки) — косвенная адресация.

? — неинициализированное значение.

Число DUP (значение) — повторяющееся значение.

 

Эти пять операторов были описаны ранее, когда говорилось о структурах данных, методах адресации и псевдокомандах определения данных.

 

LENGTH метка — число элементов данных

 

baz dw 0,1,2,3,4,5,6,7 ; определить таблицу из 8 слов

baz_count = length table ; table_count = 8

SIZE метка — размер данных

 

baz_size = size table ; table_size = 16

 

3.5. Макроопределения

Одно из самых мощных языковых средств ассемблера — макроопределения. Макроопределение (или макрос) — это участок программы, которому присвоено имя и который ассемблируется всякий раз, когда ассемблер встречает это имя в тексте программы. Макрос начинается директивой MACRO и заканчивается ENDM.

Пусть, например, описано макроопределение hex2ascii, переводящее шестнадцатеричное число, находящееся в регистре AL, в ASCII-код соответствующей шестнадцатеричной цифры:

 

hex2ascii macro

cmp al, 10

sbb al, 96h

das

endm

Теперь в программе можно использовать слово hex2ascii, как если бы это было имя команды, и ассемблер заменит каждое такое слово на три команды, содержащиеся в макроопределении. Разумеется, можно оформить этот же участок кода в виде процедуры и вызывать его командой CALL — если процедура вызывается больше одного раза, этот вариант программы займет меньше места, но вариант с макроопределением бу­дет выполняться быстрее, так как в нем не будет лишних команд CALL и RET. Но скорость выполнения — не главное преимущество макросов. В отличие от процедур макроопределения могут вызываться с параметрами, так что, в зависимости от ситуации, включаемый код будет немного различаться, например:

s_mov macro register1, register2

push register1

pop register2

endm

Теперь можно использовать S_MOV вместо команды MOV для того, чтобы скопировать значение из одного сегментного регистра в другой.

Следующее важное средство, использующееся в макроопределениях, — директивы условного ассемблирования. Например: напишем макрос, выполняющий умножение регистра АХ на число, причем, если множитель — степень двойки, умножение будет выполняться более быстрой командой сдвига влево.

 

fast_mul macro number

if number eq 2

shl ax, 1 ; умножение на 2

elseif number eq 4

shl ax, 2 ; умножение на 4

elseif number eq 8

shl ax, 3 ; умножение на 8

. . . ; аналогично вплоть до:

elseif number eq 32768

shl ax, 15 ; умножение на 215

else

mov dx, number ; умножение на число, не являющееся

mul dx ; степенью двойки

endif

endm

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

Блоки повторений

Простейший блок повторений REPT выполняет ассемблирование участка программы заданное число раз. Например, если требуется создать массив байт, проинициализированный значениями от 0 до 0FFh, это можно сделать, повторив псевдокоманду DB следующим образом.

 

hexnumber = 0

hextable label byte ; имя массива

rept 256 ; начало блока

db hexnumber ; эти две строки ассемблируются

hexnumber = hexnumber+1 ; 256 раз

endm

Блоки повторений, так же как макроопределения, могут вызываться с параметрами. Для этого используются директивы IRP и IRPC:

 

irp параметр, <значение1, значение2. . .>

. . .

endm

irpc параметр, строка

. . .

endm

Блок, описанный директивой IRP, будет вызываться столько раз, сколько значений указано в списке (в угловых скобках), и при каждом повторении будет определена метка с именем parameter, равная очередному значению из списка. Например, следующий блок повторений сохранит в стеке регистры АХ, ВХ, СХ и DX:

 

irp reg, <ax,bx,cx,dx>

push reg

endm

Директива IRPC описывает блок, который выполняется столько раз, сколько символов содержит указанная строка, и при каждом повторении будет определена метка с именем parameter, равная очередному символу из строки. Если строка содержит пробелы или другие символы, отличные от разрешенных для меток, она должна быть заключена в угловые скобки. Например, следующий блок задает строку в памяти, располагая после каждого символа строки атрибут 0Fh (белый символ на черном фоне), так что эту строку затем можно будет скопировать прямо в видеопамять.

 

irpc character,<строка символов>

db ‘&character&’, 0Fh

endm

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

Макрооператоры

Макрооператор «&» (амперсанд) используется для того, чтобы параметр, переданный в качестве операнда макроопределению или блоку повторений, заменялся на значение до обработки строки ассемблером. Так, например, следующий макрос выполнит команду PUSH EAX, если его вызвать как PUSHREG А:

 

pushreg macro letter

push e&letter&x

endm

Иногда можно использовать только один амперсанд — в начале параметра, если не возникает неоднозначностей, например, если передается номер, а требуется создать набор переменных с именами, оканчивающимися этим номером:

 

irp number, <1,2,3,4>

msg&number db ?

endm

Макрооператор «<>» (угловые скобки) действует так, что весь текст, включенный в эти скобки, рассматривается как текстовая строка, даже если он содержит пробелы или другие разделители. Как мы уже видели, этот макрооператор используется при передаче текстовых строк в качестве параметров для макросов. Другое частое применение угловых скобок — передача списка параметров вложенному макроопределению или блоку повторений.

Макрооператор «!» (восклицательный знак) используется аналогично угловым кавычкам, но действует только на один следующий символ, так что, если этот символ — запятая или угловая скобка, он все равно будет передан макросу как часть параметра.

Макрооператор «%» (процент) указывает, что следующий за ним текст является выражением и должен быть вычислен. Обычно это используется для того, чтобы передавать в качестве параметра в макрос не само выражение, а его результат.

Макрооператор «;;» (две точки с запятой) — начало макрокомментария. В отличие от обычных комментариев текст макрокомментария не попадет в текст программы при подстановке макроса и не попадает в листинг. Это сэкономит память при ассемблировании программы с большим количеством макроопределении.

3.5.3. Другие директивы, используемые в макроопределениях

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

pushreg macro reg

ifb <reg>

exitm

endif

push reg

endm

LOCAL метка... — перечисляет метки, которые будут использоваться внутри макроопределения, чтобы не возникало ошибки «метка уже оп­ределена» при использовании макроса более одного раза или если та же метка присутствует в основном тексте программы. Операнд для LOCAL — метка или список меток, которые будут использоваться в макросе.

PURGE имя_макроса — отменяет определенный ранее макрос. Эта директива часто применяется сразу после INCLUDE, включившей в текст программы файл с большим количе­ством готовых макроопределений.

 

Другие директивы

Управление файлами

INCLUDE имя_файла — директива, вставляющая в текст программы текст файла. Обычно ис­пользуется для включения файлов, содержащих определения констант, структур и макросов.

INCLUDELIB имя_файла — директива, указывающая компоновщи­ку имя дополнительной библиотеки или объектного файла, который по­требуется при компоновке данной программы. Например, если исполь­зуются вызовы процедур или обращение к данным, определенным в других модулях. Использование этой директивы позволяет не указы­вать имена дополнительных библиотек при вызове компоновщика.

3.6.2. Управление листингом

Обычно ассемблеры, помимо создания объектного файла, предоставля­ют возможность создания листинга программы (TASM/L — для TASM, ml/Fl — для MASM). Листинг — это текстовый файл, содержащий текст ассемблерной программы, код каждой ассемблированной команды, список определенных меток, перекрестных ссылок, сегментов и групп. Формат файла листинга отличается для разных ассемблеров, и директивы управления форматом этого файла также сильно различаются, но несколько наиболее общих директив все-таки поддерживаются всеми тремя ассемблерами, рассмотренными в этой книге.

TITLE текст — определяет заголовок листинга. Заголовок появляется в начале каждой страницы.

SUBTTL текст — определяет подзаголовок листинга. Подзаголовок появляется на следующей строке после заголовка.

PAGE высота,ширина — устанавливает размеры страниц листинга (высота 10 - 255, ширина 59 - 255). Директива PAGE без аргументов начинает новую страницу, директива PAGE + начинает новую секцию, и нумерация страниц ведется с самого начала.

NAME текст — определяет имя модуля программы. Если NAME не указан, в качестве имени используются первые 6 символов из TITLE; если нет ни NAME, ни TITLE, за имя берется название файла.

.XLIST — отменить выдачу листинга.

.LIST — разрешить выдачу листинга.

.SALL — запретить листинг макроопределений.

.SECOND — запретить листинг неассемблированных условных блоков.

.LFCOND — разрешить листинг неассемблированных условных блоков.

.TFCOND — изменить режим листинга условных блоков на противоположный.

.CREF — разрешить листинг перекрестных ссылок.

.XCREF — запретить листинг перекрестных ссылок.

Комментарии

Кроме обычных комментариев, начинающихся с символа «;» (точка с запятой) и заканчивающихся в конце строки, возможны большие блоки комментариев, описываемые специальной директивой COMMENT.

comment @

любой текст

@

Операнд для COMMENT — любой символ, который будет считаться концом комментария. Весь участок текста, вплоть до следующего появления этого символа, ассемблером полностью игнорируется.

 

 


ЛИТЕРАТУРА

 

 

1. Зубков С. В. Ассемблер для DOS, Windows и Unix.— М., 1999.— 640 с.

2. Юров В., Хорошенко С. Assembler: учебный курс.— СПб., 1999.— 672 с.

3. Рудаков П. И., Финогенов К. Г. Программируем на языке ассемблера IBM PC. — Обнинск, 1999. — 495 c.

4. Абель П. Язык Ассемблера для IBM PC и программирования.— М., 1992.— 447 с.

5. Финогенов К. Г. Основы языка ассемблера.— М., 1999.— 288 с.

6. Сван Т. Освоение Turbo Assembler.— К.-М.-СПб., 1995.— 544 с.







Последнее изменение этой страницы: 2016-08-15; Нарушение авторского права страницы

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.231.167.166 (0.024 с.)