Вступление
В 64-битном режиме всякий раз, когда ненулевой селектор сегмента загружается в любой из сегментных регистров, процессор автоматически загружает соответствующий дескриптор сегмента в скрытую часть сегментного регистра, как и в защищенном режиме/режиме совместимости. Однако дескрипторы сегментов, выбранные селекторами DS, ES или SS, полностью игнорируются. Также игнорируются поля ограничений и атрибутов дескрипторов сегментов, выбранных селекторами FS и GS.
Руководство Intel V3 3.4.4:
Поскольку регистры сегментов ES, DS и SS не используются в 64-битном режиме, их поля (база, лимит и атрибут) в регистрах дескриптора сегмента игнорируются. Некоторые формы инструкций по загрузке сегмента также недействительны (например, LDS, POP ES). Вычисления адресов, которые ссылаются на сегменты ES, DS или SS, обрабатываются так, как если бы основание сегмента было равно нулю.
...
В 64-битном режиме доступ к памяти с использованием переопределений FS-сегментов и GS-сегментов не проверяется на ограничение времени выполнения и не подвергается проверке атрибутов.
Помимо этого, предполагается, что базовый адрес каждого из этих сегментов равен 0, а длина равна 264. Однако некоторые части дескрипторов сегментов, выбранные с помощью селекторов CS, FS или GS, по-прежнему действуют. В частности, используются базовые адреса FS и GS, указанные в их соответствующих дескрипторах.
Руководство Intel V3 3.4.4:
Когда переопределения сегментов FS и GS используются в 64-битном режиме, их соответствующие базовые адреса используются при расчете линейного адреса.
Кроме того, используются следующие поля дескриптора CS: D (бит по умолчанию), L (64-битный бит подрежима), AVL (биты ОС), P (текущий бит), DPL (биты уровня привилегий), S (системный бит), D/C (бит данных/кода) и C (бит соответствия). Обратите внимание, что базовый адрес CS зафиксирован на 0, а длины CS, FS и GS зафиксированы на 264. Как указал Питер в своем комментарии, биты L и D дескриптора CS необходимы для возможности переключения между различными подрежимами длинного режима. Другие активные поля CS также полезны. Поддержка разных базовых адресов для FS и GS полезна для таких вещей, как локальное хранилище потока.
Руководство Intel V3 5.2.1:
Сегменты кода продолжают существовать в 64-битном режиме, даже несмотря на то, что для вычислений адресов основание сегмента считается нулевым. Некоторое содержимое дескриптора сегмента кода (CS) (поля базового адреса и лимита) игнорируется; остальные поля функционируют нормально (кроме читаемого бита в поле типа).
Дескрипторы и селекторы сегментов кода необходимы в режиме IA-32e для установки режима работы процессора и уровня привилегий выполнения.
Я думаю, что и читаемый бит, и доступный бит игнорируются в 64-битном режиме. Эти атрибуты заменяются соответствующими атрибутами в структурах страниц. Хотя я не мог найти нигде в руководстве Intel, где говорится, что доступный бит игнорируется. Но в руководстве AMD это четко указано.
Проверки пределов таблицы дескрипторов по-прежнему выполняются.
Руководство Intel V3 5.3.1:
В 64-битном режиме процессор не выполняет проверку ограничений времени выполнения для кода или сегментов данных. Однако процессор проверяет пределы таблицы дескрипторов.
Таким образом, можно сказать, что сегментация полностью отключена для сегментов DS, ES и SS. Но не совсем для остальных трех сегментов. Вот что означает segmentation cannot be completely disabled
.
Руководство Intel V2 говорит об обратном
Цитирую описание инструкции POP.
Исключения 64-битного режима
#GP(0) Если адрес памяти имеет неканоническую форму.
#SS(0) Если адрес стека имеет неканоническую форму.
#GP(селектор) Если дескриптор находится вне ограничение таблицы дескрипторов.
Если загружается регистр FS или GS, а сегмент, на который он указывает, не является сегментом данных или читаемого кода.
Если регистр FS или GS загружается, и указанный сегмент является сегментом данных или несоответствующим кодом, но и RPL, и CPL больше, чем DPL.
#AC(0) Если во время выравнивания делается невыровненная ссылка на память проверка включена.
#PF(fault-code) Если происходит ошибка страницы.
#NP Если загружается регистр FS или GS, а сегмент, на который он указывает, помечен как отсутствующий.
#UD Если используется префикс LOCK.
Обратите внимание, что POP для DS, ES, SS недействительны в 64-битном режиме и нет POP CS
. Вот почему он говорит только о FS и GS. Хотя это подразумевает, что атрибуты дескрипторов, выбранных FS и GS, не игнорируются полностью.
Точно так же в описании инструкции MOV говорится:
Исключения 64-битного режима
#GP(0)
Если адрес памяти имеет неканоническую форму.
Если сделана попытка загрузить регистр SS с селектором сегмента NULL, когда CPL = 3.
Если сделана попытка загрузить регистр SS с селектором сегмента NULL, когда CPL ‹ 3 и CPL ≠ RPL.
#GP(селектор)
Если индекс селектора сегмента выходит за пределы таблицы дескрипторов. Если доступ к памяти для таблицы дескрипторов неканонический.
Если загружается регистр SS, а RPL селектора сегмента и DPL дескриптора сегмента не равны CPL.
Если загружается регистр SS а сегмент, на который указывает, является недоступным для записи сегментом данных.
Если загружается регистр DS, ES, FS или GS, а сегмент, на который указывает, не является сегментом данных или читаемого кода.< br> Если загружается регистр DS, ES, FS или GS, а указанный сегмент является сегментом данных или несоответствующим кодом, но и RPL, и CPL больше, чем DPL.< br> #SS(0) Если адрес стека имеет неканоническую форму.
#SS(селектор) Если регистр SS загружается, а сегмент, на который он указывает, помечен как отсутствующий.
#PF(fault-code) Если происходит сбой страницы.
#AC(0) Если включена проверка выравнивания и выполняется обращение к невыровненной памяти во время текущего vilege level равен 3.
#UD При попытке загрузки регистра CS. Если используется префикс LOCK.
Но обратите внимание, что #NP здесь не встречается! Это предполагает, что текущий бит (P) проверяется только для FS, GS, CS и SS, но не для DS и ES. (Но я думаю, что бит P проверяется для всех сегментов.) Эти цитаты также предполагают, что часть RPL селектора любого сегментного регистра также используется.
Селектор нулевого сегмента
Селектор нулевого сегмента — это селектор, значение которого равно 0x0000, 0x0001, 0x0002 или 0x0003. Для процессора все эти значения всегда имеют одинаковый эффект. Все они выбирают один и тот же дескриптор, запись 0 GDT.
Селектор нулевого сегмента не может быть загружен в CS в любом режиме, использующем сегментацию (включая 64-битный режим), потому что CS всегда должен содержать фактический селектор. Попытка сделать это генерирует исключение GP.
Селектор нулевого сегмента может быть загружен в SS в 64-битном режиме (в отличие от других режимов), но только в определенных ситуациях. Дополнительные сведения см. в части «Исключение общей защиты (#GP)» руководства Intel V3 6.15.
Селектор нулевого сегмента можно загрузить в DS, ES, GS и FS.
Руководство Intel V3 5.4.1.1:
В 64-битном режиме процессор не выполняет проверку селекторов сегментов NULL во время выполнения. Процессор не вызывает ошибку #GP при попытке доступа к памяти, где регистр сегмента, на который ссылаются, имеет селектор сегмента NULL.
Я нахожу это очень интересным, как я объясню позже. (Мне также кажется странным, что в главе 3, посвященной сегментации, этого не говорится).
Мне не совсем понятно, загружает ли процессор нулевой дескриптор из памяти в невидимую часть сегментного регистра при загрузке его нулевым селектором.
Руководство Intel V3 3.4.2:
Первая запись GDT не используется процессором.
Означает ли это, что процессор не будет загружать нулевой дескриптор? Или, возможно, это просто означает, что содержимое дескриптора не используется. Позже в 3.4.4 говорится:
Чтобы настроить режим совместимости для приложения, инструкции по загрузке сегментов (MOV в Sreg, POP Sreg) нормально работают в 64-битном режиме. Запись считывается из таблицы системных дескрипторов (GDT или LDT) и загружается в скрытую часть сегментного регистра. База регистра дескриптора, лимит и атрибутивные поля загружены. Однако содержимое селектора сегментов данных и стека, а также регистров дескриптора игнорируется.
Описание инструкции POP из Intel Manual V2 гласит:
64-БИТНЫЙ РЕЖИМ
ЕСЛИ FS или GS загружаются с селектором NULL;
THEN
SegmentRegister ← селектор сегмента;
SegmentRegister ← дескриптор сегмента;
FI;
Описание инструкции MOV из Intel Manual V2 гласит:
ЕСЛИ DS, ES, FS или GS загружаются с селектором NULL
ТО
SegmentRegister ← селектор сегмента;
SegmentRegister ← дескриптор сегмента;
FI;
Это говорит о том, что нулевой дескриптор действительно загружается, но его содержимое игнорируется. Ядро Linux определяет нулевой дескриптор, чтобы все биты были равны нулю. Я читал во многих статьях и учебниках, что это обязательно. Однако Коллинз говорит, что в этом нет необходимости:
Первая запись в глобальной таблице дескрипторов (GDT) называется нулевым дескриптором. Дескриптор NULL уникален для GDT, так как он имеет TI=0 и INDEX=0. В большинстве печатных документов указано, что эта запись в таблице дескрипторов должна быть равна 0. Даже Intel несколько двусмысленно относится к этому вопросу, никогда не говоря, для чего ее НЕЛЬЗЯ использовать. Intel заявляет, что процессор никогда не ссылается на 0-ю запись в таблице дескрипторов.
Насколько я знаю, Intel не накладывает никаких ограничений на содержимое нулевого дескриптора. Так что я думаю, что Коллинз прав.
Чем интересна 5.4.1.1?
Потому что это означает, что можно использовать DS, ES, GS и GS для хранения любой из констант 0x0000, 0x0001, 0x0002 или 0x0003 в 64-битном режиме. Гарантируется, что GDT содержит по крайней мере нулевой дескриптор, поэтому проверка ограничения таблицы дескрипторов будет пройдена (это может быть не так с другими селекторами). Кроме того, все ссылки на любой из этих сегментов по-прежнему будут выполняться успешно. Инструкцию MOV можно использовать для перемещения значения из сегментного регистра в GPR и последующего выполнения над ним операции.
Руководство AMD
Быть написанным.
person
Hadi Brais
schedule
13.04.2018
L
в дескрипторе сегмента, для которого вы установилиCS
. x86-64_Changes) Таким образом, x86-64 переключается между длинным режимом и режимом совместимости с помощьюjmp far
для нового сегмента кода или с помощьюiret
или других вещей, которые изменяют CS:RIP, а не только RIP. Вместо того, чтобы изобретать новый механизм для этого, они просто использовали существующий материал сегмента, потому что ЦП все еще должен поддерживать его для устаревшего режима. - person Peter Cordes   schedule 13.04.2018