Упрощенные Директивы Сегментации Стандартные директивы

advertisement
Упрощенные Директивы Сегментации
Стандартные директивы сегментации изначально использовались для
оформления программы в трансляторах MASM и TASM. Поэтому их называют
стандартными директивами сегментации. Для простых программ,
содержащих по одному сегменту для кода, данных и стека, хотелось бы
упростить ее описание. Для этого в трансляторы MASM и TASM ввели
возможность использования упрощенных директив сегментации. Но здесь
возникла проблема, связанная с тем, что необходимо было как-то
компенсировать невозможность напрямую управлять размещением и
комбинированием сегментов. Для этого совместно с упрощенными
директивами сегментации стали использовать директиву указания модели
памяти MODEL, которая частично стала управлять размещением сегментов и
выполнять функции директивы ASSUME (поэтому при использовании
упрощенных директив сегментации директиву ASSUME можно не
использовать). Директива MODEL связывает сегменты, которые в случае
использования упрощенных директив сегментации имеют предопределенные
имена, с сегментными регистрами (хотя явно инициализировать ds все равно
придется).
Пример программы с использованием упрощенных директив сегментации:
;---------------------------------------masm
;режим работы TASM: ideal или masm
model
small
;модель памяти
.data
;сегмент данных
message db
'Введите две шестнадцатеричные цифры,$'
.stack
;сегмент стека
db
256
dup ('?')
;сегмент стека
.code
;сегмент кода
main
proc
;начало процедуры main
mov
ax,@data
;заносим адрес сегмента
;данных в регистр ax
mov
ds,ax
;ax в ds
;далее текст программы (см. сегмента кода в листинге 3.1 книги)
mov
ax,4c00h
;пересылка 4c00h в регистр ax
int
21h
;вызов прерывания с номером 21h
main
endp
;конец процедуры main
end
main
;конец программы с точкой входа main
Синтаксис директивы MODEL:
Модификатор модели памяти
Значение
модификатора
Назначение
use16
Сегменты выбранной модели используются как 16битные (если соответствующей директивой указан
процессор i80386 или i80486)
use32
Сегменты выбранной модели используются как 32битные (если соответствующей директивой указан
процессор i80386 или i80486)
dos
Программа будет работать в MS-DOS
Модель памяти является обязательным параметром директивы MODEL.
Этот параметр определяет модель сегментации памяти для программного
модуля.
Модели памяти
Модель
TINY
SMALL
MEDIUM
Тип
Тип
кода данных
near
near
far
COMPACT near
Назначение модели
near
Код, данные и стек объединены в одну группу с
именем DGROUP и размером до 64Кб.
Используется для создания программ формата
.com. Некоторые языки эту модель не
поддерживают.
СS=DS=SS=DGROUP
near
Код занимает один сегмент, данные и стек
объединены в одну группу с именем DGROUP
(хотя для описания могут использоваться разные
сегменты). Эту модель обычно используют для
большинства программ на ассемблере.
CS=_text
DS=SS=DGROUP
near
Код занимает несколько сегментов, по одному на
каждый объединяемый программный модуль. Все
ссылки на передачу управления — типа far
(вызов подпрограмм). Данные и стек
объединены в одной группе DGROUP; все ссылки
на них — типа near (для доступа к данным
испльзуется только смещение).
CS=<модуль>_text
DS=SS=DGROUP
far
Код находится в одном сегменте, данные и стек
в группе DGROUP и могут занимать несколько
сегментов, так что для обращения к данным
требуется указывать сегмент и смещение (
ссылка на данные — типа far).
CS=_text
DS=SS=DGROUP
LARGE
far
far
Код может занимать несколько сегментов, по
одному на каждый объединяемый программный
модуль. Стек и данные находятся в группе
DGROUP. Для ссылки на данные используются
дальние указатели -far.
CS=<модуль>_text
DS=SS=DGROUP
HUGE
far
far
Тоже что и модель LARGE, что касается
TurboAssebmler.
far
Тоже, что и TINY, но используются 32-битная
адресация, так что максимальный размер
сегмента, содержащего и данные, и код, и стек 4Гб.
FLAT
far
Предполагается, что программный модуль может иметь только определенные
типы сегментов, которые определяются упомянутыми нами ранее
упрощенными директивами описания сегментов. Эти директивы приведены в
таблице ниже.
Упрощенные директивы определения сегмента
Формат
директивы
(режим
MASM)
Формат
директивы
(режим IDEAL)
Назначение
.CODE [имя] CODESEG[имя] Начало или продолжение сегмента кода
.DATA
DATASEG
.CONST
CONST
.DATA?
UDATASEG
Начало или продолжение сегмента
инициализированных данных. Также
используется для определения данных типа
near
Начало или продолжение сегмента
постоянных данных (констант) модуля
Начало или продолжение сегмента
неинициализированных данных. Также
используется для определения данных типа
near
.STACK
[размер]
STACK
[размер]
.FARDATA
[имя]
FARDATA [имя]
.FARDATA?
[имя]
UFARDATA
[имя]
Начало или продолжение сегмента стека
модуля. Параметр [размер] задает размер
стека
Начало или продолжение сегмента
инициализированных данных типа far
Начало или продолжение сегмента
неинициализированных данных типа far
Наличие в некоторых директивах параметра [имя] говорит о том, что
возможно определение нескольких сегментов этого типа. С другой стороны,
наличие нескольких видов сегментов данных обусловлено требованием
обеспечить совместимость с некоторыми компиляторами языков высокого
уровня, которые создают разные сегменты данных для инициализированных и
неинициализированных данных, а также констант.
При использовании директивы MODEL транслятор делает доступными
несколько идентификаторов, к которым можно обращаться во время работы
программы, с тем, чтобы получить информацию о тех или иных
характеристиках данной модели памяти.
Идентификаторы, создаваемые директивой MODEL
Имя
идентификатора
Значение переменной
@code
Физический адрес сегмента кода
@data
Физический адрес сегмента данных типа near
@fardata
Физический адрес сегмента данных типа far
@fardata?
Физический адрес сегмента неинициализированных
данных типа far
@curseg
Физический адрес сегмента неинициализированных
данных типа far
@stack
Физический адрес сегмента стека
Если вы посмотрите на текст примера, то увидите пример использования
одного из этих идентификаторов. Это @data – с его помощью мы получили
значение физического адреса сегмента данных нашей программы.
Необязательные параметры язык и модификатор языка определяют
некоторые особенности вызова процедур. Необходимость в использовании
этих параметров появляется при написании и связывании программ на
различных языках программирования.
Язык — необязательный операнд, принимающий значения C, PASCAL, BASIC,
FORTRAN, SYSCALL и STDCALL. Если он указан, подразумевается, что процедуры
рассчитаны на вызов из программ на соответствующем языке высокого уровня,
следовательно, если указан язык C, все имена ассемблерных процедур,
объявленных как PUBLIC, будут изменены так, чтобы начинаться с символа
подчеркивания, как это принято в C.
Модификатор — необязательный операнд, принимающий значения
NEARSTACK (по умолчанию) или FARSTACK. Во втором случае сегмент стека
не будет объединяться в одну группу с сегментами данных.
После того как модель памяти установлена, вступают в силу упрощенные
директивы определения сегментов, объединяющие действия директив
SEGMENT и ASSUME. Кроме того, сегменты, объявленные упрощенными
директивами, не требуется закрывать директивой ENDS — они закрываются
автоматически, как только ассемблер обнаруживает новую директиву
определения сегмента или конец программы.
Директива .CODE описывает основной сегмент кода
.code имя_сегмента
эквивалентно:
_TEXT segment word public ’CODE’
для моделей TINY, SMALL и COMPACT
name_TEXT segment word public ’CODE’
для моделей MEDIUM, HUGE и LARGE (name — имя модуля, в котором описан
данный сегмент). В этих моделях директива .CODE также допускает
необязательный операнд — имя определяемого сегмента, но все сегменты
кода, описанные так в одном и том же модуле, объединяются в один сегмент с
именем NAME_TEXT.
Директива .STACK описывает сегмент стека
.stack размер
эквивалентно:
STACK segment para public ’stack’
Необязательный параметр указывает размер стека. По умолчанию он равен 1
Кб.
Директива .DATA описывает обычный сегмент данных
.data
эквивалентно:
_DATA segment word public ’DATA’
Директива .DATA? описывает сегмент неинициализированных данных
.data?
Эквивалентно:
_BSS segment word public ’BSS’
Этот сегмент обычно не включается в программу, а располагается за концом
памяти, так что все описанные в нем переменные на момент загрузки
программы имеют неопределенные значения.
Директива .CONST описывает сегмент неизменяемых данных
.const
Эквивалентно:
CONST segment word public ’CONST’
В некоторых операционных системах этот сегмент будет загружен так, что
попытка записи в него может привести к ошибке.
Директива .FARDATA описывает сегмент дальних данных
.fardata имя_сегмента
эквивалентно:
имя_сегмента segment para private ’FAR_DATA’
Доступ к данным, описанным в этом сегменте, потребует загрузки сегментного
регистра. Если не указан операнд, в качестве имени сегмента используется
FAR_DATA.
Директива .FARDATA? описывает сегмент дальних неинициализированных
данных
.fardata? имя_сегмента
эквивалентно:
имя_сегмента segment para private ’FAR_BSS’
Как и в случае с FARDATA, доступ к данным из этого сегмента потребует
загрузки сегментного регистра. Если имя сегмента не указано, используется
FAR_BSS.
Во всех моделях памяти сегменты, представленные директивами .DATA,
.DATA?, .CONST, .FARDATA и .FARDATA?, а также сегмент, описанный
директивой .STACK, если не был указан модификатор FARSTACK, и сегмент
.CODE в модели TINY автоматически объединяются в группу с именем FLAT
— для модели памяти FLAT или DGROUP — для всех остальных моделей. При
этом сегментный регистр DS (и SS, если не было FARSTACK, и CS в модели
TINY) настраивается на всю эту группу, как если бы была выполнена команда
ASSUME.
Порядок загрузки сегментов
При использовании стандартных директив сегментации сегменты
загружаются в память в том порядке, в котором они описываются в тексте
программы.
При использовании упрощенных директив сегментации (по умолчанию)
устанавливается порядок загрузки сегментов, существующий в MS DOS и часто
требуемый для взаимодействия программ на ассемблере с программами на
языках высокого уровня.
Порядок загрузки сегментов:
1. Все сегменты класса 'CODE'.
2. Все сегменты, не принадлежащие группе DGROUP и классу 'CODE'.
3. Группа сегментов DGROUP:
3.1. Все сегменты класса 'BEGDATA'.
3.2. Все сегменты, кроме классов 'BEGDATA', 'BSS' и 'STACK'.
3.3. Все сегменты класса 'BSS'.
3.4. Все сегменты класса 'STACK'.
Знание порядка загрузки сегментов необходимо, например, для вычисления
длины программы или адреса ее конца. Для этого надо знать, какой сегмент
будет загружен последним, и смещение последнего байта в нем.
P.S. В книге Зубкова, порядок загрузки сегментов описан несколько иначе, НО
практика показала, что его описание не правильное. При использовании
упрощенных директив сегментации, директива .seq, которая, по идее должна
устанавливать порядок загрузки сегментов, как они описаны в прорамме, этого
не делает! А делает это дериктива .alpha, и то, только при использовании
TASM, только в модели small, и при этом она добавляет заголовок в exe файл
длиной 600h байт! MASM же, при использовании упрощенных директив
сегментации всегда размещает сегменты в соответствии с порядком MS DOS,
забивая на директивы .seq и .alpha. И еще с выравниванием сегментов, при
использовании упрощенных директив сегментации, происходит какая-то
свистопляска :). Все это выявлено опытным путем. Все в следующих сериях
супер сериала "Hello World". И так, жем вас у экранов мониторов :)
АВТ ОР: - =* =- ЯРЛ Ы КИ: Д ИРЕКТ ИВА MOD EL , Д ИРЕКТ ИВ А SEGM ENT , СИНТ АКСИС
АССЕМБЛЕРА НА 7:51
0 КОММЕНТ.:
Отправить комментарий
Следующее Предыдущее Главная страница
Download