Директивы сегментации

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

 

<имя сегмента> 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 будет выполнена автоматически до на­чала выполнения программы.