RET
Retorno del procedimiento
estableVMJITAOTinstruccion
Codificaciones
| Opcode | Instruccion | Op/En | 64 bits | Compat/Legacy | Descripcion |
|---|---|---|---|---|---|
C3 | RET | ZO | Valido | Valido | Cerca de volver al procedimiento de llamada. |
CB | RET | ZO | Valido | Valido | Regreso lejos al procedimiento de llamada. |
C2 iw | RET imm16 | I | Valido | Valido | Cerca de volver al procedimiento de llamada y pop imm16 bytes de la pila. |
CA iw | RET imm16 | I | Valido | Valido | Lejos de volver al procedimiento de llamada y pop imm16 bytes de la pila. |
Codificacion de operandos
Cada modo es un valor de la columna Op/En de arriba. Dice en que campo de la instruccion codificada va cada operando, en el orden en que se escriben, y si la instruccion lo lee, lo escribe o ambas cosas.
I
imm16
Coste medido
Sin medir: no se ejecuta en procesadores de 64 bits.
Descripción
Transfiere el control del programa a una dirección de retorno situada en la parte superior de la pila. La dirección se coloca generalmente en la pila por una instrucción CALL, y el retorno se hace a la instrucción que sigue la instrucción CALL.
El operando de origen opcional especifica el número de bytes de pila para ser lanzado después de que la dirección de retorno se ha superado; el predeterminado no es ninguno. Este operando se puede utilizar para liberar los parámetros de la pila que fueron pasados al procedimiento llamado y ya no son necesarios. Debe ser utilizado cuando la instrucción CALL utilizada para cambiar a un nuevo procedimiento utiliza una puerta de llamada con un recuento de palabras no cero para acceder al nuevo procedimiento. Aquí, el operando de origen para la instrucción RET debe especificar el mismo número de bytes que se especifica en el campo de cuenta de palabras de la puerta de llamada.
La instrucción RET se puede utilizar para ejecutar tres tipos diferentes de retornos:
- Retorno cercano - Retorno a un procedimiento de convocatoria dentro del segmento actual del código (el segmento actualmente señalado)
a) Por el registro de CS), a veces referido como un retorno intrasegment.
- Retorno lejano - Retorno a un procedimiento de llamada ubicado en un segmento diferente al segmento de código actual,
a veces se refiere como un retorno intersegmento.
- Retorno a un nivel de privilegios muy elevado - Retorno a un nivel de privilegio diferente al de la actual
ejecutar programa o procedimiento.
El tipo de retorno de nivel intermedio sólo puede ejecutarse en modo protegido. Vea la sección titulada "Procedimientos de llamada usando Call and RET" en el capítulo 6 de Intel(R) 64 e IA-32 Arquitecturas Software Developer's Manual, Volumen 1, para información detallada sobre retornos cercanos, lejanos e inter-privilege-level.
Al ejecutar un regreso cercano, el procesador abre el puntero de instruccion (offset) de la parte superior de la pila en el registro EIP y comienza la ejecución del programa en el nuevo puntero de instruccion. El registro CS no cambia.
Al ejecutar un retorno lejano, el procesador abre el puntero de instruccion de vuelta desde la parte superior de la pila en el registro EIP, luego aparece el selector de segmento desde la parte superior de la pila en el registro CS. El procesador entonces comienza la ejecución del programa en el nuevo segmento de código en el nuevo puntero de instruccion.
Los mecánicos de un retorno de distancia entre niveles de privilegios son similares a un retorno de intersección, excepto que el procesador examina los niveles de privilegios y los derechos de acceso de los segmentos de código y pila que se están devolviendo para determinar si se permite la transferencia de control. Los registros de los segmentos DS, ES, FS y GS son aclarados por la instrucción RET durante un retorno entre privilegios si se refieren a segmentos que no se permiten acceder al nuevo nivel de privilegios. Como un interruptor de pila también ocurre en un nivel de retorno entre privilegios, los registros ESP y SS se cargan de la pila.
Si los parámetros se pasan al procedimiento llamado durante una llamada de nivel interprivilegio, el operando de origen opcional debe ser utilizado con la instrucción RET para liberar los parámetros en el retorno. Aquí, los parámetros se liberan tanto de la pila del procedimiento llamado y la pila del procedimiento de llamada (es decir, la pila que se devuelve a).
En modo de 64 bits, el tamaño de operación predeterminado de esta instrucción es el tamaño de la dirección de pila, es decir, 64 bits. Esto se aplica a retornos cercanos, no retornos lejanos; el tamaño de operación predeterminado de retornos lejanos es de 32 bits.
Consulte el capítulo 6, "Procedure Calls, Interrupts, and Excepcionions", y el capítulo 18, "Control-flow Enforcement Technology (CET)," en el Intel(R) 64 e IA-32 Architectures Software Developer's Manual, Volumen 1, para detalles CET.
Cuando las transiciones FRED están habilitadas, una ejecución de RET lejano que cambiaría CPL causa una excepción de protección general, al igual que una ejecución de RET lejano que entraría en modo de compatibilidad cuando CPL es 0.
Ordenación de instrucciones. Las instrucciones después de un retorno lejano pueden ser arrebatadas de memoria antes de que las instrucciones anteriores completen la ejecución, pero no ejecutarán (incluso especulativamente) hasta que todas las instrucciones antes del retorno lejano hayan completado la ejecución (las instrucciones posteriores pueden ejecutarse antes de que los datos almacenados por las instrucciones anteriores se hayan vuelto mundialmente visibles).
A diferencia de CALL indirecto cercano y casi indirecto JMP, el procesador no ejecutará especulativamente la siguiente instrucción secuencial después de un RET cercano a menos que esa instrucción sea también el objetivo de un salto o es un objetivo en un predictor de rama.
Operación
(* Near return *)
IF instruction = near return
THEN;
IF OperandSize = 32
THEN
IF top 4 bytes of stack not within stack limits
THEN #SS(0); FI;
EIP := Pop();
IF ShadowStackEnabled(CPL)
tempSsEIP = ShadowStackPop4B();
IF EIP != TempSsEIP
THEN #CP(NEAR_RET); FI;
FI;
ELSE
IF OperandSize = 64
THEN
IF top 8 bytes of stack not within stack limits
THEN #SS(0); FI;
RIP := Pop();
IF ShadowStackEnabled(CPL)
tempSsEIP = ShadowStackPop8B();
IF RIP != tempSsEIP
THEN #CP(NEAR_RET); FI;
FI;
ELSE (* OperandSize = 16 *)
IF top 2 bytes of stack not within stack limits
THEN #SS(0); FI;
tempEIP := Pop();
tempEIP := tempEIP AND 0000FFFFH;
IF tempEIP not within code segment limits
THEN #GP(0); FI;
EIP := tempEIP;
IF ShadowStackEnabled(CPL)
tempSsEip = ShadowStackPop4B();
IF EIP != tempSsEIP
THEN #CP(NEAR_RET); FI;
FI;
FI;
FI;
IF instruction has immediate operand
THEN (* Release parameters from stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE
IF StackAddressSize = 64
THEN
RSP := RSP + SRC;
ELSE (* StackAddressSize = 16 *)
SP := SP + SRC;
FI;
FI;
FI;
FI;
(* Real-address mode or virtual-8086 mode *)
IF ((PE = 0) or (PE = 1 AND VM = 1)) and instruction = far return
THEN
IF OperandSize = 32
THEN
IF top 8 bytes of stack not within stack limits
THEN #SS(0); FI;
EIP := Pop();
CS := Pop(); (* 32-bit pop, high-order 16 bits discarded *)
ELSE (* OperandSize = 16 *)
IF top 4 bytes of stack not within stack limits
THEN #SS(0); FI;
tempEIP := Pop();
tempEIP := tempEIP AND 0000FFFFH;
IF tempEIP not within code segment limits
THEN #GP(0); FI;
EIP := tempEIP;
CS := Pop(); (* 16-bit pop *)
FI;
IF instruction has immediate operand
THEN (* Release parameters from stack *)
SP := SP + (SRC AND FFFFH);
FI;
FI;
(* Protected mode, not virtual-8086 mode *)
IF (PE = 1 and VM = 0 and IA32_EFER.LMA = 0) and instruction = far return
THEN
IF OperandSize = 32
THEN
IF second doubleword on stack is not within stack limits
THEN #SS(0); FI;
ELSE (* OperandSize = 16 *)
IF second word on stack is not within stack limits
THEN #SS(0); FI;
FI;
IF return code segment selector is NULL
THEN #GP(0); FI;
IF return code segment selector addresses descriptor beyond descriptor table limit
THEN #GP(selector); FI;
Obtain descriptor to which return code segment selector points from descriptor table;
IF return code segment descriptor is not a code segment
THEN #GP(selector); FI;
IF return code segment selector RPL < CPL
THEN #GP(selector); FI;
IF return code segment descriptor is conforming and return code segment DPL > return code segment selector RPL
THEN #GP(selector); FI;
IF return code segment descriptor is non-conforming and return code segment DPL return code segment selector RPL
THEN #GP(selector); FI;
IF return code segment descriptor is not present
THEN #NP(selector); FI:
IF return code segment selector RPL > CPL
THEN GOTO RETURN-TO-OUTER-PRIVILEGE-LEVEL;
ELSE GOTO RETURN-TO-SAME-PRIVILEGE-LEVEL;
FI;
FI;
RETURN-TO-SAME-PRIVILEGE-LEVEL:
IF the return instruction pointer is not within the return code segment limit
THEN #GP(0); FI;
IF OperandSize = 32
THEN
EIP := Pop();
CS := Pop(); (* 32-bit pop, high-order 16 bits discarded *)
ELSE (* OperandSize = 16 *)
EIP := Pop();
EIP := EIP AND 0000FFFFH;
CS := Pop(); (* 16-bit pop *)
FI;
IF instruction has immediate operand
THEN (* Release parameters from stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE (* StackAddressSize = 16 *)
SP := SP + SRC;
FI;
FI;
IF ShadowStackEnabled(CPL)
(* SSP must be 8 byte aligned *)
IF SSP AND 0x7 != 0
THEN #CP(FAR-RET/IRET); FI;
tempSsCS = shadow_stack_load 8 bytes from SSP+16;
tempSsLIP = shadow_stack_load 8 bytes from SSP+8;
prevSSP = shadow_stack_load 8 bytes from SSP;
SSP = SSP + 24;
(* do a 64 bit-compare to check if any bits beyond bit 15 are set *)
tempCS = CS; (* zero pad to 64 bit *)
IF tempCS != tempSsCS
THEN #CP(FAR-RET/IRET); FI;
(* do a 64 bit-compare; pad CSBASE+RIP with 0 for 32 bit LIP*)
IF CSBASE + RIP != tempSsLIP
THEN #CP(FAR-RET/IRET); FI;
(* prevSSP must be 4 byte aligned *)
IF prevSSP AND 0x3 != 0
THEN #CP(FAR-RET/IRET); FI;
(* In legacy mode SSP must be in low 4GB *)
IF prevSSP[63:32] != 0
THEN #GP(0); FI;
SSP := prevSSP
FI;
RETURN-TO-OUTER-PRIVILEGE-LEVEL:
IF top (16 + SRC) bytes of stack are not within stack limits (OperandSize = 32)
or top (8 + SRC) bytes of stack are not within stack limits (OperandSize = 16)
THEN #SS(0); FI;
Read return segment selector;
IF stack segment selector is NULL
THEN #GP(0); FI;
IF return stack segment selector index is not within its descriptor table limits
THEN #GP(selector); FI;
Read segment descriptor pointed to by return segment selector;
IF stack segment selector RPL RPL of the return code segment selector
or stack segment is not a writable data segment
or stack segment descriptor DPL RPL of the return code segment selector
THEN #GP(selector); FI;
IF stack segment not present
THEN #SS(StackSegmentSelector); FI;
IF the return instruction pointer is not within the return code segment limit
THEN #GP(0); FI;
IF OperandSize = 32
THEN
EIP := Pop();
CS := Pop(); (* 32-bit pop, high-order 16 bits discarded; segment descriptor loaded *)
CS(RPL) := ReturnCodeSegmentSelector(RPL);
IF instruction has immediate operand
THEN (* Release parameters from called procedure's stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE (* StackAddressSize = 16 *)
SP := SP + SRC;
FI;
FI;
tempESP := Pop();
tempSS := Pop(); (* 32-bit pop, high-order 16 bits discarded; seg. descriptor loaded *)
ELSE (* OperandSize = 16 *)
EIP := Pop();
EIP := EIP AND 0000FFFFH;
CS := Pop(); (* 16-bit pop; segment descriptor loaded *)
CS(RPL) := ReturnCodeSegmentSelector(RPL);
IF instruction has immediate operand
THEN (* Release parameters from called procedure's stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE (* StackAddressSize = 16 *)
SP := SP + SRC;
FI;
FI;
tempESP := Pop();
tempSS := Pop(); (* 16-bit pop; segment descriptor loaded *)
FI;
IF ShadowStackEnabled(CPL)
(* check if 8 byte aligned *)
IF SSP AND 0x7 != 0
THEN #CP(FAR-RET/IRET); FI;
IF ReturnCodeSegmentSelector(RPL) !=3
THEN
tempSsCS = shadow_stack_load 8 bytes from SSP+16;
tempSsLIP = shadow_stack_load 8 bytes from SSP+8;
tempSSP = shadow_stack_load 8 bytes from SSP;
SSP = SSP + 24;
(* Do 64 bit compare to detect bits beyond 15 being set *)
tempCS = CS; (* zero extended to 64 bit *)
IF tempCS != tempSsCS
THEN #CP(FAR-RET/IRET); FI;
(* Do 64 bit compare; pad CSBASE+RIP with 0 for 32 bit LA *)
IF CSBASE + RIP != tempSsLIP
THEN #CP(FAR-RET/IRET); FI;
(* check if 4 byte aligned *)
IF tempSSP AND 0x3 != 0
THEN #CP(FAR-RET/IRET); FI;
FI;
FI;
tempOldCPL = CPL;
CPL := ReturnCodeSegmentSelector(RPL);
ESP := tempESP;
SS := tempSS;
tempOldSSP = SSP;
IF ShadowStackEnabled(CPL)
IF CPL = 3
THEN tempSSP := IA32_PL3_SSP; FI;
IF tempSSP[63:32] != 0
THEN #GP(0); FI;
SSP := tempSSP
FI;
(* Now past all faulting points; safe to free the token. The token free is done using the old SSP
* and using a supervisor override as old CPL was a supervisor privilege level *)
IF ShadowStackEnabled(tempOldCPL)
expected_token_value = tempOldSSP | BUSY_BIT (* busy bit - bit position 0 - must be set *)
new_token_value = tempOldSSP (* clear the busy bit *)
shadow_stack_lock_cmpxchg8b(tempOldSSP, new_token_value, expected_token_value)
FI;
FI;
FOR each SegReg in (ES, FS, GS, and DS)
DO
tempDesc := descriptor cache for SegReg (* hidden part of segment register *)
IF (SegmentSelector == NULL) OR (tempDesc(DPL) < CPL AND tempDesc(Type) is (data or non-conforming code)))
THEN (* Segment register invalid *)
SegmentSelector := 0; (*Segment selector becomes null*)
FI;
OD;
IF instruction has immediate operand
THEN (* Release parameters from calling procedure's stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE (* StackAddressSize = 16 *)
SP := SP + SRC;
FI;
FI;
(* IA-32e Mode *)
IF (PE = 1 and VM = 0 and IA32_EFER.LMA = 1) and instruction = far return
THEN
IF OperandSize = 32
THEN
IF second doubleword on stack is not within stack limits
THEN #SS(0); FI;
IF first or second doubleword on stack is not in canonical space
THEN #SS(0); FI;
ELSE
IF OperandSize = 16
THEN
IF second word on stack is not within stack limits
THEN #SS(0); FI;
IF first or second word on stack is not in canonical space
THEN #SS(0); FI;
ELSE (* OperandSize = 64 *)
IF first or second quadword on stack is not in canonical space
THEN #SS(0); FI;
FI
FI;
IF return code segment selector is NULL
THEN GP(0); FI;
IF return code segment selector addresses descriptor beyond descriptor table limit
THEN GP(selector); FI;
IF return code segment selector addresses descriptor in non-canonical space
THEN GP(selector); FI;
Obtain descriptor to which return code segment selector points from descriptor table;
IF return code segment descriptor is not a code segment
THEN #GP(selector); FI;
IF return code segment descriptor has L-bit = 1 and D-bit = 1
THEN #GP(selector); FI;
IF return code segment selector RPL < CPL or (CR4.FRED = 1 and return code segment selector RPL > CPL)
THEN #GP(selector); FI;
IF return code segment descriptor is conforming and return code segment DPL > return code segment selector RPL
THEN #GP(selector); FI;
IF return code segment descriptor is non-conforming and return code segment DPL return code segment selector RPL
THEN #GP(selector); FI;
IF CR4.FRED = 1 and CPL = 0 and L-bit is 0 in return code segment descriptor
THEN #GP(selector); FI;
IF return code segment descriptor is not present
THEN #NP(selector); FI:
IF return code segment selector RPL > CPL
THEN GOTO IA-32E-MODE-RETURN-TO-OUTER-PRIVILEGE-LEVEL;
ELSE GOTO IA-32E-MODE-RETURN-TO-SAME-PRIVILEGE-LEVEL;
FI;
FI;
IA-32E-MODE-RETURN-TO-SAME-PRIVILEGE-LEVEL:
IF the return instruction pointer is not within the return code segment limit
THEN #GP(0); FI;
IF the return instruction pointer is not within canonical address space
THEN #GP(0); FI;
IF OperandSize = 32
THEN
EIP := Pop();
CS := Pop(); (* 32-bit pop, high-order 16 bits discarded *)
ELSE
IF OperandSize = 16
THEN
EIP := Pop();
EIP := EIP AND 0000FFFFH;
CS := Pop(); (* 16-bit pop *)
ELSE (* OperandSize = 64 *)
RIP := Pop();
CS := Pop(); (* 64-bit pop, high-order 48 bits discarded *)
FI;
FI;
IF instruction has immediate operand
THEN (* Release parameters from stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE
IF StackAddressSize = 16
THEN
SP := SP + SRC;
ELSE (* StackAddressSize = 64 *)
RSP := RSP + SRC;
FI;
FI;
FI;
IF ShadowStackEnabled(CPL)
IF SSP AND 0x7 != 0 (* check if aligned to 8 bytes *)
THEN #CP(FAR-RET/IRET); FI;
tempSsCS = shadow_stack_load 8 bytes from SSP+16;
tempSsLIP = shadow_stack_load 8 bytes from SSP+8;
tempSSP = shadow_stack_load 8 bytes from SSP;
SSP = SSP + 24;
tempCS = CS; (* zero padded to 64 bit *)
IF tempCS != tempSsCS (* 64 bit compare; CS zero padded to 64 bits *)
THEN #CP(FAR-RET/IRET); FI;
IF CSBASE + RIP != tempSsLIP (* 64 bit compare *)
THEN #CP(FAR-RET/IRET); FI;
IF tempSSP AND 0x3 != 0 (* check if aligned to 4 bytes *)
THEN #CP(FAR-RET/IRET); FI;
IF (CS.L = 0 AND tempSSP[63:32] != 0) OR
(CS.L = 1 AND tempSSP is not canonical relative to the current paging mode)
THEN #GP(0); FI;
SSP := tempSSP
FI;
IA-32E-MODE-RETURN-TO-OUTER-PRIVILEGE-LEVEL:
IF top (16 + SRC) bytes of stack are not within stack limits (OperandSize = 32)
or top (8 + SRC) bytes of stack are not within stack limits (OperandSize = 16)
THEN #SS(0); FI;
IF top (16 + SRC) bytes of stack are not in canonical address space (OperandSize =32)
or top (8 + SRC) bytes of stack are not in canonical address space (OperandSize = 16)
or top (32 + SRC) bytes of stack are not in canonical address space (OperandSize = 64)
THEN #SS(0); FI;
Read return stack segment selector;
IF stack segment selector is NULL
THEN
IF new CS descriptor L-bit = 0
THEN #GP(selector);
IF stack segment selector RPL = 3
THEN #GP(selector);
FI;
IF return stack segment descriptor is not within descriptor table limits
THEN #GP(selector); FI;
IF return stack segment descriptor is in non-canonical address space
THEN #GP(selector); FI;
Read segment descriptor pointed to by return segment selector;
IF stack segment selector RPL RPL of the return code segment selector
or stack segment is not a writable data segment
or stack segment descriptor DPL RPL of the return code segment selector
THEN #GP(selector); FI;
IF stack segment not present
THEN #SS(StackSegmentSelector); FI;
IF the return instruction pointer is not within the return code segment limit
THEN #GP(0); FI:
IF the return instruction pointer is not within canonical address space
THEN #GP(0); FI;
IF OperandSize = 32
THEN
EIP := Pop();
CS := Pop(); (* 32-bit pop, high-order 16 bits discarded, segment descriptor loaded *)
CS(RPL) := ReturnCodeSegmentSelector(RPL);
IF instruction has immediate operand
THEN (* Release parameters from called procedure's stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE
IF StackAddressSize = 16
THEN
SP := SP + SRC;
ELSE (* StackAddressSize = 64 *)
RSP := RSP + SRC;
FI;
FI;
FI;
tempESP := Pop();
tempSS := Pop(); (* 32-bit pop, high-order 16 bits discarded, segment descriptor loaded *)
ELSE
IF OperandSize = 16
THEN
EIP := Pop();
EIP := EIP AND 0000FFFFH;
CS := Pop(); (* 16-bit pop; segment descriptor loaded *)
CS(RPL) := ReturnCodeSegmentSelector(RPL);
IF instruction has immediate operand
THEN (* Release parameters from called procedure's stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE
IF StackAddressSize = 16
THEN
SP := SP + SRC;
ELSE (* StackAddressSize = 64 *)
RSP := RSP + SRC;
FI;
FI;
FI;
tempESP := Pop();
tempSS := Pop(); (* 16-bit pop; segment descriptor loaded *)
ELSE (* OperandSize = 64 *)
RIP := Pop();
CS := Pop(); (* 64-bit pop; high-order 48 bits discarded; seg. descriptor loaded *)
CS(RPL) := ReturnCodeSegmentSelector(RPL);
IF instruction has immediate operand
THEN (* Release parameters from called procedure's stack *)
RSP := RSP + SRC;
FI;
tempESP := Pop();
tempSS := Pop(); (* 64-bit pop; high-order 48 bits discarded; seg. desc. loaded *)
FI;
FI;
IF ShadowStackEnabled(CPL)
(* check if 8 byte aligned *)
IF SSP AND 0x7 != 0
THEN #CP(FAR-RET/IRET); FI;
IF ReturnCodeSegmentSelector(RPL) !=3
THEN
tempSsCS = shadow_stack_load 8 bytes from SSP+16;
tempSsLIP = shadow_stack_load 8 bytes from SSP+8;
tempSSP = shadow_stack_load 8 bytes from SSP;
SSP = SSP + 24;
(* Do 64 bit compare to detect bits beyond 15 being set *)
tempCS = CS; (* zero padded to 64 bit *)
IF tempCS != tempSsCS
THEN #CP(FAR-RET/IRET); FI;
(* Do 64 bit compare; pad CSBASE+RIP with 0 for 32 bit LIP *)
IF CSBASE + RIP != tempSsLIP
THEN #CP(FAR-RET/IRET); FI;
(* check if 4 byte aligned *)
IF tempSSP AND 0x3 != 0
THEN #CP(FAR-RET/IRET); FI;
FI;
FI;
tempOldCPL = CPL;
CPL := ReturnCodeSegmentSelector(RPL);
ESP := tempESP;
SS := tempSS;
tempOldSSP = SSP;
IF ShadowStackEnabled(CPL)
IF CPL = 3
THEN tempSSP := IA32_PL3_SSP; FI;
IF (CS.L = 0 AND tempSSP[63:32] != 0) OR
(CS.L = 1 AND tempSSP is not canonical relative to the current paging mode)
THEN #GP(0); FI;
SSP := tempSSP
FI;
(* Now past all faulting points; safe to free the token. The token free is done using the old SSP
* and using a supervisor override as old CPL was a supervisor privilege level *)
IF ShadowStackEnabled(tempOldCPL)
expected_token_value = tempOldSSP | BUSY_BIT (* busy bit - bit position 0 - must be set *)
new_token_value = tempOldSSP (* clear the busy bit *)
shadow_stack_lock_cmpxchg8b(tempOldSSP, new_token_value, expected_token_value)
FI;
FOR each of segment register (ES, FS, GS, and DS)
DO
IF segment register points to data or non-conforming code segment
and CPL > segment descriptor DPL; (* DPL in hidden part of segment register *)
THEN SegmentSelector := 0; (* SegmentSelector invalid *)
FI;
OD;
IF instruction has immediate operand
THEN (* Release parameters from calling procedure's stack *)
IF StackAddressSize = 32
THEN
ESP := ESP + SRC;
ELSE
IF StackAddressSize = 16
THEN
SP := SP + SRC;
ELSE (* StackAddressSize = 64 *)
RSP := RSP + SRC;
FI;
FI;
FI;Banderas afectadas
None.
Descripción
Rota los bits de operando de origen derecho por el valor de cuenta especificado en imm8 sin afectar las banderas aritméticas. El resultado está escrito al operando de destino. Esta instrucción no es compatible en modo real y modo virtual-8086. El tamaño de operando es siempre 32 bits si no en modo de 64 bits. En modo de 64 bits tamaño de operando 64 requiere VEX.W1. VEX.W1 es ignorado en modos no-64-bit. Un intento de ejecutar esta instrucción con VEX.L no igual a 0 causará #UD.
Operación
IF (OperandSize = 32)
y := imm8 AND 1FH;
DEST := (SRC >> y) | (SRC << (32-y));
ELSEIF (OperandSize = 64)
y := imm8 AND 3FH;
DEST := (SRC >> y) | (SRC << (64-y));
FI;Banderas afectadas
None.
SIMD coma flotante Excepciones
None.
Otras excepciones
Ver Tabla 2-29, "Tipo 13 Condiciones de Excepción de Clase".
RORX -- girar derecho lógica sin afectar las banderas
Excepciones
Modo protegido
#GP(0) | Si el código de retorno o selector de segmento de pila es NULL. Si el puntero de instrucción de retorno no está dentro del límite de segmento de código de retorno. Si regresa a modo de 32 bits o compatibilidad y el SSP anterior de la pila de sombras (al regresar a CPL <3) o de IA32 PL3 SSP (regresar a CPL 3) está más allá de 4GB. |
#GP(selector) | SiRPLdel código de devoluciónselector de segmentoes menos entonces elCPL. Si el código de retorno o la pilaselector de segmentoEl índice no está dentro de sus límites de tabla descriptor. Si el descriptor del segmento de código de retorno no indica un segmento de código. Si el segmento de código de retorno no es conforme yel selector de segmento's DPLno es igual a laRPLdel segmento de códigoselector de segmentoSi el segmento de código de retorno está conformando yel selector de segmento's DPLmás grande que elRPLdel segmento de códigoselector de segmentoSi el segmento de la pila no es un segmento de datos writable.selector de segmento RPLno es igual a laRPLdel código de devoluciónselector de segmento. Si el descriptor del segmento de la pilaDPLno es igual a laRPLdel código de devoluciónselector de segmento. |
#SS(0) | Si los bytes superiores de la pila no están dentro de los límites de la pila. Si el segmento de la pila de retorno no está presente. |
#NP(selector) | Si el segmento de código de retorno no está presente. #PF(fault-code) Si un fallo de pagina ocurre. |
#AC(0) | Si un acceso de memoria no deseado ocurre cuando el CPL es 3 y la comprobación de alineación está habilitada. #CP(Far-RET/IRET) Si el SSP anterior de la pila de sombra (al regresar a CPL <3) o de IA32 PL3 SSP (regresar a CPL 3) no es alineado de 4 byte. |
Modo real
#GP | Si el retorno puntero de instruccion no está dentro del límite del segmento del código de devolución |
#SS | Si los bytes superiores de la pila no están dentro de los límites de la pila. |
Modo virtual-8086
#GP(0) | Si el retorno puntero de instruccion no está dentro del límite del segmento del código de devolución |
#SS(0) | Si los bytes superiores de la pila no están dentro de los límites de la pila. #PF(fault-code) Si un fallo de pagina ocurre. |
#AC(0) | Si un acceso de memoria no deseado ocurre cuando se activa la comprobación de alineación. |
Modo de compatibilidad
| Igual que las excepciones del modo 64-bit. |
Modo de 64 bits
#GP(0) | Si el regresopuntero de instruccionno es canónico.puntero de instruccionno está dentro del límite del segmento de código de retorno.selector de segmentoesNULLvolver al modo de compatibilidad.selector de segmentoesNULLvolver aCPL3Modo de 64 bits.NULLpilaselector de segmento RPLno es igual aCPLvolver a no-CPL3Modo 64-bit. Si el código de devoluciónselector de segmentoesNULL. Si regresa al modo de 32 bits o compatibilidad y al modo anteriorSSPde la pila de sombras (al regresar aCPL <3) o de IA32 PL3 SSP (volviendo aCPL3) está más allá de 4GB. |
#GP(selector) | Si el descriptor de segmento propuesto para un segmento de código no indica que es un segmento de código. Si el nuevo descriptor de segmento de código propuesto tiene el conjunto D-bit y L-bit.DPLpara un segmento de código no conforme no es igual alRPLdel códigoselector de segmento. SiCPLes mayor que elRPLdel códigoselector de segmento. SiFREDlas transiciones están habilitadas yCPLes menos que elRPLdel códigoselector de segmento. SiFREDlas transiciones están habilitadas yCPL= 0 y lejosRETentraría en modo de compatibilidad.DPLde un segmento de código de conformación es mayor que el código de retornoselector de segmento RPL. Siun selector de segmentoEl índice está fuera de sus límites de tabla descriptor. Si una dirección de memoria descriptor de segmento no es canónica. Si el segmento de la pila no es un segmento de datos writable.DPLno es igual a laRPLdel código de devoluciónselector de segmento. Si la pilaselector de segmento RPLno es igual a laRPLdel código de devoluciónselector de segmento. |
#SS(0) | Si un intento de crear un valor fuera de la pila viola el límite SS. Si un intento de crear un valor fuera de la pila hace que una dirección no canónica sea referenciada. |
#NP(selector) | Si el código de retorno o segmento de pila no está presente. #PF(fault-code) Si un fallo de pagina ocurre. |
#AC(0) | Si la comprobación de alineación está habilitada y se hace una referencia de memoria no alineada mientras que el nivel de privilegio actual es 3.#CP(Far-RET/IRET)Si el anteriorSSPde la pila de sombras (al regresar aCPL <3) o de IA32 PL3 SSP (volviendo aCPL3) no es 4 byte alineado.puntero de instruccionde la pila y la pila de sombra no coinciden.RORX-- girar derecho lógico sin afectar banderascódigo de operación/ Op/ 64/32-CPUIDDescripción Instrucción En bit Modo de alimentación BanderaVEX.LZ.F2.0F3A.W0F0 /r ibRMI V/V BMI2Girar 32-bitr/m32derechoimm8tiempos y carga enr32sinRORX r32, r/m32, imm8afectando las banderas aritméticas.VEX.LZ.F2.0F3A.W1F0 /r ibRMI V/N.E. BMI2Rotación 64-bitr/m64derechoimm8tiempos y carga enr64sinRORX r64, r/m64, imm8afectando las banderas aritméticas. |