Загрузка...

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


Далее мы приведем такой же пример программы, как и в преды-дущем разделе, но на этот раз используем стандартные директивы определения сегментов SEGMENT, ENDS и ASSUME.

DGROUP GROUP _DATA, STACK

ASSUME CS:_TEXT, DS:_DATA, SS:STACK

STACK SEGMENT PARA STACK ‘STACK’

DB 200h DUP (?)

STACK ENDS

_DATA SEGMENT WORD PUBLIC ‘DATA’

MemVar DW 0

_DATA ENDS

_TEXT SEGMENT WORD PUBLIC ‘CODE’

ProgramStart:

mov ax,_DATA

mov ds,ax

mov ax,[MemVar]

mov ah,4ch

int 21h

_TEXT ENDS

END ProgramStart

Теперь вы видите, почему упрощенные директивы определения сегментов называются упрощенными. Однако, многое из того, что де-лают упрощенные директивы определения сегментов предназначено для того, чтобы облегчить компоновку модулей Ассемблера с языками вы-сокого уровня, что является излишним в автономных программах на Ассемблере. Приведем пример программы HELLO с использованием стандартных директив определения сегментов:

Stack Segment PARA STACK ‘STACK’

DB 200h DUP (?)

Stack ENDS

Data SEGMENT WORD ‘DATA’

HelloMessage DB ‘Привет!’,13,10,’$’

Data ENDS

Code Segment WORD ‘CODE’

ASSUME CS:Code, DS:Data

ProgramStart:

mov ax,Data

mov ds,ax ; установить DS в значение

; сегмента данных

mov dx,OFFSET HelloMessage ; DS:DX указывает

; на сообщение ‘Привет!’

mov ah,9 ; функция DOS вывода строки

int 21h ; вывести строку на экран

mov ah,4ch ; функция DOS завершения

; программы

int 21h ; завершить программу

Code ENDS

END ProgramStart

Последний пример не слишком усложнился, но тем не менее яс-но, что стандартные директивы определения сегментов более сложны, чем упрощенные директивы.

В Главе 9 стандартные (полные) директивы определения сегмен-тов описываются более подробно. В данном разделе разделе мы пы-таемся только дать вам представление о том, что делают стандарт-ные директивы определения сегментов.

Директива SEGMENT

Директива SEGMENT определяет начало сегмента. Метка, которая указывается в данной директиве, определяет начало сегмента. Нап-ример, директива:

Cseg SEGMENT

определяет начало сегмента с именем Cseg. Директива SEGMENT может также (необязательно) определять атрибуты сегмента, включая вы-равнивание в памяти на границу байта, слова, двойного слова, па-раграфа (16 байт) или страницы (256 байт). Другие атрибуты вклю-чают в себя способ, с помощью которого сегмент будет комбиниро-ваться с другими сегментами с тем же именем и классом сегмента.

Директива ENDS

Директива ENDS определяет конец сегмента. Например:

Cseg ENDS

завершает сегмент с именем Cseg, который начинался по директиве SEGMENT. При использовании стандартных директив определения сег-ментов вы должны явным образом завершать каждый сегмент.

Директива ASSUME

Директива ASSUME указывает Турбо Ассемблеру, что в значение какого сегмента установлен данный сегментный регистр. Директиву ASSUME CS: требуется указывать в каждой программе, в которой ис-пользуются стандартные сегментные директивы, так как Турбо Ас-семблеру необходимо знать о сегменте кода для того, чтобы устано-вить выполняемую программу. Кроме того, обычно используются директивы ASSUME DS: и ASSUME ES:, благодаря которым Турбо Ас-семблер знает, к каким ячейкам памяти вы можете адресоваться в данный момент.

Директива ASSUME позволяет Турбо Ассемблеру проверить допус-тимость каждого обращения к именованной ячейке памяти с учетом значения текущего сегментного регистра. Рассмотрим следующий при-мер:

Data1 SEGMENT WORD ‘DATA’

Var1 DW 0

Data1 ENDS

Data2 SEGMENT WORD ‘DATA’

Var2 DW 0

Data2 ENDS

Code SEGMENT WORD ‘CODE’

ASSUME CS:Code

ProgramStart:

mov ax,Data1

mov ds,ax ; установить DS в Data1

ASSUME DS:Data1

mov ax,[Var2] ; попытаться загрузить Var2 в AX

; это приведет к ошибке, так как

; Var2 недоступна в сегменте

; Data1

mov ah,4ch ; номер функции DOS для

; завершения программы

int 21h ; завершить программу

Code ENDS

END ProgramStart

Турбо Ассемблер отмечает в данной программе ошибку, так как в ней делается попытка получить доступ к переменной памяти Var2, когда регистр DS установлен в значение сегмента Data1 (к Var2 нельзя адресоваться, пока DS не будет установлен в значение сег-мента Data2).

Важно понимать, что Ассемблер на самом деле не знает, что регистр DS установлен в значение Data1. С помощью директивы ASSUME вы указали Турбо Ассемблеру, что нужно сделать такое допу-щение. Директива ASSUME дает вам способ в любой момент сообщить Ассемблеру о значении сегментного регистра, после чего Турбо Ас-семблер будет сообщать вам, если вы пытаетесь сделать невозмож-ное.

Однако Турбо Ассемблер не может перехватывать все подобные ошибки. Когда в ссылке на память используется именованная пере-менная памяти (такая, как Var1 и Var2 в предыдущем примере), Тур-бо Ассемблер может проверить допустимость этой ссылки, так как каждая именованная переменная памяти явным образом связана с сег-ментом. Невозможно сообщить Турбо Ассемблеру, к какому сегменту пытается обратиться инструкция:

mov al,[bx]

В этом случае Турбо Ассемблер должен предположить, что зна-чение сегментного регистра DS соответствует тому сегменту, к ко-торому вы хотите обратиться.

Если в данный момент сегментный регистр не указывает ни на какой именованный сегмент, то чтобы сообщить об этом Ассемблеру, можно использовать в директиве ASSUME ключевое слово NOTHING.

Например:

mov ax,0b800h

mov ds,ax

ASSUME ds:NOTHING

Здесь регистр DS устанавливается таким образом, чтобы указы-вать на цветной графический экран, а затем Турбо Ассемблеру сооб-щается, что регистр DS не указывает ни на какой именованный сег-мент. Вот еще один способ ссылки на цветной графический экран:

ColorTextSeg SEGMENT AT 0B8000h

ColorTextMemory LABEL BYTE

ColorTextSeg ENDS

mov ax,ColorTextSeg

mov ds,ax

ASSUME ds:ColorTextSeg

Обратите внимание, что в директиве AT, которая следует за директивой SEGMENT, задается явный начальный адрес сегмента.

Сделаем последнее замечание по директиве ASSUME: в некоторых случаях она может привести к тому, что Турбо Ассемблер будет ис-пользовать для доступа к памяти не тот сегментный регистр, кото-рый вы ожидаете, а другой. Рассмотрим, например, следующий фраг-мент программы:

Data1 SEGMENT WORD ‘DATA’

Var1 DW 0

Data1 ENDS

Data2 SEGMENT WORD ‘DATA’

Var2 DW 0

Data2 ENDS

Code SEGMENT WORD ‘CODE’

ASSUME CS:Code

ProgramStart:

mov ax,Data1

mov ds,ax ; установить DS в Data1

ASSUME DS:Data1

mov ax,Data2

mov es,ax ; установить ES в Data2

ASSUME ES:Data2

mov ax,[Var2] ; загрузить Var2 в AX —

; Турбо Ассемблер укажет

; процессору 8086, что

; загрузку нужно выполнять

; относительно ES, так как

; к Var2 нельзя получить

; доступ относительно DS

mov ah,4ch ; функция DOS завершения

; работы программы

int 21h ; завершить программу

Code ENDS

END ProgramStart

Данный пример должен быть вам знаком: это модифицированная версия фрагмента программы, использованного нами ранее для того, чтобы показать, как директива ASSUME позволяет Турбо Ассемблеру указать вам, когда вы пытаетесь использовать недопустимую ссылку на память. Однако в данном примере сообщение об ошибке не выво-дится. Но это не означает, что Турбо Ассемблер позволяет вам сде-лать ошибку. Он модифицирует инструкцию:

mov ax,[Var2]

для доступа к Var2 относительно сегментного регистра ES, а не сегментного регистра DS.

Это происходит по следующим причинам. Две директивы ASSUME информируют Турбо Ассемблер о том, что регистр DS установлен в значение сегмента Data1, а ES установлен в значение сегмента Data2. Турбо Ассемблер совершенно правильно заключает, что к Var2 нельзя получить доступ относительно регистра DS, однако Var2 дос-тупно относительно сегментного регистра ES. В итоге Турбо Ассем-блер включает перед инструкцией MOV специальный код (префикс пе-реопределения сегмента), чтобы указать процессору 8086, что вмес-то сегментного регистра DS нужно использовать сегментный регистр ES.

Какое все это имеет для вас значение? Это значит, что если вы корректно используете директивы ASSUME, позволяя Турбо Ассем-блеру узнать о текущих установленных для регистров DS и ES значе-ниях, то он может автоматически вам помочь, проверяя возможность доступа к именованным переменным в памяти и в некоторых случаях даже может выполнить автоматическую корректировку сегмента.

Общее обсуждение префиксов переопределения сегментов и стан-дартные директивы определения сегментов обсуждаются в Главе 10.

Загрузка...