Материал: 1117

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

2) из стандартных (полных) директив определения сегментов (более сложно использовать, но он предусматривает полное управление сегментами, необходимое в некоторых прикладных программах ассемблера; см. уч. пос., ч.2, 10 и 11).

Взависимости от того, сколько и каких сегментов предусматривается

впрограмме, различают следующие модели памяти.

Сверхмалая (tiny) – код программы и ее данные должны размещаться внутри одного и того же сегмента размером 64 Кб. Код и данные имеют ближний тип (см. уч. пос., ч.3 и 7).

Малая (small) – код программы должен размещаться внутри одного сегмента данных размером 64 Кб, а данные – в отдельном сегменте данных (размером 64 Кб). И код, и данные должны быть ближнего типа (см. уч.

пос., ч.4 и 5).

Средняя (medium) – код программы может превышать 64 Кб, но данные должны помещаться в один сегмент размером 64 Кб. Код имеет дальний тип, а данные – ближний (см. уч. пос., ч.2 и 6).

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

ч.14).

Большая (large) – код и данные программы могут превышать 64 Кб, но один массив данных не может превышать 64 Кб. И код и данные имеют дальний тип (см. уч. пос., ч.14).

Сверхбольшая (huge) – код и данные могут превышать по размеру 64 Кб. Массивы данных также могут превышать 64 Кб. Код и данные имеют дальний тип. Указатели на элементы массива также дальнего типа

(см.п.4.58; уч. пос., ч.14; 1, с. 112).

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

Приведем пример программы, использующей стандартные директивы определения сегментов segment, ends и assume.

stacksg

segment para stack 'stack'

db 200h dup (?)

stacksg

ends

datasg

segment para 'data'

HelloMessage db 'Привет!',13,10,'$'

datasg

ends

codesg

segment para 'code'

assume cs:codesg, ds:datasg, ss:stacksg ProgramStart:

mov ax,datasg

31

mov ds,ax

; установить ds в значение сегмента данных

mov dx,offset HelloMessage;ds:dx указывает на сообщение 'Привет!'

mov ah,9

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

int 21h

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

mov ah,4ch

; функция DOS завершения программы

int 21h

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

codesg ends

end ProgramStart

4.25. Директива segment

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

codesg segment

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

4.26. Директива ends

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

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

4.27. Директива assume

Директива assume указывает, в значение какого сегмента установлен данный сегментный регистр. Директиву assume cs: требуется указывать в каждой программе, в которой используются стандартные сегментные директивы, так как ассемблеру необходимо знать о сегменте кода для того, чтобы установить выполняемую программу. Кроме того, обычно используются директивы assume ds: и assume es:, благодаря которым ассемблер знает, к каким ячейкам памяти можно адресоваться в данный момент.

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

Data1 segment para 'Data' Var1 dw 0

32

Data1 ends

Data2 segment para 'Data' Var2 dw 0

Data2 ends

Codesg segment para 'Code' assume cs:Codesg

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

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

Codesg ends

end ProgramStart

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

Чтобы сообщить ассемблеру, что в данный момент сегментный регистр не указывает ни на какой именованный сегмент, в директиве assume используется ключевое слово nothing.

Например: mov ax,0b800h mov ds,ax

assume ds:nothing

Здесь регистр ds устанавливается таким образом, чтобы указывать на цветной графический экран, а затем ассемблеру сообщается, что регистр ds не указывает ни на какой именованный сегмент.

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

Data1 segment para 'Data' Var1 dw 0

Data1 ends

Data2 segment para 'Data' Var2 dw 0

Data2 ends

Codesg segment para 'Code'

33

assume cs:Codesg 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

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

Codesg

ends

 

end ProgramStart

В данном примере сообщение об ошибке не выводится. Но это не означает, что ассемблер позволяет вам сделать ошибку. Он модифицирует инструкцию

mov ax,[Var2]

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

Это происходит потому что регистр ds установлен в значение сегмента Data1, а es установлен в значение сегмента Data2. Ассемблер совершенно правильно заключает, что к Var2 нельзя получить доступ относительно регистра ds, однако Var2 доступно относительно сегментного регистра es. В итоге ассемблер включает перед инструкцией mov специальный код (префикс переопределения сегмента), чтобы указать процессору 8086, что вместо сегментного регистра ds нужно использовать регистр es.

Таким образом, если вы корректно используете директивы assume, позволяя ассемблеру узнать о текущих установленных для регистров ds и es значениях, то он в некоторых случаях даже может выполнить автоматическую корректировку сегмента.

4.28. Директива end

Директива end отмечает конец исходного кода программы. Все строки, которые следуют за нею, ассемблером игнорируются. Например: stacksg segment para ‘Stack’

db 200h ; стек объемом 512 байтов stacksg ends

datasg segment para ‘Data’ ; начало сегмента данных datasg ends

codesg segment para ‘Code’ ; начало сегмента кода

34

main proc far

assume cs:codesg, ds:datasg, ss:stacksg

mov ax,datasg

 

mov ds,ax

; ds указывает на сегмент данных datasg

mov

ah,4ch

 

int

21h

 

main endp

 

codesg ends

 

end

main

 

Это простейшая программа на ассемблере. Она ничего не делает, просто немедленно возвращает управление DOS.

Кроме завершения программы, директива end может указывать, где должно начинаться выполнение при запуске программы (с метки main). Иногда требуется начать выполнение программы в файле .exe не с первой инструкции. Директива end предусматривает такие случаи. Например:

stacksg segment para ‘Stack’

 

 

db

200h

 

; стек объемом 512 байтов

stacksg ends

 

 

 

datasg segment para ‘Data’

; начало сегмента данных

datasg ends

 

 

 

codesg segment para ‘Code’

; начало сегмента кода

Delay proc

 

 

 

mov

cx,60000

 

 

DelayLoop:

 

 

 

loop DelayLoop

 

 

ret

 

 

 

 

 

Delay endp

 

 

 

mainproc far

 

 

 

 

assume cs:codesg, ds:datasg, ss:stacksg

ProgramStart:

 

 

 

mov ax,datasg

 

 

mov ds,ax

; ds указывает на сегмент данных datasg

call Delay

; пауза на время, необходимое для выполнения 64

циклов

 

 

 

 

 

mov

ah,4ch

 

 

 

int

21h

 

 

 

main endp

 

 

 

codesg ends

 

 

 

end

ProgramStart

 

 

Выполнение здесь начинается не на первой инструкции исходного кода (mov cx,60000) по метке Delay. Вместо этого выполнение начинается

35

Источник: https://studfile.net/preview/16407174/