Материал: Системное программирование

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

В качестве сегментных регистров можно использовать регистры CS, DS, SS и ES. Начальные адреса сегментов памяти можно хранить и в других регистрах, однако использовать их для сегментирования адресов не удастся.

На начальные адреса сегментов накладываются ограничения. В связи с тем, что абсолютные адреса 20-разрядные, а сегментные регистры 16-разрядные, адрес сегмента должен быть кратен 16 (последние 4 бита нулевые, что в шестнадцатеричной форме имеет вид xxxx0h). В результате в сегментных регистрах хранятся первые 16 битов начального адреса сегмента (рис. 16).

Рис. 16. Схема формирования физического адреса.

Например, если адресом начала сегмента является число 12340h, то в сегментном регистре будет храниться величина 1234h. Процессор учитывает такую особенность и при сегментировании адреса к содержимому сегментного регистра добавляет справа 0 и затем прибавляет смещение, указанное в команде. Поскольку добавление справа нуля к шестнадцатеричному числу эквивален­тно умножению числа на 16, то формула вычисления абсолютного адреса по адресной паре CS:disp имеет вид:

При записи ко­манд на ассемблере конструкция вида:

<сегментный регистр>:<адресное выражение>

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

Логический адрес может находиться в пределах:

0000h:0000h <= [логический адрес] <= FFFFh:000Fh

На рис. 17 изображено все доступное адресное пространство оперативной памяти. Показан некоторый сегмент (он может относиться к сегменту кода, данных, стека или к дополнительному сегменту), расположенный по адресу 0010h. В самом сегменте указан адрес с помощью смещения 0120h. Таким образом, логический адрес 0010h:0120h соответствует физическому адресу 00120h.

Рис. 17. Соответствие физического адреса логическому.

Запись вида CS:, DS:, SS: и ES: принято называть префиксом сегментного регистра. Префикс указывается перед адресом, который должен быть просегментирован. С помощью префикса замены сегмента можно обратиться к операнду с использованием любого из четырёх сегментных регистров. Функциональное распределение сегментных регистров следующее (рис. 18).

Ре­гистр CS всегда должен указывать на начало сегмента команд. Адрес очередной подлежащей выполнению команды, указы­вается регистровой парой CS:IP. Указатель команд IP содержит смещение команды, отсчитанное от начала сегмента команд. Регистр DS должен указывать на начало сегмен­та данных, а SS – на начало сегмента стека. Регистр ES (а также позднее введенные FS и GS) может указывать на любой сегмент памяти. Например, инструкция MOV AX, [BP] загружает в регистр AX содержимое слова памяти по адресу SS:BP, однако, инструкция MOV AX, ES:[BP] загрузит содержимое слова по адресу ES:BP.

Рис. 18. Распределение памяти с помощью сегментных регистров.

Коды сегментных префиксов приведены в табл. 5. Вместо сегментного регистра DS может использоваться любой сегментный регистр, для чего необходимо задать соответствующий префикс замены сегмента. Доступ к стековой памяти с использованием указателя стека SP всегда подразумевает использование только сегментного регистра SS.

Табл. 5. Сегментные префиксы.

Код

Префикс

Описание

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

MOVBX,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

эквивалентна директиве:

ASSUMEES:A,DS:B,CS:C

Следует заметить, что директива ASSUME не загружает в сегментные ре­гистры начальные адреса сегментов. Поэтому выполне­ние программы должно начинаться с загрузки в сегментные регистры начальных адресов соответствующих сегментов памяти.

Например, сегментный регистр DS требуется установить на начало сегмента B, т.е. выполнить присваивание DS:=B. Команда пересылки MOV DS, B недопустима, т.к. имя сегмента есть константное выражение, а помещение непосредственного операнда в сегментный регистр запрещена. Поэтому инициализацию регистра DS можно выполнить, используя только несегментный регистр, например АХ:

MOV AX, B

MOV DS, AX

Аналогично загружаются регистр ES. Регистр CS загружать не нужно, т.к. к началу выполнения программы регистр уже будет указывать на начало сегмента команд. Такую загрузку выполнит операционная система, прежде чем передаст управ­ление программе.

Источник: https://files.student-it.ru/previewfile/284711