3.3.1. Сегменты

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

Сегмент программы описывается директивами SEGMENT и ENDS.

имя.сегмента      segment readonly выравн.  тип разряд 'класс'

ends

Имя сегмента - метка, которая будет использоваться для получения сегмент­ного адреса, а также для комбинирования сегментов в группы. Все пять операндов директивы SEGMENT необязательны.

READONLY. Если этот операнд присутствует, MASM выдаст сообщение об ошибке на все команды, выполняющие запись в данный сегмент. Другие ассемб­леры этот операнд игнорируют.

Выравнивание. Указывает ассемблеру и компоновщику, с какого адреса может начинаться сегмент. Значения этого операнда:

Q BYTE - с любого адреса;

□ WORD - с четного адреса;

□ DWORD - с адреса, кратного 4;

□ PARA - с адреса, кратного 16 (граница параграфа);

□ PAGE - с адреса, кратного 256.

По умолчанию используется выравнивание по границе параграфа.

Тип. Выбирает один из возможных типов комбинирования сегментов:

тип PUBLIC (иногда используется синоним MEMORY) означает, что все та­кие сегменты с одинаковым именем, но разными классами будут объедине­ны в один;

тип STACK - то же самое, что и PUBLIC, но должен использоваться для сег­ментов стека, потому что при загрузке программы сегмент, полученный объеди­нением всех сегментов типа STACK, будет использоваться как стек; Q сегменты типа COMMON с одинаковым именем также объединяются в один, но не последовательно, а по одному и тому же адресу, следовательно, длина суммарного сегмента будет равна не сумме длин объединяемых сегментов,

как в случае PUBLIC и STACK, а длине максимального. Таким способом иногда можно формировать оверлейные программы;

тип AT - выражение указывает, что сегмент должен располагаться по фик­сированному абсолютному адресу в памяти. Результат выражения, исполь­зующегося в качестве операнда для AT, равен этому адресу, деленному на 16. Например: segment at 40h - сегмент, начинающийся по абсолютному адресу 0400h. Такие сегменты обычно содержат только метки, указывающие на об­ласти памяти, которые могут потребоваться программе; □ PRIVATE (значение по умолчанию) - сегмент такого типа не объединяется с другими сегментами.

Разрядность. Этот операнд может принимать значения USE16 и USE32. Раз­мер сегмента, описанного как USE16, не может превышать 64 Кб, и все команды и адреса в этом сегменте считаются 16-битными. В этих сегментах все равно мож­но применять команды, использующие 32-битные регистры или ссылающиеся на данные в 32-битных сегментах, но они будут использовать префикс изменения разрядности операнда или адреса и окажутся длиннее и медленнее. Сегменты

могут занимать до 4 Гб, и все команды и адреса в них по умолчанию ные. Если разрядность сегмента не указана, по умолчанию используется 16 при условии, что перед .MODELне применялась директива задания допустимого набора команд .386 или старше.

Класс сегмента - это любая метка, взятая в одинарные кавычки. Все сегменты с одинаковым классом, даже сегменты типа PRIVATE, будут расположены в ис­полняемом файле непосредственно друг за другом.

Для обращения к любому сегменту следует загрузить его сегментный адрес (или селектор в защищенном режиме) в какой-нибудь сегментный регистр.

Если в программе определено много сегментов, удобно объединить несколько сег­ментов в группу, адресуемую с помощью одного сегментного регистра:

group

Операнды этой директивы - список имен сегментов (или выражений,

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

директивы ASSUME.

assume регистр:связь,..

Директива ASSUME указывает ассемблеру, с каким сегментом или группой сегментов связан тот или иной сегментный регистр. В качестве операнда «связь» могут использоваться имена сегментов, имена групп, выражения с оператором SEGmiH слово «NOTHING», означающее отмену действия предыдущей ASSUME для данного регистра. Эта директива не изменяет значений сегментных регист­ров, а только позволяет ассемблеру проверять допустимость ссылок и самостоя­тельно вставлять при необходимости префиксы переопределения сегментов.

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