Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторна робота № 1 МЗКІТ (Звіт з 4-х частин).docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
47.93 Кб
Скачать

1.2.2 Директиви сегментації

У ході попереднього обговорення були з'ясовані всі основні правила запису команд і операндів у програмі на асемблері. Відкритим залишилося питання про те, як правильно

оформити послідовність команд, щоб транслятор міг їх обробити, а мікропроцесор - виконати.

При розгляді архітектури мікропроцесора нам відомо, що він має шість сегментних регістрів, за допомогою яких може одночасно працювати:

- з одним сегментом коду;

- з одним сегментом стека;

- з одним сегментом даних;

- із трьома додатковими сегментами даних.

Ще раз згадаємо, що фізично сегмент являє собою область пам'яті, зайняту командами й (або) даними, адреси яких обчислюються щодо значення у відповідному сегментному регістрі.

Синтаксичний опис сегмента на асемблері являє собою наступну конструкцію:

Ім'я сегмента SEGMENT [тип вирівнювання] [тип комбінування] [клас сегмента] [тип розміру сегмента]

уміст сегмента

Ім'я сегмента ENDS

Важливо відзначити, що функціональне призначення сегмента трохи ширше, чим проста розбивка програми на блоки коду, даних і стека. Сегментація є частиною загального механізму, пов'язаного з концепцією модульного програмування. Вона припускає уніфікацію оформлення об'єктних модулів, створюваних компілятором, у тому числі з різних мов програмування. Це дозволяє поєднувати програми, написані на різних мовах. Саме для реалізації різних варіантів такого об'єднання й призначені операнди в директиві SEGMENT.

Розглянемо їх докладніше:

- Атрибут вирівнювання сегмента (тип вирівнювання) повідомляє компонувальнику про те, що потрібно забезпечити розміщення початку сегмента на заданій границі. Це важливо, оскільки при правильному вирівнюванні доступ до даних у процесорах i80х86 виконується швидше. Припустимі значення цього атрибута наступні:

- BYTE - вирівнювання не виконується. Сегмент може починатися з будь-якої адреси пам'яті;

- WORD - сегмент починається за адресою, кратному двом, тобто останній (молодший) значущий біт фізичної адреси рівний 0 (вирівнювання на границю слова);

- DWORD - сегмент починається за адресою, кратному чотирьом, тобто два останні (молодших) значущих біта, рівні 0 (вирівнювання на границю подвійного слова);

- PARA - сегмент починається за адресою, кратному 16, тобто остання шістнадцяткова цифра адреси повинна бути 0h (вирівнювання на границю параграфа);

- PAGE - сегмент починається за адресою, кратному 256, тобто дві останні шістнадцяткові цифри повинні бути 00h (вирівнювання на границю 256-байтної сторінки);

- MEMPAGE - сегмент починається за адресою, кратному 4 Кбайт, тобто три останні шістнадцяткові цифри повинні бути 000h (адреса наступної 4-кбайтной сторінки пам'яті).

За замовчуванням тип вирівнювання має значення PARA.

- Атрибут комбінування сегментів (комбінаторний тип) повідомляє компонувальнику, як потрібно комбінувати сегменти різних модулів, що мають те саме ім'я. Значеннями атрибута комбінування сегмента можуть бути:

- PRIVATE - сегмент не буде поєднуватися з іншими сегментами з тим же іменем поза даним модулем;

- PUBLIC - змушує компонувальник з'єднати всі сегменти з однаковими іменами. Новий об'єднаний сегмент буде цілим і безперервним. Усі адреси (зсуву) об'єктів, а це можуть бути, залежно від типу сегмента, команди й дані, будуть

обчислюватися відносно початку цього нового сегмента;

- COMMON - розташовує всі сегменти із тим самим іменем по одній адресі. Усі сегменти з даним іменем будуть перекриватися й спільно використовувати пам'ять. Розмір отриманого в результаті сегмента буде дорівнює розміру найбільшого сегмента;

- AT xxxx - розташовує сегмент по абсолютній адресі параграфа (параграф - обсяг пам'яті, кратний 16, тому остання шістнадцяткова цифра адреси параграфа дорівнює 0);

- STACK - визначення сегмента стека. Змушує компонувальник з'єднати всі однойменні сегменти й обчислювати адреси в цих сегментах щодо регістру ss.

За замовчуванням атрибут комбінування приймає значення PRIVATE.

- Атрибут класу сегмента (тип класу) - це взятий в лапки рядок, що допомагає компонувальнику визначити відповідний порядок проходження сегментів при збиранні програми із сегментів декількох модулів. Компонувальник поєднує в пам'яті всі сегменти з тим самим іменем класу (ім'я класу, у загальному випадку, може бути будь-яким, але краще, якщо воно буде відображувати функціональне призначення сегмента);

- Атрибут розміру сегмента. Для процесорів i80386 і вище сегменти можуть бути 16 або 32-розрядними. Це впливає, насамперед, на розмір сегмента й порядок формування фізичної адреси всередині нього. Атрибут може приймати наступні значення:

- USE16 - це означає, що сегмент допускає 16-розрядну адресацію. При формуванні фізичної адреси може використовуватися тільки 16-розрядний зсув. Відповідно, такий сегмент може містити до 64 Кбайт коду або даних;

- USE32 - сегмент буде 32-розрядним. При формуванні фізичної адреси може

використовуватися 32-розрядний зсув. Тому такий сегмент може містити до 4 Гбайт коду або даних. Усі сегменти самі по собі рівноправні, тому що директиви SEGMENT і ENDS не містять інформації про функціональне призначення сегментів. Для того щоб використовувати їх як сегменти коду, даних або стека, необхідно попередньо повідомити транслятор про це, для чого використовують спеціальну директиву ASSUME. Ця директива повідомляє транслятор про те, який сегмент, до якого сегментного регістру прив'язаний. У свою чергу, це дозволить транслятору коректно зв'язувати символічні імена, визначені в сегментах.

Далі наведемо приклад програми з використанням стандартних директив сегментації:

data segment para public 'data' ;сегмент даних

message db 'Hello World,$' ; опис рядка

data ends

stk segment stack

db 256 dup ('?') ; розмір сегмента стека

stk ends

code segment para public 'code' ; початок сегмента

; коду

main proc ;початок процедури main

assume cs:code,ds:data,ss:stk

mov ax,data ; адреса сегмента даних

; у регістр ax

mov ds, ax ; ax в ds

mov ah,9

mov dx,offset message

int 21h ; ah=9 функція 21h переривання

; виводить рядок на екран, адресу

; якої зберігатися в регістрі dx,

; рядок повинен обов'язково

; закінчуватися символом $

mov ax,4c00h ; пересилання 4c00h у регістр ax

int 21h ; виклик переривання з номером 21h

main endp ; кінець процедури main

code ends ; кінець сегмента коду

end main ; кінець програми із крапкою входу

main

Для простих програм, що містять по одному сегменту для коду, даних і стека, хотілося б спростити її опис. Для цього в транслятори MASM і TASM увели можливість використання спрощених директив сегментації. Але тут виникла проблема, пов'язана з тим, що необхідно було якось компенсувати неможливість прямо управляти розміщенням і комбінуванням сегментів. Для цього, разом зі спрощеними директивами сегментації, сталі використовувати директиву вказівки моделі пам'яті MODEL, яка частково стала управляти розміщенням сегментів і виконувати функції директиви ASSUME (тому при використанні спрощених директив сегментації директиву ASSUME можна не використовувати). Ця директива зв'язує сегменти, які у випадку використання спрощених директив сегментації мають визначені імена із сегментними регістрами (хоча явно ініціалізувати ds однаково прийдеться).

Тепер, перепишемо вищенаведену програму з використанням спрощених директив сегментації.

masm ; режим роботи TASM: ideal або masm

model small ; модель пам'яті

.data ; сегмент даних

message db 'Hello World,$' ; опис рядка

.stack ;сегмент стека

db 256 dup ('?') ; сегмент стека

.code ;сегмент коду

main proc ; початок процедури main

mov ax,@data ; затягаємо адресу сегмента даних в

; регістр ax

mov ds, ax ; ax в ds

mov ah,9

mov dx,offset message

int 21h ; ah=9 функція 21h переривання

; виводить рядок на екран, адресу

; якої зберігатися в регістрі dx

mov ax,4c00h ; пересилання 4c00h у регістр ax

int 21h ; виклик переривання з номером 21h

main endp ; кінець процедури main

end main ; кінець програми із крапкою входу main

Обов'язковим параметром директиви MODEL є модель пам'яті. Цей параметр визначає модель сегментації пам'яті для програмного модуля. Передбачається, що програмний модуль може мати тільки певні типи сегментів, які визначаються згаданими нами раніше спрощеними директивами опису сегментів. Ці директиви наведено в таблиці 1.

Таблица 1. Спрощені директиви визначення сегмента

Формат директиви (режим MASM)

Формат директиви (режим IDEAL)

Призначення

.CODE

[имя]

CODESEG[имя]

Початок або продовження сегмента коду

.DATA

DATASEG

Початок або продовження сегмента ініціалізованих даних. Також використовується для визначення даних типу near

.CONST

CONST

Початок або продовження сегмента постійних даних (констант) модуля

.FARDATA

[имя]

FARDATA

[имя]

Початок або продовження ініціалізованих даних типу far

Наявність у деяких директивах параметра [ім'я] говорить про те, що можливе визначення декількох сегментів цього типу. З іншого боку, наявність декількох видів сегментів даних обумовлене вимогою забезпечення сумісності з деякими компіляторами мов високого рівня, які створюють різні сегменти даних для ініціалізованих і неініціалізованих даних, а також констант.

При використанні директиви MODEL транслятор робить доступними кілька ідентифікаторів, до яких можна звертатися під час роботи програми, для того, щоб одержати інформацію про ті або інших характеристиках даної моделі пам'яті (таблиця 3). Перелічимо ці ідентифікатори й їхні значення (табл. 2).

Таблиця 2. Моделі пам’яті

Модель

Тип

Тип

Призначення моделі

кода

данных

TINY

near

near

Код и дані об’єднані в одну групу с іменем DGROUP.

Використовується для створення програм формату .com.

SMALL

near

near

Код займає один сегмент, дані об’єднані в одну групу з іменем DGROUP. Цю модель зазвичай використовують для більшості програм на асемблері

MEDIUM

far

near

Код займає декілька сегментів, по одному на кожний об’єднуючий програмний модуль. Всі посилання на передачу управління – типу far. Дані об’єднані в одній групі; всі посилання на них – типу near

COMPACT

near

far

Код в одному сегменті; посилання на дані – типу far

LARGE

far

far

Код в декількох сегментах, по одному на кожний об’єднуючий програмний модуль

Параметр модифікатор директиви MODEL дозволяє уточнити деякі особливості використання обраної моделі пам'яті (табл. 3).

Таблиця 3. Модифікатори моделі пам’яті

Значення модифікатора

Призначення

use16

Сегменти вибраної моделі використовуються як 16-битні

(якщо відповідної

директивою вказаний процесор i80386 або i80486)

use32

Сегменти вибраної моделі використовуються як 32-бітні (якщо відповідною директивою вказаний процесор i80386 або i80486)

dos

Програма буде працювати в MS-DOS

Необов'язкові параметри - мова й модифікатор мови, визначають деякі особливості виклику процедур. Необхідність у використанні цих параметрів з'являється при написанні й зв'язуванні програм на різних мовах програмування.

Описані нами стандартні й спрощені директиви сегментації не виключають один одного. Стандартні директиви використовуються, коли програміст бажає одержати повний контроль над розміщенням сегментів у пам'яті і їх комбінуванням із сегментами інших модулів.

Спрощені директиви доцільно використовувати для простих програм і програм, призначених для зв'язування із програмними модулями, написаними на мовах високого рівня. Це дозволяє компонувальнику ефективно зв'язувати модулі різних мов за рахунок стандартизації зв'язків і керування.