Введение
Реализация сегментации памяти на Intel x86
Сегментация памяти x86 относится к реализации сегментации памяти в архитектуре набора команд компьютера Intel x86. Сегментация была введена в процессоре Intel 8086 в 1978 году как способ позволить программам адресовать более 64 КБ (65 536 байт) памяти. В 1982 году Intel 80286 представила вторую версию сегментации, добавив поддержку виртуальной памяти и защиту памяти. Оригинальный режим был переименован в реальный режим, а новая версия получила название защищенный режим. Архитектура x86-64, представленная в 2003 году, в значительной степени отказалась от поддержки сегментации в 64-битном режиме. Как в реальном, так и в защищенном режимах система использует 16-битные сегментные регистры для вычисления фактического адреса памяти. В реальном режиме регистры CS, DS, SS и ES указывают на текущий сегмент программного кода (CS), текущий сегмент данных (DS), текущий сегмент стека (SS) и дополнительный сегмент, определяемый программистом (ES). Процессор Intel 80386, представленный в 1985 году, добавил два дополнительных сегментных регистра, FS и GS, без конкретных функций, определенных аппаратным обеспечением. Способ использования сегментных регистров различается в этих двух режимах.
80286 защищенный режим
Защищенный режим 80286 расширяет адресное пространство процессора до 2<sup>24</sup> байт (16 мегабайт), но не путем корректировки значения сдвига. Вместо этого 16-битовые сегментные регистры теперь содержат индекс в таблицу сегментных дескрипторов, содержащих 24-битовые базовые адреса, к которым добавляется смещение. Для поддержки старого программного обеспечения процессор запускается в "реальном режиме", в котором он использует сегментированную модель адресации 8086. Однако есть небольшое различие: полученный физический адрес больше не усекается до 20 бит, поэтому указатели реального режима (но не указатели 8086) теперь могут ссылаться на адреса между 100000<sub>16</sub> и 10FFEF<sub>16</sub>. Эта область памяти, составляющая примерно 64 килобайта, была известна как область высокой памяти (High Memory Area, HMA), и более поздние версии DOS могли использовать ее для увеличения доступной "обычной" памяти (то есть в пределах первого МБ). С добавлением HMA общее адресное пространство составляет приблизительно 1,06 МБ. Хотя 80286 не усекает адреса реального режима до 20 бит, система, содержащая 80286, может сделать это с помощью внешнего оборудования, отключая 21-ю адресную линию, линию A20. IBM PC AT предоставил аппаратное обеспечение для этого (для полной обратной совместимости с программным обеспечением для оригинальных моделей IBM PC и PC/XT), и так же все последующие клоны ПК "класса AT". Защищенный режим 286 использовался редко, поскольку он исключал бы большое количество пользователей с машинами 8086/88. Более того, все еще требовалось разделять память на 64-килобайтные сегменты, как это было сделано в реальном режиме. Это ограничение может быть преодолено на 32-битных процессорах, которые позволяют использовать указатели памяти размером более 64 КБ, однако, поскольку поле "Ограничение сегмента" имеет длину только 24 бита, максимальный размер сегмента, который может быть создан, составляет 16 МБ (хотя механизм страничной организации памяти можно использовать для выделения большего объема памяти, ни один отдельный сегмент не может превышать 16 МБ). Этот метод обычно использовался в приложениях Windows 3.x для создания плоского адресного пространства, хотя, поскольку сама ОС все еще была 16-битной, вызовы API не могли быть выполнены с помощью 32-битных инструкций. Таким образом, все еще необходимо было размещать весь код, выполняющий вызовы API, в 64-килобайтных сегментах. После того, как 286 защищенный режим был вызван, его нельзя было покинуть, кроме как выполняя аппаратный сброс. Машины, соответствующие стандарту IBM PC/AT, могли имитировать сброс процессора через стандартизированный контроллер клавиатуры, но это было значительно медленнее. Windows 3.x обошла обе эти проблемы, намеренно вызывая тройную ошибку в механизмах обработки прерываний процессора, что приводило к возврату процессора в реальный режим почти мгновенно.
80386 защищенный режим
В Intel 80386 и более поздних процессорах защищенный режим сохраняет механизм сегментации защищенного режима 80286, но в качестве второго уровня преобразования адресов между блоком сегментации и физической шиной добавлен блок страничной организации памяти (paging unit). Важно также, что смещения адресов теперь 32-битные (вместо 16-битных), а базовый адрес сегмента в каждом сегментном дескрипторе также 32-битный (вместо 24-битного). Общая работа блока сегментации в остальном не изменилась. Блок страничной организации памяти может быть включен или отключен; если он отключен, работа происходит так же, как на 80286. Если блок страничной организации памяти включен, адреса в сегменте становятся виртуальными адресами, а не физическими, как это было на 80286. То есть, начальный адрес сегмента, смещение и итоговый 32-битный адрес, вычисленный блоком сегментации путем их сложения, являются виртуальными (или логическими) адресами при включенном блоке страничной организации памяти. Когда блок сегментации генерирует и проверяет эти 32-битные виртуальные адреса, включенный блок страничной организации памяти, наконец, преобразует их в физические адреса. Физические адреса на 386 имеют размер 32 бита, но могут быть больше на более новых процессорах, поддерживающих расширение физических адресов. 80386 также представил два новых сегментных регистра данных общего назначения – FS и GS – к исходному набору из четырех сегментных регистров (CS, DS, ES и SS). Процессор 386 может быть возвращен в реальный режим путем сброса бита в регистре управления CR0, однако это привилегированная операция, необходимая для обеспечения безопасности и надежности. Для сравнения, 286 можно было вернуть в реальный режим только принудительным сбросом процессора, например, с помощью тройной ошибки или с использованием внешнего оборудования.
Позднее развитие
Архитектура x86 64 не использует сегментацию в длинном режиме (64-битном режиме). Четыре сегментных регистра – CS, SS, DS и ES – принудительно устанавливаются в базовый адрес 0, а предел – в 2<sup>64</sup>. Сегментные регистры FS и GS могут по-прежнему иметь ненулевой базовый адрес. Это позволяет операционным системам использовать эти сегменты для специальных целей. В отличие от механизма глобальной таблицы дескрипторов, используемого в устаревших режимах, базовый адрес этих сегментов хранится в регистре, специфичном для данной модели. Архитектура x86 64 также предоставляет специальную инструкцию SWAPGS, которая позволяет менять местами базовые адреса режимов ядра и пользователя. Например, Microsoft Windows в x86 64 использует сегмент GS для указания на блок окружения потока – небольшую структуру данных для каждого потока, содержащую информацию об обработке исключений, локальных переменных потока и других состояниях, специфичных для потока. Аналогично, ядро Linux использует сегмент GS для хранения данных, специфичных для каждого процессора. GS/FS также используются в механизме хранения локальных переменных потока в gcc и в защите стека на основе "канареек".