Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Методичні вказівки до лабораторних робіт.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
463.87 Кб
Скачать

Zzzzz - абсолютна адреса

Оскільки приписування праворуч нуля до шістнадцятирічного числа еквівалентно множенню цього числа на 16, то формулу обчислення абсолютної адреси по адресній парі CP:ofs можна виразити так:

Аабс = 16*[CP] + ofs

Наприклад, якщо ES=1234h, тоді адресна пара ES:53h задає абсолютну адресу 16*1234h+53h = 12340h+53h = 12387h.

Тепер уточнимо одну річ. Як ми знаємо, адреси, що вказують у командах, можна модифікувати по регістрах ВХ, ВР, SI і DI. Як сполучається ця модифікація із сегментуванням? Правила тут наступні. Спочатку виконується модифікація адреси по регістрах-модифікаторах, у результаті чого виходить адреса, яку ми називаємо виконавчою. При цьому, нагадаємо, обчислення ведеться по модулю 216, тобто виконавча адреса - це завжди 16-розрядна адреса. Потім ця адреса розглядається як зсув і саме він сегментується, тобто саме до нього додається вміст сегментного регістра, помножене на 16. Причому дане підсумовування ведеться по модулі 220, щоб не вийшла адреса, більше максимально припустимого. Таким чином, більш точна формула обчислення абсолютної адреси така:

Аабс = (Авик + 16*[СР]) mod 220

Відзначимо, що сегментування виконавчої адреси відбувається, тільки якщо команда здійснює доступ до пам'яті. Якщо ж у команді не передбачене звертання до пам'яті, то сегментний регістр не враховується. Скажемо, команда LEA r16,А не звертається до пам'яті, тому адреса А не буде сегментуватися, тобто по цій команді виконується операція r16:=Авик, а не операція r16:=Аабс.

І, нарешті, розглянемо ще одну, найцікавішу особливість сегментування адрес у ПК.

1.3. Сегментні регістри за замовчуванням

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

З урахуванням цієї особливості реальних програм у ПК прийнятий ряд угод, які дозволяють у багатьох командах не вказувати явно сегментні регістри, а мати на увазі їх за замовчуванням.

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

Що ж стосується регістра ES, то щодо нього немає ніяких домовленостей, він вільний і може вказувати на будь-який сегмент пам'яті.

По-друге, домовляються про наступне. Перед адресами переходу регістр CS явно не вказується, він мається на увазі по умовчанню; наприклад, у команді переходу досить указати тільки мітку (JMP L), префікс же CS: буде доданий автоматично (JMP CS:L). При посиланнях на сегмент даних можна явно не вказувати регістр DS, він мається на увазі за замовчуванням; наприклад, якщо X - ім'я змінної, то замість команди MOV DS:X,0 можна писати просто MOV Х,0. І, нарешті, домовляються, що при посиланнях на стек можна явно не вказувати регістр SS, він мається на увазі за замовчуванням.

Більш точно правила про вибір сегментних регістрів за замовчуванням формулюються в такий спосіб:

• Адреси переходу завжди сегментуються по регістрі CS.

• У так званих рядкових командах діють особливі угоди.

• У всіх інших командах.

Якщо адреса в команді не модифікується або якщо він модифікується, але серед модифікаторів немає регістра ВР, то ця адреса вважається посиланням у сегмент даних і тому за замовчуванням сегментуються по регістрі DS; якщо адреса модифікується по ВР, то він уважається посиланням у стек і тому за замовчуванням сегментується по регістру SS. (Тут слід уточнити одну річ, пов'язану з непрямими переходами: Розглянемо такий фрагмент:

X DW l

JMP X ; JMP DS:X = goto CS:L L: ...

У команді переходу X - це ще не адреса переходу, а адреса того осередку, де перебуває адреса переходу. Тому в даній команді мається на увазі, що X є адресою із сегмента даних і тому за замовчуванням сегментується по регістрі DS. Але от коли із цього осередку обрана адреса переходу (L), то вже він сегментується по регістру CS.)

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

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

Вигода від цих угод також і в тім, що вони дозволяють скоротити розміри машинних програм, оскільки перед переважною більшістю машинних команд можна не ставити команди-префікси, команди пророблять правильно й без них. Саме заради цього й пішли на "винос" префіксів за межі машинних команд: якби префікс вказувався в самій команді, то угоди нічого не дали б - місце для префікса однаково залишалося б у команді, і це місце однаково треба було б чимось заповнювати. Префікси ж як окремі команди можна опускати, не вказувати.

Отже, якщо дотримуватися угод про сегментні регістри, то текст програми на мові Асемблера буде коротше й розмір машинної програми буде менше.

А що буде, якщо цих угод не дотримуватися? Тоді потрібно буде в командах виписувати повні адресні пари. Наприклад, якщо ми встановили на початок області даних не регістр DS, а, скажемо, регістр SS, тоді для засилання 0 в осередок X із цієї області потрібно писати команду MOV SS:X,0; писати ж команду MOV Х,0 уже не можна, тому що вона сприйметься як MOV DS:X,0 і тому зашле 0 невідомо куди. Ясно, що краще дотримуватися зазначених угод, якщо ми не хочемо увесь час виписувати префікси.

Відзначимо, що одне із цих угод не можна порушувати в жодному разі: регістр CS завжди зобов'язаний указувати на початок сегмента команд. Це пояснюється тим, що в ПК адресу чергової команди, яку треба виконати, завжди вказується парою регістрів CS і IP, де покажчик команд IP містить зсув цієї команди, відлічене від початку сегмента команд. Тому, якщо регістр CS буде вказувати не на початок сегмента команд, то поводження машини буде непередбаченим. По цій же причині перед адресами переходу не можна вказувати префікс, відмінний від CS: (префікс же CS: можна не вказувати, оскільки він і так: мається на увазі за замовчуванням).

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

Перший - це коли ми в цілому дотримуємося даних угод, але в якімсь окремому випадку хочемо їх порушити. Нехай, приміром, ми хочемо записати в регістр АХ уміст осередку L, розташованої в сегменті команд. Використати тут команду MOV AX,L не можна, оскільки вона сприйметься як MOV AX,DS:L і тому запише в АХ уміст осередку, що має зсув L, але перебуває не в сегменті команд, а в сегменті даних. Як видно, нас тут не влаштовує угода про те, що в команді MOV за замовчуванням береться регістр DS, тому ми зобов'язані явно вказати той сегментний регістр, що нам потрібний, тобто ми зобов'язані записати команду MOV AX,CS:L.

Другий випадок - це коли нам треба працювати із сегментом пам'яті, відмінним від сегментів команд, даних і стека. У цьому випадку на початок цього сегмента встановлюють регістр ES і при посиланнях на осередки цього сегмента використають даний регістр, наприклад: INC ES:Y. Опускати тут префікс ES: не можна, тому що він не мається на увазі за замовчуванням. Відзначимо попутно, що регістр ES саме й призначений для роботи з додатковими сегментами пам'яті.

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