Глобальна таблиця дескрипторів

Глобальна таблиця дескрипторів або GDT (англ. Global Descriptor Table) — одна з найважливіших структур даних в комп'ютерній архітектурі x86. Ця структура допомагає керувати доступом до пам'яті та її захистом. Введена разом із процесором Intel 80286, вона відіграє ключову роль у визначенні сегментів пам'яті та їхніх атрибутів: базової адреси, розміру та різних допоміжних атрибутів, таких як права доступу, права на виконання чи на запис та ін.[1]

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

Опис

Кожен доступ до пам'яті, що виконується x86 процесором, завжди проходить через сегмент. На процесорі 80386 і пізніших моделях, завдяки 32-бітним зміщенням та обмеженням сегментів, можливо зробити так, щоб сегменти охоплювали всю адресовану пам'ять, що робить сегментно-відносну адресацію прозорою для користувача. Щоб посилатися на сегмент, програма повинна використовувати його індекс всередині GDT або LDT. Такий індекс називається селектором сегментів (або селектором). Для використання селектор необхідно завантажити в сегментний регістр. Окрім машинних інструкцій, які дозволяють встановлювати/отримувати позицію GDT та таблиці дескрипторів переривань (IDT) у пам'яті, кожна машинна інструкція, що звертається до пам'яті, має неявний сегментний регістр, іноді два. У більшості випадків цей сегментний регістр можна перезаписати, додавши префікс сегмента перед інструкцією.

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

Структура GDT використовується в основному у захищеному режимі (більш просунутий режим процесора, який дозволяє захист пам'яті та контроль доступу), в цьому режимі вона визначає:

  • Сегменти коду: області пам'яті, що містять виконувані інструкції.
  • Сегменти даних: області, що використовуються для зберігання даних програми.
  • Системні сегменти, такі як сегмент стану завдання (TSS), який використовується для підтримки багатозадачності.[1][2]

Кожен запис у GDT має довжину 8 (у 32-бітних системах) або 16 байт (у 64-бітних) і містить дескриптор сегмента, тобто запис, котрий визначає властивості одного сегмента пам'яті. Кожен дескриптор містить атрибути бази, розміру, та прав доступу, чим забезпечується коректна робота з пам'яттю. Таблиця GDT може містити від 1 до 8192 дескрипторів і обов'язково починається з нульового дескриптора, звернення до якого викликає виняток «Загальна помилка захисту» (англ. General protection fault), чим забезпечується захист від звернення до пам'яті з використанням неініціалізованого сегментного регістру, тобто такого, в який не було завантажено селектор.

Формат кожного дескриптора склався історично і має наступну структуру[1]:

Байт Біти Назва поля Опис
0–1 0–15 Segment Limit 0:15 Молодші 16 біт ліміту (розміру) сегмента
2–3 16–31 Base address 0:15 Молодші 16 біт базової (початкової) адреси
4 32–39 Base address 16:23 Середні 8 біт базової адреси
5 40–47 Access Byte Опис прав доступу до сегмента
40 A (Accessed) Маркер, що до коду відбувався доступ (автоматично встановлюється CPU при доступі до сегмента)
41 RW (Read/Write) Права на читання/запис
42 ED (Expand-down/Conforming) визначає дозвіл на доступ з нижчого рівня привілеїв
43 Executable Права на виконання
44 S Тип дескриптора; 1 – код чи дані, 0 – Системний сегмент
45-46 DPL Рівень привілеїв, потрібних, щоб отримати доступ до сегмента (ring0-ring3)
47 Present Присутність сегмента у пам'яті
6 48–51 Limit 16:19 Старші 4 біти ліміту сегмента
52 AVL Резервний біт, не використовується процесором, доступний для власного використання
53 L (Long mode) Визначає підтримку 64-бітного режиму коду в даному сегменті; 0 для 32-бітного; 1 для 64-бітного
54 D/B (Default/Big operand size) Розмір пам'яті, якою оперують інструкції: 0 – інструкції та зміщення за замовчуванням 16-бітні; 1 – 32-бітні.
55 G Гранулярність, тобто визначення одиниць, у яких вказано ліміт сегмента: 0 – байти, 1 – 4 КБ сторінки
7 56–63 Base address 24:31 Старші 8 біт базової адреси
Формат дескриптора сегмента для 32-бітних систем

Завантаження селектора у сегментний регістр зчитує запис GDT або LDT під час його завантаження та кешує властивості сегмента в прихованому регістрі. Таке завантаження селектора сегмента семантично схоже з присвоєнням значення адреси цьому регістру, як це часто робиться у реальному режимі процесора. Однак у захищеному режимі роботи процесора таке присвоєння насправді використовує селектор сегмента — спеціальне значення, по суті індекс у таблиці GDT[a], що вказує процесору, який запис GDT використовувати. Потім процесор завантажує цей дескриптор у регістр сегмента, який містить як видимі, так і приховані метадані про сегмент.

    ; завантаження GDT, котра розміщена за адресою gdt_desc
    lgdt fword ptr [gdt_desc]

    ; завантаження у сегментний регістр DS посилання на 1-й елемент в GDT
    mov ax, 8   
    mov ds, ax

[1]

GDT у 64-бітній версії

У 64-бітному режимі сегментація здебільшого вимкнена: усі бази сегментів розглядаються як нульові, а обмеження ігноруються, створюючи «плоский» (англ. flat) адресний простір. Однак, GDT все ще повинен визначати системні дескриптори, такі як сегмент стану завдання (TSS). Два сегментні регістри, FS та GS, залишаються активними та часто використовуються операційними системами для зберігання локальних потоків або даних, специфічних для процесу (наприклад, локальний TLS-блок потоку виконання у Windows або gs_base у Linux).[1]

Примітно, що Windows застосовує суворі заходи захисту GDT: спроби підмінити або змінити GDT у 64-розрядних версіях призведуть до збою системи.[3]

Таблиця локальних дескрипторів

Таблиця GDT визначає загальносистемні сегменти; водночас в системі може існувати таблиця локальних дескрипторів (англ. LDT), котра визначатиме сегменти, які є приватними для одного процесу. Історично операційні системи використовували LDT для розділення пам'яті кожної програми на приватні області, особливо до введення механізму підкачування сторінок в процесорі Intel 80386.

Після поширення ОС захищеного режиму, таблиці LDT застаріли, але все ще можуть з'являтися для сумісності з 16-розрядними або старішими 32-розрядними програмами (наприклад, програмами DOS або OS/2). LDT визначається окремим записом у GDT та може містити до 8192 дескрипторів сегментів.[2]

Історія та сучасне використання

У ранніх системах x86 (таких як 80286) сегментація за допомогою GDT та LDT була критично важливою для реалізації багатозадачності та ізоляції пам'яті. Кожен процес мав власну LDT, тоді як GDT містив глобальні визначення. Система могла автоматично перемикати поточний LDT під час зміни завдань, що робило ізоляцію на основі сегментів ефективною.[b].

З появою системи віртуальної пам'яті Підкачування сторінок на процесорі 80386, операційні системи почали використовувати сторінкову віртуальну пам'ять замість сегментної. Підкачування дозволяє детальне управління пам'яттю фрагментами по 4 КБ та спрощує спільний доступ до пам'яті або її захист. В результаті, сучасні операційні системи, такі як Windows, Linux та macOS, використовують модель «плоскої пам'яті», де всі сегменти коду та даних охоплюють весь адресний простір. Однак, GDT все ще бере участь в ініціалізації системи, обробці переривань та визначенні спеціальних структур, таких як покажчик TSS та LDT.[1]

Застарілі режими або режими сумісності (наприклад, виконання 16-бітного коду DOS або OS/2) можуть все ще активно використовувати сегментацію. У таких випадках можна використовувати техніку, відому як мозаїчне розбиття LDT, де LDT заповнюється дескрипторами, які відображають блоки пам'яті фіксованого розміру (наприклад, по 64 КБ кожен), щоб забезпечити покриття для застарілих програм. Ще одним прикладом специфічного використання GDT є Unreal mode — незвичний режим роботи процесора, де через використання недокументованої можливості процесора у 16-бітному реальному режимі програмам стає доступна пам'ять поза стандартним лімітом в 1 МБ (аж до 4 ГБ).

Посилання

Виноски
  1. історично склалось так, що цей індекс задається не номером, а вирівняним байтовим зміщенням, з деякими службовими бітами
  2. Саме сумісністю з древніми ОС та процесорами продиктована нелогічно подрібнена структура дескриптора в таблиці GDT
Посилання
  1. а б в г д Intel 64 and IA-32 Architectures Software Developer’s Manual, Chapter 5: “Memory Management”. Intel. Процитовано 19 травня 2025.
  2. а б Tanenbaum, Andrew S.; Bos, Herbert (2014). Modern Operating Systems (4th ed.) (PDF). Pearson. с. 249. ISBN 978-0133591620. Процитовано 19 травня 2025.
  3. Patching Policy for x64-Based Systems. 8 жовтня 2009. Архів оригіналу за 19 січня 2022. Процитовано 11 грудня 2020. If the operating system detects one of these modifications or any other unauthorized patch, it will generate a bug check and shut down the system.

Джерела

Prefix: a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9

Portal di Ensiklopedia Dunia

Kembali kehalaman sebelumnya