Система команд x86 |
|
Программирование - Архитектура и система команд микропроцессоров x86 |
RET
Влияние команды на флаги и форматы команды:
|
|
|
|
|
|
|
|
|
C3 |
RET |
Ближний возврат из процедуры |
8086 |
retn |
CB |
RET |
Дальний возврат из процедуры |
8086 |
retf |
C2 iw |
RET imm16 |
Ближний возврат из процедуры с освобождением imm16 байт в стеке |
8086 |
retn 2 |
CA iw |
RET imm16 |
Дальний возврат из процедуры с освобождением imm16 байт в стеке |
8086 |
retf 6 |
Описание:
Команда RET предназначена для возврата из подпрограмм, она передает управление по адресу возврата, выбираемому из стека. Этот адрес обычно помещается в стек командой CALL. Необязательный числовой параметр команды RET указывает количество байт, которые команда дополнительно освобождает в стеке после извлечения адреса возврата (эти байты могли содержать, например, параметры покидаемой подпрограммы, переданные командой CALL-через_шлюз_вызова).
Поддерживается две разновидности команды возврата: ближняя и дальняя. Ближний возврат позволяет передавать управление только внутри одного кодового сегмента, дальний — допускает межсегментные переходы.
Для ближнего возврата восстанавливаемый из стека адрес является абсолютным смещением в сегменте, которое помещается в указатель команд (регистр CS при этом не изменяется). Для дальнего возврата адрес в стеке является дальним указателем, первым извлекается смещение, затем следует селектор.
В реальном режиме регистры CS и IP загружаются сразу без каких-либо проверок.
В защищенном режиме дальний возврат инициализирует проверку селектора и дескриптора адреса возврата. Кроме этого, возврат к меньшему уровню привилегий вызывает перезагрузку стека SS:eSP значением, сохраненным перед блоком параметров стека покидаемой процедуры. Сегментные регистры DS, ES, FS и GS могут быть очищены при выполнении дальнего возврата к меньшему уровню привилегий, если значения селекторов в этих регистрах задают сегменты, которые не могут быть использованы на новом уровне привилегий (определяется путем анализа соответствующих дескрипторов).
Если осуществляется дальний возврат с изменением уровня привилегий и очисткой блока параметров в стеке, то соответствующее число байт освобождается как в стеке покидаемой процедуры, так и в стеке головной процедуры.
Операция:
IF (Команда ближний RET) (* RETN *)
THEN
IF OperandSize = 16
THEN
6 байт в вершине стека должны попадать в пределы стекового сегмента, иначе #SS(0);
tempEIP = Pop();
tempEIP = tempEIP AND 0000FFFFh;
tempEIP должен попадать в пределы кодового сегмента, иначе GP(0);
EIP = tempEIP;
ELSE (* OperandSize = 32 *)
12 байт в вершине стека должны попадать в пределы стекового сегмента, иначе #SS(0);
EIP = Pop();
FI;
IF (Команда имеет непосредственный операнд) THEN
IF StackAddressSize = 32
THEN
ESP = ESP + SRC; (* Освобождение места в стеке *)
ELSE (* StackAddressSize = 16 *)
SP = SP + SRC; (* Освобождение места в стеке *)
FI;
FI;
FI;
IF (PE = 0 OR (PE = 1 AND VM = 1)) AND (Команда дальний RET)(* Реальный или виртуальный-8086 режим, RETF *)
THEN
IF OperandSize = 16
THEN
6 байт в вершине стека должны попадать в пределы стекового сегмента, иначе #SS(0);
tempEIP = Pop();
tempEIP = tempEIP AND 0000FFFFh;
tempEIP должен попадать в пределы кодового сегмента, иначе GP(0);
EIP = tempEIP;
CS = Pop(); (* Извлекает из стека 16 бит *)
ELSE (* OperandSize = 32 *)
12 байт в вершине стека должны попадать в пределы стекового сегмента, иначе #SS(0);
EIP = Pop();
CS = Pop(); (* Извлекает из стека 32 бита, старшие 16 бит очищаются *)
FI;
IF (Команда имеет непосредственный операнд) THEN SP = SP + (SRC AND FFFFh); FI;
FI;
IF (PE = 1 AND VM = 0) AND (Команда дальний RET)(* Защищенный режим, не V86 режим, команда RETF *)
THEN
IF OperandSize = 32
THEN Два двойных слова в вершине стека должны попадать в пределы стекового сегмента, иначе #SS(0);
ELSE Два слова в вершине стека должны попадать в пределы стекового сегмента, иначе #SS(0);
FI;
Проверка возвращаемого селектора кодового сегмента и соответствующего дескриптора:
Селектор должен быть не нулевым, иначе #GP(0);
RPL селектора должен быть ³ CPL, иначе #GP(Возвращаемый селектор);
Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(Возвращаемый селектор);
Байт AR дескриптора должен задавать кодовый сегмент, иначе #GP(Возвращаемый селектор);
Для согласованного кодового сегмента RPL селектора должен быть ³ DPL CPL, иначе #GP(Возвращаемый селектор);
Сегмент должен присутствовать, иначе #NP(Возвращаемый селектор);
IF (RPL возвращаемого селектора = CPL)
THEN GOTO RETURN-SAME-LEVEL;
ELSE GOTO RETURN-OUTER-LEVEL;
FI;
FI;
SAME-LEVEL:
Возвращаемый указатель команды должен попадать в пределы сегмента CS, иначе #GP(0);
IF OperandSize = 32
THEN
EIP = Pop();
CS = Pop(); (* Выбирается 32 бита, старшие 16 бит отбрасываются *)
ELSE (* OperandSize = 16 *)
EIP = Pop();
EIP = EIP AND 0000FFFFh;
CS = Pop(); (* Выбирается 16 бит *)
FI;
IF (Команда имеет непосредственный операнд) THEN
IF StackAddressSize = 32
THEN
ESP = ESP + SRC; (* Освобождение места в стеке *)
ELSE (* StackAddressSize = 16 *)
SP = SP + SRC; (* Освобождение места в стеке *)
FI;
FI;
OUTER-PRIVILEGE-LEVEL:
IF OperandSize = 32
THEN В пределы стека должны попадать верхние 16 + SRC байт, иначе #SS(0);
ELSE В пределы стека должны попадать верхние 8 + SRC байт, иначе #SS(0);
FI;
Проверка возвращаемого селектора SS и соответствующего дескриптора стекового сегмента:
Селектор должен быть не нулевым, иначе #GP(0);
Индекс селектора должен попадать в пределы таблицы дескрипторов, иначе #GP(SS селектор);
RPL селектора должен быть равен RPL возвращаемого CS селектора, иначе #GP(SS селектор);
AR байт дескриптора должен задавать разрешенный для записи сегмент данных, иначе #GP(SS селектор);
DPL сегмента стека должен быть равен RPL возвращаемого CS селектора, иначе #GP(SS селектор);
Сегмент должен присутствовать, иначе #SS(SS селектор);
Возвращаемый указатель команды должен попадать в пределы сегмента CS, иначе #GP(0);
Установить CPL равным RPL в возвращаемом CS селекторе;
IF OperandSize = 32
THEN
EIP = Pop();
CS = Pop(); (* Выбирается 32 бита, старшие 16 бит отбрасываются *)
CS.RPL = CPL;
eSP = eSP + SRC; (* Корректировка стека покидаемой процедуры *)
tempESP = Pop();
tempSS = Pop(); (* Выбирается 32 бита, старшие 16 бит отбрасываются *)
ESP = tempESP;
SS = tempSS;
ELSE
EIP = Pop();
EIP = EIP AND 0000FFFFh;
CS = Pop(); (* Выбирается 16 бит *)
CS.RPL = CPL;
eSP = eSP + SRC;
tempESP = Pop();
tempSS = Pop(); (* Выбирается 16 бит *)
ESP = tempESP;
SS = tempSS;
FI;
Загрузить дескриптор CS в скрытую часть регистра CS;
Загрузить дескриптор SS в скрытую часть регистра SS;
FOR ES, FS, GS, DS (* Для каждого из регистров ES, FS, GS и DS *)
DO
IF (Значение регистра недопустимо для текущего уровня)
THEN Обнулить регистр (селектор = 0);
FI;
Быть допустимым для текущего уровня - значит отвечать следующим условиям:
Индекс селектора должен попадать в пределы таблицы дескрипторов;
AR байт дескриптора должен задавать разрешенный для чтения сегмент кода или данных;
Для сегмента данных и несогласованного кодового сегмента DPL должен быть ³ CPL и DPL должен быть ³ RPL;
OD;
eSP = eSP + SRC; (* Корректировка стека головной процедуры *)
Особые ситуации защищенного режима:
#GP, #NP или #SS, как описано в разделе "Операция". #PF(Код ошибки) при страничной ошибке.
#AC(0) при невыровненной ссылке в память при текущем уровне привилегий равном 3.
Особые ситуации режима реальной адресации:
#GP, если возвращаемый указатель команды находится вне пространства эффективных адресов в сегменте CS.
#SS, если необходимое число байт вершины стека не находится в пространстве эффективных адресов сегмента SS.
Особые ситуации режима V86:
Такие же, как и в режиме реальной адресации.
#PF(Код ошибки) при страничной ошибке.
#AC(0) при невыровненной ссылке в память.
Все права защищены © Алексей Ровдо, 1994-2023. Перепечатка возможна только по согласованию с владельцем авторских прав. admin@club155.ru