Инструкция mov es, ax
вызовет ошибку общей защиты (#GP), поскольку текущий уровень привилегий (CPL) больше, чем уровень привилегий дескриптора (DPL), или запрошенный уровень привилегий (RPL) будет игнорироваться, посколькучисленно не выше, чем DPL. В вашем примере, поскольку он работает в пользовательском режиме, CPL равен 3. Это означает, что DPL дескриптора также должен быть равен 3, иначе инструкция сработает. Если DPL равен 3, то сбоя не будет, но RPL фактически игнорируется, поскольку он не может быть выше, чем DPL.
(Обратите внимание, что проверки уровня привилегий сегмента выполняются только тогда, когдарегистр сегмента загружен, поэтому из-за них может произойти сбой только команды mov es, ax
. *
В документации по инструкции MOV в Руководстве разработчика программного обеспечения Intel объясняется, когда это приведет к ошибке #GP при загрузкерегистр сегмента:
IF DS, ES, FS, or GS is loaded with non-NULL selector
THEN
IF segment selector index is outside descriptor table limits
or segment is not a data or readable code segment
or ((segment is a data or nonconforming code segment)
or ((RPL > DPL) and (CPL > DPL))
THEN #GP(selector); FI;
IF segment not marked present
THEN #NP(selector);
ELSE
SegmentRegister ← segment selector;
SegmentRegister ← segment descriptor; FI;
FI;
Поведение самого высокого из используемых DPL и RPL задокументировано в Intel SDM Volume 3, «5.5 PRIVILEGE LEVELS»:
- Запрошенный уровень привилегий (RPL) - [...] Даже если программа или задача, запрашивающая доступ к сегменту, имеет достаточные привилегии для доступа к сегменту, доступ запрещается, если RPL не имеет достаточного уровня привилегий. ,То есть, если RPL селектора сегмента численно больше, чем CPL, RPL переопределяет CPL, и наоборот. [...]
Поле RPL селектора позволяет повысить эффективный уровень привилегий только до численно более высокого или менее привилегированного уровня, чем DPL. Это не имеет никакого эффекта, если вы установите его на численно более низкий уровень.
Другими словами, если селектор 0x10 ссылается на сегмент данных режима ядра (DPL = 0), то ваш код будет аварийно завершаться. Если селектор 0x10 является сегментом данных пользовательского режима (DPL = 3), он обрабатывается так же, как если бы вы использовали вместо него 0x13 (RPL = 3).
Обратите внимание, что на практике это не имеет значенияво многом, так как все современные операционные системы используют модель плоского сегмента, где каждый сегмент имеет базу 0 и может получить доступ ко всему линейному адресному пространству. Код пользовательского режима на самом деле не ограничен в доступе к коду и данным ядра посредством проверок сегментов, а через защиту страниц. Они используют только CPL, чтобы определить, должен ли быть предоставлен доступ к страницам режима супервизора (ядра).