 |
цессор 8086 в любое время позволяет вам получить доступ к любой
ячейке памяти в пределах 1 Мбайта, но только в блоках по 64К (от-
носительно сегментного регистра).
Вы можете захотеть загрузить регистр DS одним сегментом, по-
лучить доступ к данным в этом сегменте, а затем загрузить DS дру-
гим сегментом, чтобы обратиться к другому блоку данных. В малень-
ких и средних программах (таких, как в приведенных нами примерах)
вам не потребуется использовать более одного сегмента данных, но
в больших программах несколько сегментов данных используется час-
то. Кроме того, вам потребуется загружать регистр DS различным
значениями, если вы хотите получить доступ к системным областям
памяти, например, к ячейкам памяти, используемым базовой системой
ввода-вывода (BIOS).
Из всего этого можно сделать следующий краткий вывод: Турбо
Ассемблер позволяет вам в любой момент установить регистр DS в
значение любого сегмента. За эту гибкость приходится расплачи-
ваться тем, что вы должны явно устанавливать регистр DS в значе-
ние нужного сегмента (обычно @data), что эквивалентно сегменту,
который начинается с директивы .DATA. После этого вы сможете по-
лучить доступ к ячейкам памяти этого сегмента.
Сегментный регистр ES загружается аналогично регистру DS.
Чаще всего вам не потребуется использовать регистр ES, но когда
появится необходимость получить доступ к ячейке памяти в сегмен-
те, на который указывает регистр ES, вы должны сначала загрузить
регистр ES значением этого сегмента. Например, следующая прог-
рамма загружает регистр ES значением сегмента .DATA, а затем
загружает через ES символ, который нужно напечатать из этого
сегмента:
DOSSEG
.MODEL small
.STACK 200h
.DATA
OutputChar DB 'B'
.CODE
ProgramStart:
mov dx,@data
mov es,dx ; установить ES в значение
; сегмента .DATA
mov bx,OFFSET OutputChar ; BX указывает на
; смещение OutputChar
mov al,es:[bx] ; получить выводимый символ
; из сегмента, на который
; указывает регистр ES
mov ah,2 ; функция DOS вывода символа
int 21h ; вызвать DOS для вывода
; символа на экран
END ProgramStart
Обратите внимание, что регистр ES (как и регистр DS ранее)
загружается последовательностью из двух инструкций:
.
.
.
mov dx,@Data
mov es,dx
.
.
.
Положим, в данном примере нет конкретной причины использо-
вать вместо DS регистр ES. Фактически, использование регистра ES
означает, что мы применили префикс переопределения сегмента ES:
(как это описывается в Главе 9). Однако во многих случаях чрезвы-
чайно удобно, когда регистр DS указывает на один сегмент, а ре-
гистр ES - на другой (особенно это касается использования строко-
вых инструкций).
Директива DOSSEG
-----------------------------------------------------------------
Директива DOSSEG приводит к тому, что сегменты в программе
Ассемблера будут сгруппированы в соответствии с соглашениями по
упорядочиванию сегментов фирмы Microsoft. В данным момент вам не
следует вникать в смысл того, что это означает. Запомните просто,
что почти все автономные программы на Ассемблере будут прекрасно
работать, если вы начнете их с директивы DOSSEG.
При компоновке модулей Ассемблера с модулями языков высокого
уровня задавать директиву DOSSEG не обязательно, так как в языке
высокого уровня автоматически выбирается упорядочивание сегментов
по стандарту фирмы Microsoft. Однако эта директива не повредит.
Из всего перечисленного можно сделать заключение, что ис-
пользование директивы DOSSEG в качестве первой строки вашей прог-
раммы является простейшим подходом (если у вас нет конкретной
причины поступать иначе). Благодаря этому вы сможете использовать
определенный порядок сегментов (более подробно о директиве DOSSEG
рассказывается в Главе 3 "Справочного руководства").
Директива .MODEL
-----------------------------------------------------------------
Директива .MODEL определяет модель памяти в модуле Ассембле-
ра, где используются упрощенные директивы определения сегментов.
Заметим, что в "ближнем" коде переходы осуществляются с помощью
загрузки одного регистра IP, а в "дальнем" коде - путем загрузки
регистров CS и IP. Аналогично, к "ближним" данным обращение вы-
полняется только по смещению, а к "дальним" - с помощью полного
адреса "сегмент:смещение". Вкратце, термин "дальний" (FAR) озна-
чает использование полного 32-разрядного адреса ("сегмент:смеще-
ние"), а "ближний" (NEAR) означает использование 16-разрядных
смещений.
Существуют следующие модели памяти:
Сверхмалая И код программы, и ее данные должны размещаться
внутри одного и того же сегмента размером 64К.
Код и данные имеют ближний тип.
Малая Код программы должен размещаться внутри одного
сегмента данных размером 64К, а данные программы
должны размещаться в отдельном сегмента данных
(размером 64К). И код, и данные должны быть ближ-
него типа.
Средняя Код программы может превышать 64К, но данные
программы должны помещаться в один сегмент разме-
ром 64К. Код имеет дальний тип, а данные - ближ-
ний.
Компактная Код программы должен помещаться в один сегмент
размером 64К, а данные могут превышать по размеру
64К. Код имеет ближний тип, а данные - дальнего
типа.
Большая И код, и данные программы могут превышать 64К, но
один массив данных не может превышать 64К. И код,
и данные имеют дальний тип.
Сверхбольшая И код, и данные программы могут превышать по раз-
меру 64К. Массивы данных также могут превышать
64К. Код и данные имеют дальний тип. Указатели на
элементы массива также дальнего типа.
Заметим, что с точки зрения Ассемблера большая и сверхболь-
шая модели идентичны. Сверхбольшая модель не поддерживает автома-
тически массивы данных, превышающие 64К.
Немногие программы на Ассемблере используют более 64К кода
или данных, поэтому для большинства прикладных задач подходит ма-
лая модель. Вы должны использовать малую модель там, где это воз-
можно, так как дальний код (средняя, большая и сверхбольшая мо-
дель) замедляет выполнение программы, а с данными дальнего типа
(компактная, большая и сверхбольшая модель) на Ассемблере рабо-
тать значительно труднее.
Описанные здесь модели памяти соответствуют моделям, исполь-
зуемым в Турбо Си (и во многих других компиляторах для компьютера
IBM PC). Когда вы компонуете модуль на Ассемблере с языком высо-
кого уровня, убедитесь, что используется правильная директива
.MODEL. Эта директива обеспечивает соответствие имен сегментов
Ассемблера тем именам, которые используются в языках высокого
уровня, а также используемого по умолчанию типа меток PROC, ис-
пользующихся для наименования подпрограмм, процедур и функций,
типу (ближнему или дальнему), используемому в языках высокого
уровня.
Директиву .MODEL необходимо указывать, если вы используете
упрощенные директивы определения сегментов, так как в противном
случае Турбо Ассемблер не будет знать как устанавливать сегменты,
определенные с помощью директив .CODE и .DATA. Директива .MODEL
должна предшествовать директивам .CODE, .DATA и .STACK.
Приведем пример наброска программы, использующей упрощенные
директивы определения сегментов:
DOSSEG
.MODEL small
.STACK 200h
.DATA
MemVar DW 0
.
.
.
.CODE
ProgramStart:
mov ax,@data
mov ds,ax
mov ax,[MemVar]
.
.
.
mov ah,4ch
int 21h
END ProgramStart
Другие упрощенные директивы определения сегментов
-----------------------------------------------------------------
Имеется еще несколько общеупотребительных директив определе-
|