Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторна робота4.doc
Скачиваний:
1
Добавлен:
15.11.2019
Размер:
151.04 Кб
Скачать

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

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

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

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

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

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

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

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

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

Рис. 4. Синтаксис опису сегмента

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

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

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

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

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

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

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

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

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

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

    • PUBLIC — змушує компоновщик з'єднати всі сегменти з однаковими іменами. Новий об'єднаний сегмент буде цілим і безперервним. Всі адреси (зсуву) об'єктів, а це можуть бути, залежно від типу сегмента, команди й дані, будуть обчислюватися відносно початку цього нового сегмента;

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

    • STACK — визначення сегмента стека. Змушує компоновщик з'єднати всі однойменні сегменти й обчислювати адреси в цих сегментах щодо регістра ss. Комбінований тип STACK (стек) аналогічний комбінованому типу PUBLIC, за винятком того, що регістр ss є стандартним сегментним регістром для сегментів стека. Регістр sp установлюється на кінець об'єднаного сегмента стека. Якщо не зазначено жодного сегмента стека, компоновщик видасть попередження, що стековий сегмент не знайдений. Якщо сегмент стека створена, а комбінований тип STACK не використовується, програміст повинен явно завантажити в регістр ss адреса сегмента (подібно тому, як це робиться для регістра ds ).

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

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

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

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

    • USE32 — сегмент буде 32-розрядним. При формування фізичної адреси може використовуватися 32-розрядний зсув. Тому такий сегмент може містити до 4 Гбайт коду або даних.

Всі сегменти самі по собі рівноправні, тому що директиви SEGMENT і ENDS не містять інформації про функціональне призначення сегментів. Для того щоб використовувати їх як сегменти коду, даних або стека, необхідно попередньо повідомити транслятор про це, для чого використовують спеціальну директиву ASSUME , що має формат, показаний на рис. 15. Ця директива повідомляє транслятор про те, який сегмент до якого сегментного регістра прив'язаний. У свою чергу, це дозволить транслятору коректно зв'язувати символічні імена, певні в сегментах. Прив'язка сегментів до сегментних регістрів здійснюється за допомогою операндов цієї директиви, у яких ім'я_сегмента повинне бути ім'ям сегмента, певним у вихідному тексті програми директивою SEGMENT або ключовим словом nothing . Якщо в якості операнда використовується тільки ключове слово nothing , то попередні призначення сегментних регістрів анулюються, причому відразу для всіх шести сегментних регістрів. Але ключове слово nothing можна використовувати замість аргументу ім'я сегмента; у цьому випадку буде вибірково розриватися зв'язок між сегментом з ім'ям ім'я сегмента й відповідним сегментним регістром (див. рис. 5).

Рис. 5. Директива ASSUME

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

У лістингу 1 наведений приклад програми з використанням спрощених директив сегментації:

 

        Лістинг 1. Використання спрощених директив сегментації

;============Prg_3_1.asm==================

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 показаний на рис. 6.

Рис. 6. Синтаксис директиви MODEL

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

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

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

Призначення

.CODE [ім'я]

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

.DATA

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

.CONST

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

.DATA?

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

.STACK [розмір]

Початок або продовження сегмента стека модуля. Параметр [розмір] задає розмір стека

.FARDATA [ім'я]

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

.FARDATA? [ім'я]

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

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

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

Таблиця 2. Ідентифікатори, створювані директивою MODEL

Ім'я ідентифікатора

Значення змінної

@code

Фізична адреса сегмента коду

@data

Фізична адреса сегмента даних типу near

@fardata

Фізична адреса сегмента даних типу far

@fardata?

Фізична адреса сегмента ініціалізованих даних типу far

@curseg

Фізична адреса сегмента неініціалізованих даних типу far

@stack

Фізична адреса сегмента стека

Якщо ви подивитеся на текст лістингу 1 , то побачите приклад використання одного із цих ідентифікаторів. Це @data ; з його допомогою ми одержали значення фізичної адреси сегмента даних нашої програми.

Операнды директиви MODEL використовують для задання моделі пам'яті, що визначає набір сегментів програми, розміри сегментів даних і коду, спосіб зв'язування сегментів і сегментних регістрів. У табл. 3 наведені деякі значення параметра модель пам'яті директиви MODEL

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

Модель

Тип коду

Тип даних

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

TINY

near

near

Код і дані об'єднані в одну групу з ім'ям DGROUP.  Використовується для створення програм формату .com.

SMALL

near

near

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

MEDIUM

far

near

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

COMPACT

near

far

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

LARGE

far

far

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

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

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

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

Призначення

use16

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

use32

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

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

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

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

   

  1. Завдання для виконання лабораторної роботи.

  1. Представити формат речення асемблера.

  2. Представити формат директив асемблера.

  3. Представити формат команд та макрокоманд асемблера.

  4. Описати моделі пам’яті, які використовуються директивою MODEL.

  1. Виконання лабораторної роботи.

  1. Опрацювати теоретичні відомості.

  2. Виконати поставлене завдання (п.4), записати результат.

  3. Дати відповіді на контрольні питання(п.6).

  4. Зробити висновки.

  1. Контрольні питання.

  1. Які ви знаєте спрощені директиви визначення сегмента?

  2. Для чого використовується директива ASSUME?

  3. Які ви знаєте атрибути вирівнювання сегмента?

  1. Зміст звіту.