Дескриптор сегмента¶
Дескриптор сегмента — это структура данных, используемая в архитектурах x86 (начиная с Intel 80286) и x86-64 для описания сегмента памяти. Дескриптор определяет базовый адрес, размер, тип доступа и права на сегмент, обеспечивая механизм сегментации памяти. В отличие от простого сегментирования, где адрес вычисляется из сегментного регистра и смещения, дескрипторная модель позволяет операционной системе контролировать доступ к памяти на уровне отдельных сегментов, поддерживая многозадачность и защиту.
¶История
Концепция дескрипторов сегментов возникла в рамках развития архитектуры x86, когда процессоры Intel перешли от 16-битного режима реального адреса (Real Mode) к 32-битному защищённому режиму (Protected Mode). В реальном режиме сегментный регистр хранил 16-битный адрес, который сдвигался на 4 бита влево и складывался с 16-битным смещением, давая 20-битный физический адрес. Это не обеспечивало никакой защиты памяти.
В 1982 году процессор Intel 80286 ввёл защищённый режим, где сегментные регистры стали указывать на дескрипторы, хранящиеся в таблицах дескрипторов. Это позволило задавать 24-битные базовые адреса и 16-битные лимиты, а также уровни привилегий. С появлением 32-битных процессоров (Intel 80386) дескрипторы были расширены до 32-битных базовых адресов и 20-битных лимитов, а также добавлены биты гранулярности (4 КБ или 1 байт).
В архитектуре x86-64 (AMD64, Intel 64) сегментация в длинном режиме (Long Mode) практически не используется для адресации памяти, но дескрипторы сегментов остаются необходимыми для управления сегментными регистрами (CS, SS, DS, ES, FS, GS) и определения их атрибутов (например, кольца привилегий).
¶Структура дескриптора сегмента
В архитектуре x86 дескриптор сегмента занимает 8 байт (64 бита) и имеет следующую структуру:
| Поле | Размер (бит) | Описание |
|---|---|---|
| Base (15:0) | 16 | Младшие 16 бит базового адреса |
| Base (23:16) | 8 | Следующие 8 бит базового адреса |
| Base (31:24) | 8 | Старшие 8 бит базового адреса |
| Limit (15:0) | 16 | Младшие 16 бит лимита |
| Limit (19:16) | 4 | Старшие 4 бита лимита |
| Type | 4 | Тип сегмента (код, данные, системный) |
| S | 1 | Дескриптор системы (0 — системный, 1 — код/данные) |
| DPL | 2 | Уровень привилегий (0 — наивысший, 3 — наименьший) |
| P | 1 | Присутствие сегмента (Present) |
| G | 1 | Гранулярность (0 — 1 байт, 1 — 4 КБ) |
| D/B | 1 | Размер операнда (0 — 16 бит, 1 — 32 бита) |
| L | 1 | Длинный режим (только для x86-64) |
| AVL | 1 | Доступно для системы |
Пояснения:
- Base — 32-битный физический адрес начала сегмента.
- Limit — 20-битный размер сегмента. При G=0 лимит задаётся в байтах (до 1 МБ), при G=1 — в блоках по 4 КБ (до 4 ГБ).
- Type — определяет тип сегмента: для кода (чтение/выполнение), для данных (чтение/запись), для системных объектов (TSS, LDT, шлюзы).
- S — отличает дескрипторы сегментов кода/данных (S=1) от системных дескрипторов (S=0).
- DPL — уровень привилегий, определяющий, с какого кольца защиты можно обращаться к сегменту.
- P — если P=0, сегмент отсутствует в памяти (вызовет исключение при попытке доступа).
- G — гранулярность: при G=1 лимит умножается на 4096.
- D/B — для сегментов кода задаёт размер операнда по умолчанию (16 или 32 бита), для сегментов данных — размер стека (SS).
- L — устанавливается в 1 для 64-битных сегментов в длинном режиме.
- AVL — зарезервировано для использования операционной системой.
¶Типы дескрипторов
¶Дескрипторы сегментов кода и данных (S=1)
- Сегмент данных (Data Segment): поддерживает чтение и/или запись. Тип может быть «только чтение», «чтение/запись», «расширяющийся вниз» (для стеков).
- Сегмент кода (Code Segment): поддерживает выполнение и/или чтение. Тип может быть «только выполнение», «выполнение/чтение», «подчинённый» (conforming) — разрешает выполнение с меньшим уровнем привилегий.
¶Системные дескрипторы (S=0)
- TSS (Task State Segment): описывает состояние задачи (регистры, стек, ссылки на другие сегменты).
- LDT (Local Descriptor Table): содержит локальные дескрипторы для конкретной задачи.
- Call Gate (Шлюз вызова): позволяет переключать уровень привилегий при вызове процедуры.
- Interrupt Gate (Шлюз прерывания): используется для обработки аппаратных прерываний.
- Trap Gate (Шлюз ловушки): аналогичен шлюзу прерывания, но не сбрасывает флаг IF.
¶Таблицы дескрипторов
Дескрипторы хранятся в двух типах таблиц:
- GDT (Global Descriptor Table): глобальная таблица дескрипторов, доступная всем задачам. Обычно содержит дескрипторы ядра ОС, TSS, LDT и шлюзы.
- LDT (Local Descriptor Table): локальная таблица, создаваемая для каждой задачи (процесса). Позволяет изолировать сегменты разных процессов.
Адрес и размер GDT хранятся в регистре GDTR, а LDT — в регистре LDTR. Для доступа к сегменту процессор загружает селектор (16-битное значение) в сегментный регистр (CS, SS, DS и т.д.). Селектор содержит индекс в таблице дескрипторов, номер таблицы (GDT или LDT) и уровень привилегий (RPL).
¶Использование в защищённом режиме
В защищённом режиме (32-битном) каждый сегментный регистр (CS, SS, DS, ES, FS, GS) содержит селектор, который ссылается на дескриптор. При загрузке селектора процессор извлекает дескриптор из GDT или LDT и кэширует его в теневом регистре (shadow register). Последующие обращения к памяти проверяются по закэшированным атрибутам: базовый адрес, лимит, права доступа и уровень привилегий.
Например, при попытке записи в сегмент данных с типом «только чтение» процессор генерирует исключение (General Protection Fault). Это обеспечивает защиту памяти между задачами и ядром ОС.
¶Использование в длинном режиме (x86-64)
В 64-битном длинном режиме сегментация для адресации памяти отключена: все сегментные регистры, кроме FS и GS, имеют фиксированный базовый адрес 0. Однако дескрипторы сегментов всё ещё используются для:
- Определения уровня привилегий (кольца защиты) через сегмент кода (CS).
- Настройки сегментов данных (DS, ES, SS) — их атрибуты (DPL, тип) влияют на проверки доступа.
- Регистров FS и GS: их базовые адреса могут быть заданы через Model-Specific Registers (MSR) для поддержки локальной памяти потоков (Thread-Local Storage, TLS).
В длинном режиме дескрипторы сегментов кода и данных имеют 64-битную структуру, но лимит игнорируется (считается равным 2^64 - 1). Бит L (Long mode) в дескрипторе кода указывает, что сегмент работает в 64-битном режиме.
¶Примеры дескрипторов
¶Дескриптор сегмента кода для 32-битного защищённого режима
- Base: 0x00000000
- Limit: 0xFFFFF (при G=1 даёт 4 ГБ)
- Type: 0xA (выполнение/чтение, не подчинённый)
- S: 1
- DPL: 0 (кольцо 0)
- P: 1
- G: 1
- D/B: 1 (32-битный)
¶Дескриптор сегмента данных для 64-битного длинного режима
- Base: 0x00000000
- Limit: 0x00000 (игнорируется)
- Type: 0x2 (чтение/запись)
- S: 1
- DPL: 3 (кольцо 3)
- P: 1
- G: 0
- D/B: 0 (16-битный, но не используется)
- L: 0 (не длинный режим для данных)
¶Критика и ограничения
Сегментация с дескрипторами была разработана для обеспечения защиты и изоляции в многозадачных системах, но на практике оказалась сложной и негибкой. Основные недостатки:
- Сложность управления: операционная система должна поддерживать GDT и LDT, что увеличивает накладные расходы.
- Ограниченная адресация: в 32-битном режиме база и лимит ограничены 4 ГБ, что недостаточно для современных систем.
- Несовместимость с плоской моделью памяти: большинство современных ОС (Linux, Windows) используют плоскую модель памяти, где все сегменты имеют одинаковый базовый адрес (0) и лимит (4 ГБ), а сегментация фактически игнорируется.
- Устаревание в x86-64: в длинном режиме сегментация отключена, и дескрипторы используются только для управления привилегиями и TLS.
Тем не менее, дескрипторы сегментов остаются обязательным элементом архитектуры x86 для обратной совместимости с 16-битным и 32-битным кодом.
¶Источники
- Intel Corporation. Intel 64 and IA-32 Architectures Software Developer’s Manual, Volume 3A: System Programming Guide. 2023. Chapter 3.2: "Protected-Mode Memory Management".
- AMD Corporation. AMD64 Architecture Programmer’s Manual, Volume 2: System Programming. 2022. Chapter 4: "Segmentation".
- Crawford, J., & Gelsinger, P. Programming the 80386. Sybex, 1987.
- Love, R. Linux Kernel Development. 3rd ed. Addison-Wesley, 2010. Chapter 4: "Memory Management".
- Таненбаум, Э., Бос, Х. Современные операционные системы. 4-е изд. Питер, 2015. Глава 3: "Управление памятью".