Селекторы сегментов
Рассмотрим теперь вопрос о том, каким образом процессор i486 использует дескрипторы сегментов после их определения. Напомним, что отправной точкой доступа к дескриптору служит содержимое сегментного регистра, называемое селектором. В процессоре i486 ради совместимости с предыдущими процессорами длина сегментных регистров сохранена равной 16 бит, однако содержимое сегментного регистра интерпретируется иначе. Если в процессоре 8086 оно служит просто старшими битами начального адреса сегмента, то в процессоре i486 селектор косвенно через дескрипторную таблицу определяет сегмент памяти. Новый формат селектора сегмента приведен на рис. 2.7.
15 2 10
Рис. 2.7. Формат селектора сегмента
Двухбитное поле запрашиваемого уровня привилегий RPL (Requested Privilege Level) не участвует в выборе дескриптора, а привлекается для контроля привилегий в механизме защиты.
Бит индикатора таблицы TI (Table Indicator) показывает, из какой дескрипторной таблицы выбирается дескриптор: если TI = 0, обращение производится к глобальной дескрипторной таблице GDT, а при TI = 1 — к локальной дескрипторной таблице LDT.
Старшие 13 бит селектора, образующие поле индекса Index, определяют нужный дескриптор в дескрипторной таблице.
Рис.2.8. Формирование линейного адреса
Процесс образования линейного адреса памяти с привлечением селектора и эффективного адреса показан на рис. 2.8. Так как дескриптор содержит восемь байт, поле индекса дополняется в процессоре тремя младшими нулями. Значение селектора с полем Index = 0 и TI = 0 допустимо, но первый элемент таблицы GDT зарезервирован процессором и должен содержать нули. Такой селектор (Index = 0, TI = 0 и поле RPL произвольно) называется пустым селектором (null selector) или нуль-селектором, а соответствующий дескриптор — пустым дескриптором. Следовательно, пустые селекторы 0000Н — 0003Н не описывают никаких полезных сегментов. Пустой селектор разрешается загружать в сегментный регистр (правда, кроме регистров CS и SS), но любая попытка использовать его в формировании адреса вызывает особый случай. Одно из возможных применений пустых селекторов заключается в следующем. Перед инициированием задачи операционная система может загрузить в регистры DS и ES пустые селекторы. Если в последующем не инициализировать эти регистры правильными селекторами, то адресация памяти через них вызовет особый случай.
Рассмотрим несколько подробнее процесс выполнения команды
mov eax,[ecx][esi+20h]
В этой команде нет специальных указаний об использовании сегмента, поэтому она обращается к текущему сегменту данных, селектор которого находится в регистре DS. Пусть в регистре DS содержится двоичное значение 00000000000110ХХВ. Так как бит TI = 0, дескриптор сегмента находится в таблице GDT и имеет номер 3. Выполнение команды включает в себя такие действия (без страничного преобразования, т.е. линейный адрес будет и физическим адресом памяти):
1. Образовать эффективный адрес ЕА = (ЕСХ) + (ESI) + 20H
2. Выбрать третий дескриптор из таблицы GDT. Для этого следует обратиться к полю базы регистра GDTR, прибавить к нему индекс из регистра DS и считать в процессор дескриптор по полученному адресу.
3. Просуммировать эффективный адрес и базовый адрес сегмента из дескриптора. В результате получится линейный адрес операнда.
4.- Обратиться к памяти по линейному адресу и передать двойное слово в регистр ЕАХ.
Описанные выше операции обращения к сегменту данных требуют считывания из памяти 8-байтного дескриптора из таблицы GDT. (Отметим, что при обращении к сегменту через таблицу LDT потребовалось бы дополнительное считывание из памяти дескриптора этой таблицы из таблицы GDT.) Если производить все эти операции при каждом обращении к памяти (в том числе и при выборке каждой команды!), производительность процессора будет невысокой. Чтобы не допустить этого, в процессоре i486 применяется так называемое кэширование (caching) дескрипторов.
Кэширование опирается на тот факт, что обращения к памяти производятся гораздо чаще, чем изменения сегментов и переключения задач. Поэтому целесообразно ускорить обращения к памяти за счет замедления загрузки сегментных регистров. Компромиссное решение заключается в ассоциировании с каждым сегментным регистром (а также с регистрами LDTR и TR) «теневого» (shadow) регистра или кэш-регистра, что показано на рис. 2.9. Такие кэш-регистры невидимы и явно недоступны программам. Когда программа загружает селектор в сегментный регистр, процессор автоматически считывает («кэширует») нужный дескриптор в соответствующий теневой регистр. Поскольку теперь дескриптор находится внутри процессора, для получения линейного адреса памяти потребуется только сформировать эффективный адрес и просуммировать его с базовым адресом сегмента из нужного теневого регистра.
Рис. 2.9. Теневые регистры дескрипторов сегментов
Если программа редко модифицирует сегментные регистры, то в Р-режиме она будет выполняться примерно с такой же скоростью, как и в R-режиме. Частые изменения сегментных регистров в Р-режиме ухудшают быстродействие программ.
ЗАГРУЗКА СЕЛЕКТОРА.Выше показано, что имеется прямая связь между селектором и определяемым им дескриптором сегмента: каждое значение селектора выбирает только один дескриптор. Однако каждый дескриптор можно выбрать четырьмя последовательными значениями селектора, так как поле RPL не влияет на выбор дескриптора. Изменение всего нескольких бит в сегментном регистре может иметь очень серьезные последствия для адресации памяти. Многие значения селекторов, вполне допустимые в процессоре 8086, могут оказаться бессмысленными для Р-режима процессора i486. Если, например, в таблице GDT определены всего четыре дескриптора, любые значения селекторов большие 001ВН окажутся недействительными (неверными), так как они обращаются к несуществующим дескрипторам за концом дескрипторной таблицы. Аналогично, если в системе не определены таблицы LDT, то любые селекторы с битом TI = 1 также будут недействительными.
По этим причинам в процессоре i486 до загрузки селектора в сегментный регистр и кэширования дескриптора осуществляется несколько контрольных проверок. Некоторые из них связаны с контролем уровней привилегий в механизме защиты, а остальные предотвращают загрузку бессмысленных селекторов. Процессор проверяет, что поле Index селектора находится в пределах таблицы, определяемой битом TI. Именно в связи с этим пределы дескрипторных таблиц хранятся вместе с их базовыми адресами. Далее, при загрузке селектора в сегментный регистр данных (DS, ES, FS и GS) тип дескриптора должен разрешать считывание из сегмента. Только выполняемые сегменты для этих регистров не допускаются, но сегменты с разрешенными операциями выполнения/считывания допустимы. В случае регистра SS в сегменте должны быть разрешены операции считывания и записи. При загрузке регистра CS сегмент должен быть обязательно исполняемым. Если селектор проходит все эти проверки, процессор анализирует флажок присутствия (бит Р) дескриптора — находится ли соответствующий сегмент в памяти. Загрузка сегментного регистра и кэширование выбираемого селектором дескриптора осуществляются только при Р = 1. В тех ситуациях, когда хотя бы одна проверка дает отрицательный результат, формируется особый случай и загрузка селектора не производится.
Когда выбираемый селектором дескриптор находится вне предела соответствующей дескрипторной таблицы или дескриптор имеет неверный тип, процессор формирует нарушение общей защиты (прерывание 13) и «виноватый» селектор включается в стек как код ошибки. Если селектор отмечен как неприсутствующий (Р = 0), генерируется нарушение неприсутствия (прерывание 11, а для сегмента SS — прерывание 12) и селектор включается в стек, чтобы процедура обработки особого случая могла выяснить его причину. Загрузка селектора со значениями 0000Н — 0003Н, т.е. пустого селектора, вызывает нарушение общей защиты только для сегментов CS и SS.
Прикладной программист не касается сложностей интерпретации селекторов и скрытых за ними дескрипторов и теневых регистров. Для манипуляций сегментными регистрами доступны обычные команды MOV, PUSH и POP, а также специальные команды загрузки LDS, LES, LFS, LGS и LSS. Однако результат загрузки сегментного регистра в Р-режиме радикально отличается от результата аналогичной операции в процессоре 8086 и R-режиме процессора i486.
Рассмотрим взаимосвязь между селекторами, выбираемыми ими дескрипторами и адресными пространствами, которые определяются дескрипторами. Отметим, во-первых, что инкремент сегментного регистра не означает выбор следующего дескриптора в дескрипторной таблице. При этом происходит инкремент поля RPL, влияющего на механизм контроля привилегий. Для перехода к следующему дескриптору необходимо увеличивать содержимое сегментного регистра на 8 (т.е. на 1000В).Во-вторых, нет никакой связи между последовательными дескрипторами в таблице (если, конечно, они специально не выстроены таким образом при создании таблицы). Даже когда селектор выбирает следующий дескриптор, этим не определяется следующий диапазон адресов. Таким образом, по селектору невозможно узнать, какое адресное пространство определяет сегментный регистр и селектор следует считать просто тэгом («этикеткой») некоторого адресного пространства.
ПРОСМОТР СЕЛЕКТОРОВ.Может показаться, что перед прикладным программистом, работающим на языке ассемблер, стоит почти невыполнимая задача, требующая знания тонкостей организации таблиц GDT и LDT. Программист не может прямо адресовать физическую память. Любое обращение к памяти (коду, стеку или данным) производится относительно базовых адресов сегментов, а они больше не хранятся в сегментных регистрах, как это реализовано в процессоре 8086. Программисту остается только одно — обращаться к памяти по символическим адресам и загружать в сегментные регистры только их.
Вместе с процессором i486 для его программной поддержки разработаны новые компиляторы, ассемблеры, редакторы связей и загрузчики. При редактировании связей (компоновке) символическим адресам назначаются действительные адреса памяти. Однако для процессора i486 окончательную привязку адресов осуществляет загрузчик. Тонкости манипуляций селекторами, дескрипторами и дескрипторными таблицами оставлены разработчикам операционных систем и системным программистам.
При выполнении программы можно просмотреть фактические значения селекторов, которые редактор связей или загрузчик назначил сегментам. По селектору можно узнать, какую дескрипторную таблицу (бит TI) и какой дескриптор сегмента (поле Index) он выбирает. Имея права доступа к дескрипторным таблицам, можно даже считать и декодировать дескриптор.
Чтобы упростить анализ селекторов, в процессоре i486 предусмотрено несколько специальных команд, сообщающих важную информацию. Команда LAR загрузки прав доступа (Load Access Rights) имеет следующий формат:
lar regl6/32, regl6/iaeml6
Она загружает в регистр-получатель права доступа селектора, адресуемого операндом regl6/meml6. Эта команда отыскивает соответствующий селектору дескриптор и возвращает байт прав доступа AR и биты G, D, X и U (расширение прав). Другими словами, команда LAR сообщает о сегменте все, кроме базового адреса и предела. Выделяя нужные биты, можно определить, доступен ли данный сегмент программе, не вызывая нарушения защиты.
Предел сегмента сообщает команда загрузки предела сегмент; LSL (Load Segment Limit) со следующим форматом:
Isl regl6/32, regl6/meml6
В 16- или 32-битный регистр-получатель загружается предел, сегмента, который определяет селектор, адресуемый операнде.: regl6/meml6. Если в дескрипторе бит гранулярности G = 1 (т.е. сегмент имеет страничную гранулярность), предел расширяется на байтную гранулярность. Поэтому при использовании сегментов со страничной гранулярностью получателем следует указывать 32-битный регистр.
Еще две команды позволяют узнать, допускает ли сегмент, определяемый селектором, операции считывания или записи. Команды проверки на считывание VERR (VERify for Read) и запись VERW (VERifyfor Write) имеют одинаковый формат:
verr regl6/meml6 verw regl6/meml6
Операнд regl6/meml6 задает в регистре или памяти селектор проверяемого сегмента. Обе эти команды устанавливают флажок ZF = 1, если программа может загрузить адресуемый селектор в сегментный регистр данных DS, ES, FS или GS, а также считывать (записывать) в сегмент без нарушения защиты. Отметим, что обе эти команды не контролируют бит Р присутствия в дескрипторе.
При выполнении приведенных выше команд процессор учитывает уровень привилегий текущей программы и тех сегментов, которые определяют проверяемые селекторы. При нарушении правил привилегий он может не возвратить нужной информации.
Дата добавления: 2015-06-05; просмотров: 2663;