Глава 9. Задание и использование счетчика адреса
Счетчик адреса отслеживает при ассемблировании исходного
файла текущий адрес. Это позволяет вам в любой момент в процессе
ассемблирования программа знать, где вы находитесь. Турбо Ассемб-
лер предоставляет директивы, которые позволяют работать со счет-
чиком адреса и помещать в него нужно значение адреса.
Метки представляют собой имена, использующиеся для ссылок на
адреса в программе. Меткам во время их определения присваивается
текущее значение счетчика адреса программы. Метки позволяют вам
назначать имена переменным в памяти и адресам конкретных инструк-
ций.
В данной главе описываются имеющиеся директивы, которые ис-
пользуются для работы со счетчиком адреса и описания метод по те-
кущему адресу.
Идентификатор счетчика адреса $
Предопределенный идентификатор $ представляет текущий счет-
чик адреса. Счетчик адреса состоит из двух частей: сегмента и
смещения. При ассемблировании счетчик адреса представляет собой
смещение в текущем сегменте.
Счетчик адреса - это адрес адрес, который увеличивается и
отражает текущий адрес при ассемблировании каждого оператора ис-
ходного файла. Например:
helpkMessage DB 'это справочное сообщение программы'
helpLength = $ - helpMessage
Когда эти две строки ассемблируются, идентификатор
helpLength равен длине справочного сообщения.
Директивы счетчика адреса $
В Турбо Ассемблере предусмотрено несколько директив, уста-
навливающий счетчик инструкций. Эти директивы описываются в сле-
дующем разделе. Заметим, что все эти директивы работают как в ре-
жиме MASM, так и в режиме Ideal.
Директива ORG
Вы можете использовать директиву ORG, чтобы установить
счетчик адреса в значение текущего сегмента. Директива ORG имеет
следующий синтаксис:
ORG выражение
где "выражение" не может содержать никаких имен идентификаторов с
опережающими ссылками. Оно может быть константой или смещением от
идентификатора в текущем сегменте, либо смещением относительно
текущего счетчика адреса.
Перед данными или кодом, которые уже введены в сегмент, вы
можете восстановить значение счетчика адреса. Это можно использо-
вать для возврата назад и заполнения записей таблицы, значения
которых не были известны во время определения таблицы. Используй-
те этот метод с осторожностью: вы можете непреднамеренно что-либо
затереть.
Директиву ORG можно использовать для того, чтобы связать
метку с конкретным адресом. Директива ORG может также использо-
ваться для задания начального адреса файлов .COM. Приведем приме-
ры ее использования:
PROG SEGMENT
ORG 100h ; начальное смещение файла .COM
start:
;
; остальная часть программы .COM
PROG ENDS
end start
Приведем другой пример:
PROG SEGMENT
ASSUME cs:PROG, ds:PROG, ss:PROG, es:NOTHING
ORG 20h
EnvPtr label word ; определить метку для доступа
; к слову в PSP, которое ука-
; зывает на сегмент, содержа-
; щий блок операционной среды
; (он обычно освобождается для
; создания более компактной
; резидентной программы)
ORG 80h
CmdLength lebel byte ; определить метку для доступа
; к длине командной строки
ORG @1h
CmdLine label byte ; определить метку для доступа
; к тексту командной строки
ORG 0100h
start:
; освободить блок операционной среды
mov es, EnvPtr ; ES -> блок операционной среды
mov ah, 49h ; функция 49h: освободить блок
; памяти
int 21h ; вызвать MS-DOS
jc error_ENV ; ошибка освобождения EnvBlock?
; анализ командной строки
mov al, CmdLength ; длина командной строки
or al,al ; проверка на 0
jz no_params ; нет параметров
mov cl,al ; поместить длину в cl
mov ch,0
mov si,offset CmdLine ; адрес командной строки
mov al,' ' ; символ для поиска
repne scasb ; поиск первого пробела
;
; остальная часть файла .COM резидентной программы:
PROG ENDS
end start
Директивы EVEN и EVENDATA
Вы можете использовать директиву EVEN для округления счетчи-
ка адреса до следующего четного адреса. Директива EVEN позволяет
вам выравнивать код для эффективного доступа к процессорам, ис-
пользующим 16-разрядную шину данных. Производительность процессо-
ров, использующих 8-разрядную шину данных, директивой EVEN не
улучшается.
Директива EVENDATA выполняет выравнивание на четную границу,
изменяя счетчика адреса без генерации данных, что полезно исполь-
зовать для неинициализированных сегментов. Директивы EVEN и
EVENDATA приводят к тому, что если выравнивание текущего сегмента
выполнено недостаточно строго, Турбо Ассемблер выводит предупреж-
дающее сообщение.
Если когда встречается директива EVEN счетчик адреса имеет
нечетное значение, то Турбо Ассемблер помещает в сегмент один
байт или инструкцию NOP, чтобы счетчик адреса стал четным. С по-
мощью заполнения инструкциями NOP директиву EVEN можно в сегмен-
тах кода, не вызывая на этапе работы программы выполнения невер-
ных инструкций. Если счетчик адреса уже имеет четное значение, то
данная директива не действует.
Аналогично, если счетчик адреса имеет нечетное значение,
когда встречается директива EVENDATA, Турбо Ассемблер генерирует
неинициализированный байт.
Приведем следующий пример использования директивы EVEN:
EVEN
@@A: lodsb
xor bl,al ; выравнивание для эффективного доступа
loop @@a
Приведем пример использования директивы EVENDATA:
EVENDATA
VAR1 DW 0 ; выравнивание для эффективного
; доступа 8086
Директива ALIGN
Для выравнивания счетчика адреса на адрес, значение которо-
го равно степени 2, можно использовать директиву ALIGN. Директива
ALIGN имеет следующий синтаксис:
ALIGN граница
где "граница" должна быть степенью 2.
Если счетчик адреса еще не соответствует смещению, которое
представляет собой произведение "границы", Турбо Ассемблер, чтобы
присвоить счетчика адреса нужный адрес, вставляет в сегмент инс-
трукции NOP (нет операции).
Вы не можете выполнить надежное выравнивание на границу, яв-
ляющееся более строгим, чем выравнивание сегмента, в котором
встречается директива ALIGN. Выравнивание сегмента задается, ког-
да сегмент в первый раз начинается по директива SEGMENT.
Например, если вы определили сегмент следующим образом:
CODE SEGMENT PARA PUBLIC
затем вы можете задать ALIGN 16 (что эквивалентно PARA), но не
ALIGN 32, как как это более строгое выравнивание, чем выравнива-
ние, заданное в директиве SEGMENT с помощью PARA. Если выравнива-
ние сегменте недостаточно строгое, то директива ALIGN генерирует
предупреждающее сообщение.
Использование директивы ALIGN показано в следующем примере:
ALIGN 4 ; выравнивание на границу DWORD для 386
BignNum DD 12345678
Определение меток
Метки позволяют вам присваивать значения идентификаторам.
Существует три способа определения меток:
- использование операции :;
- использование директивы LABEL;
- использование операции :: (MASM 5.1).
Операция :
Операция : определяет ближнюю метку кода и имеет синтаксис:
имя:
где "имя" - это идентификатор, который вы не объявляли ранее в
исходном коде. Ближние метки кода вы можете размещать на строке
кода, где содержится только одна метка, или в начале строки перед
инструкцией. Обычно ближние метки кода используются в качестве
адреса перехода в инструкциях JMP и CALL в том же сегменте.
Если вы не используете директиву PUBLIC, чтобы метка была
доступна из других файлов, она доступна только в текущем исходном
файле.
Данная директива работает точно также, как при использовании
директивы LABEL для определения ближней метки (NEAR). Например,
A: эквивалентно A LABEL NEAR.
Приведем пример использования операции :
jne A ; пропустить следующую инструкцию
inc si
A: ; jne передает управление сюда
Директива LABEL
Директиву LABEL вы можете использовать для определения иден-
тификатора заданного типа. Заметим, что синтаксис в режимах MASM
и Ideal различен. В режиме Ideal задавайте:
LABEL имя сложный_тип
В режиме MASM используйте следующее:
имя LABEL сложный_тип
где "имя" - это идентификатор, который вы не определяли ранее в
исходном файле. "Сложный_тип" описывает размер идентификатора и
то, ссылается он на код или данные. См. Главу 5, в которой можно
найти дальнейшую информацию о сложных типах.
Если вы не используете директиву PUBLIC, чтобы метка была
доступна из других файлов, она доступна только в текущем исходном
файле.
Вы можете использовать директиву LABEL для доступа к элемен-
там различного размера, которые содержатся в структуре данных.
Этот принцип иллюстрируется следующим примером:
WORDS LABEL WORD ; доступ к "BYTES" как к
; WORDS
BYTES DB 64 DUP (0)
mov WORDS[2],1 ; запись в WORDS 1
Директива ::
Директива :: позволяет вам определить с областью действия,
выходящей за рамки процедуры, в которой она находится. Это отли-
чается от директивы : тем, что метки, определенные с помощью :
имеют область действия только в текущей процедуре. Заметим, что
:: отличается от : только когда вы задаете язык в операторе
.MODEL. Приведем пример (файл DBLCOLON.ASM):
VERSION M510
.MODEL SMALL,C
.CODE
A PROC
NOP
ASINGLE:NOP
ADOUBLE::NOP
NOP
A ENDP
B PROC
NOP
JMP ASINGLE ; приведет к ошибке
JMP ADOUBLE
RET
B ENDP
END
Назад | Содержание | Вперед