Код
|
Префикс
|
Описание
|
26
|
ES:
|
Использование сегмента ES.
|
2E
|
CS:
|
Использование сегмента CS.
|
36
|
SS:
|
Использование сегмента SS.
|
3E
|
DS:
|
Использование сегмента DS.
|
Приведем примеры явного указания сегментных регистров. Предположим, требуется записать в регистр АХ содержимое ячейки памяти M, расположенной в сегменте команд. Использовать команду MOV AX,M нельзя, поскольку она воспримется как MOV AX, DS:M и потому запишет в АХ содержимое ячейки, имеющей смещение M, но находящейся в сегменте данных. Поэтому следует явно указать сегментный регистр, т.е. записать команду MOV AX, CS:M.
Другой типичный случай – требуется работать с сегментом памяти, отличным от сегментов команд, данных и стека. В этом случае на начало сегмента устанавливается регистр ES и при ссылках на ячейки сегмента используется этот регистр, например: MOV AX, ES:M. Опускать префикс ES: нельзя, т.к. он не подразумевается по умолчанию.
4.2. Директивы сегментации
Все предложения, которые требуется разместить в одном сегменте памяти, в исходном тексте программы должны быть объединены в один программный сегмент, который имеет следующую структуру:
<имя сегмента> SEGMENT <параметры>
<предложение>
...
<предложение>
<имя сегмент> ENDS
Между директивами может быть указано любое число предложений, которые ассемблер разместит в одном сегменте памяти. Размер сегмента не должен превышать 64 Кб. В программе может быть несколько сегментов с одним и тем же именем. В этом случае они рассматриваются как один сегмент, разделенный на несколько частей, и все предложения из этих сегментов ассемблер объединит вместе.
Ассемблер размещает в памяти программные сегменты последовательно, с адреса, кратного 16 (выравнивание по границе параграфа), и имени каждого сегмента присваивает его номер в памяти, т.е. первые 16 разрядов начального адреса данного сегмента.
Приведем пример использования директивы SEGMENT:
A SEGMENT
A1 DB 100h DUP(?)
A2 DW 8
A ENDS
В SEGMENT
B1 DW A2
B2 DD А2
В ENDS
С SEGMENT
L: MOV AX, A2
MOV BX, B2
С ENDS
При трансляции предложений ассемблер ставит в соответствие описанным именам переменных и меткам адреса – смещения соответствующих ячеек памяти, отсчитанные от начала сегмента. В примере имя A1 получит смещение 0, имя A2 – смещение 100h, имя B1 – смещение 0, имя B2 – смещение 2, имя L – смещение 0. Имена переменных и метки рассматриваются как адресные выражения. Но есть возможность рассматривать их и как константные, для чего используется оператор:
OFFSET <имя>
Значением оператора является смещение переменной, относительно начала сегмента, в котором оно описано:
OFFSET A1 = 0
OFFSET A2 = 100h
OFFSET L = 0
Оператор SEG позволяет узнать, в каком сегменте описано имя переменной или метка:
SEG <имя>
Значением оператора является имя сегмента, в котором описана переменная-операнд:
SEG A1 = SEG A2 = А
SEG B1 = SEG B2 = В
SEG L = С
Директива SEGMENT не содержит информации о функциональном назначении сегментов, поэтому все сегменты равноправны. Директива ASSUME (предполагать) позволяет сообщить транслятору, что данный сегмент будет использоваться как сегмент кода, данных или стека.
Директиву ASSUME обычно указывают в начале сегмента команд:
ASSUME <пара> {, <пара>}
где <пара> обозначает адресную пару <сегментный регистр>:<имя сегмента>
Например, директива:
ASSUME ES: A, DS: B, CS: C
сообщает транслятору, что для сегментирования адресов из сегмента A выбран регистр ES, для адресов из сегмента B – регистр DS, а для адресов из сегмента C – регистр CS.
Например, команда MOV AX, A2 будет транслироваться как MOV AX, ES:A2 (имя A2 описано в сегменте А), а команда MOV АХ, B2 как MOV AX, DS:B2 (имя B2 описано в сегменте B).
Перечисли особенности применения директивы ASSUME. Если в директиве ASSUME указано несколько пар с одним сегментным регистром, то последнее объявление отменяет предыдущее, т.к. каждому сегментному регистру можно поставить в соответствие только один сегмент. Например, по директиве:
ASSUME DS:A, DS:B
ассемблер будет считать, что регистр DS указывает только на сегмент В.
На один и тот же сегмент могут указывать разные сегментные регистры. Например, в следующей директиве:
ASSUME ES:A, DS:A
на сегмент A будут указывать регистры ES и DS. Ассемблер выберет префикс, который в транслируемой команде подразумевается по умолчанию, поскольку его можно опустить и сэкономить память.
Если в директиве ASSUME в качестве второго элемента пары задано служебное слово NOTHING (ничего), например ASSUME ES:NOTHING, то сегментный регистр не указывает ни на какой сегмент, и ассемблер не должен использовать регистр при трансляции команд. Для отмены ранее установленных соответствий для всех сегментных регистров, используется конструкция:
ASSUME NOTHING
Директива ASSUME может быть указана любое число раз. При этом несколько подряд идущих директив можно объединить в одну. Например, последовательность директив:
ASSUME ES:A ASSUME DS:B ASSUME CS:C
эквивалентна директиве:
ASSUME ES:A, DS:B, CS:C
Следует заметить, что директива ASSUME не загружает в сегментные регистры начальные адреса сегментов. Поэтому выполнение программы должно начинаться с загрузки в сегментные регистры начальных адресов соответствующих сегментов памяти.
Например, сегментный регистр DS требуется установить на начало сегмента B, т.е. выполнить присваивание DS:=B. Команда пересылки MOV DS, B недопустима, т.к. имя сегмента есть константное выражение, а помещение непосредственного операнда в сегментный регистр запрещена. Поэтому инициализацию регистра DS можно выполнить, используя только несегментный регистр, например АХ:
MOV AX, B
MOV DS, AX
Аналогично загружаются регистр ES. Регистр CS загружать не нужно, т.к. к началу выполнения программы регистр уже будет указывать на начало сегмента команд. Такую загрузку выполнит операционная система, прежде чем передаст управление программе.
Регистр SS должен указывать на начало стека. Настроить его можно аналогично DS или поручить операционной системе. В последнем случае в директиве SEGMENT необходимо указать параметр STACK:
S SEGMENT STACK
В результате загрузка S в регистр SS будет выполнена автоматически до начала выполнения программы.
Do'stlaringiz bilan baham: |