RET

Return From Procedure

stableVMJITAOTinstruction

Encodings

OpcodeInstructionOp/En64-bitCompat/LegacyDescription
C3RETZOValidValidNear return to calling procedure.
CBRETZOValidValidFar return to calling procedure.
C2 iwRET imm16IValidValidNear return to calling procedure and pop imm16 bytes from stack.
CA iwRET imm16IValidValidFar return to calling procedure and pop imm16 bytes from stack.

Operand encoding

Each mode is a value of the Op/En column above. It says which field of the encoded instruction carries each operand, in the order they are written, and whether the instruction reads it, writes it or both.

I

  1. imm16

Measured cost

Not measured: it does not run on 64-bit processors.

Description

Transfers program control to a return address located on the top of the stack. The address is usually placed on the stack by a CALL instruction, and the return is made to the instruction that follows the CALL instruction.

The optional source operand specifies the number of stack bytes to be released after the return address is popped; the default is none. This operand can be used to release parameters from the stack that were passed to the called procedure and are no longer needed. It must be used when the CALL instruction used to switch to a new procedure uses a call gate with a non-zero word count to access the new procedure. Here, the source operand for the RET instruction must specify the same number of bytes as is specified in the word count field of the call gate.

The RET instruction can be used to execute three different types of returns:

to by the CS register), sometimes referred to as an intrasegment return.

sometimes referred to as an intersegment return.

executing program or procedure.

The inter-privilege-level return type can only be executed in protected mode. See the section titled "Calling Procedures Using Call and RET" in Chapter 6 of the Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for detailed information on near, far, and inter-privilege-level returns.

When executing a near return, the processor pops the return instruction pointer (offset) from the top of the stack into the EIP register and begins program execution at the new instruction pointer. The CS register is unchanged.

When executing a far return, the processor pops the return instruction pointer from the top of the stack into the EIP register, then pops the segment selector from the top of the stack into the CS register. The processor then begins program execution in the new code segment at the new instruction pointer.

The mechanics of an inter-privilege-level far return are similar to an intersegment return, except that the processor examines the privilege levels and access rights of the code and stack segments being returned to determine if the control transfer is allowed to be made. The DS, ES, FS, and GS segment registers are cleared by the RET instruction during an inter-privilege-level return if they refer to segments that are not allowed to be accessed at the new privilege level. Since a stack switch also occurs on an inter-privilege level return, the ESP and SS registers are loaded from the stack.

If parameters are passed to the called procedure during an inter-privilege level call, the optional source operand must be used with the RET instruction to release the parameters on the return. Here, the parameters are released both from the called procedure's stack and the calling procedure's stack (that is, the stack being returned to).

In 64-bit mode, the default operation size of this instruction is the stack-address size, i.e., 64 bits. This applies to near returns, not far returns; the default operation size of far returns is 32 bits.

Refer to Chapter 6, "Procedure Calls, Interrupts, and Exceptions," and Chapter 18, "Control-flow Enforcement Technology (CET)," in the Intel(R) 64 and IA-32 Architectures Software Developer's Manual, Volume 1, for CET details.

When FRED transitions are enabled, an execution of far RET that would change CPL causes a general-protection exception, as does an execution of far RET that would enter compatibility mode when CPL is 0.

Instruction ordering. Instructions following a far return may be fetched from memory before earlier instructions complete execution, but they will not execute (even speculatively) until all instructions prior to the far return have completed execution (the later instructions may execute before data stored by the earlier instructions have become globally visible).

Unlike near indirect CALL and near indirect JMP, the processor will not speculatively execute the next sequential instruction after a near RET unless that instruction is also the target of a jump or is a target in a branch predictor.

Operation

(* 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;

Flags affected

None.

Description

Rotates the bits of source operand right by the count value specified in imm8 without affecting arithmetic flags. The result is written to the destination operand. This instruction is not supported in real mode and virtual-8086 mode. The operand size is always 32 bits if not in 64-bit mode. In 64-bit mode operand size 64 requires VEX.W1. VEX.W1 is ignored in non-64-bit modes. An attempt to execute this instruction with VEX.L not equal to 0 will cause #UD.

Operation

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;

Flags affected

None.

SIMD Floating-Point Exceptions

None.

Other Exceptions

See Table 2-29, "Type 13 Class Exception Conditions."

RORX -- Rotate Right Logical Without Affecting Flags

Exceptions

Protected mode
#GP(0)If the return code or stack segment selector is NULL. If the return instruction pointer is not within the return code segment limit. If returning to 32-bit or compatibility mode and the previous SSP from shadow stack (when returning to CPL <3) or from IA32_PL3_SSP (returning to CPL 3) is beyond 4GB.
#GP(selector)If the RPL of the return code segment selector is less then the CPL. If the return code or stack segment selector index is not within its descriptor table limits. If the return code segment descriptor does not indicate a code segment. If the return code segment is non-conforming and the segment selector's DPL is not equal to the RPL of the code segment's segment selector If the return code segment is conforming and the segment selector's DPL greater than the RPL of the code segment's segment selector If the stack segment is not a writable data segment. If the stack segment selector RPL is not equal to the RPL of the return code segment selector. If the stack segment descriptor DPL is not equal to the RPL of the return code segment selector.
#SS(0)If the top bytes of stack are not within stack limits. If the return stack segment is not present.
#NP(selector)If the return code segment is not present. #PF(fault-code) If a page fault occurs.
#AC(0)If an unaligned memory access occurs when the CPL is 3 and alignment checking is enabled. #CP(Far-RET/IRET) If the previous SSP from shadow stack (when returning to CPL <3) or from IA32_PL3_SSP (returning to CPL 3) is not 4 byte aligned. If return instruction pointer from stack and shadow stack do not match.
Real address mode
#GPIf the return instruction pointer is not within the return code segment limit
#SSIf the top bytes of stack are not within stack limits.
Virtual-8086 mode
#GP(0)If the return instruction pointer is not within the return code segment limit
#SS(0)If the top bytes of stack are not within stack limits. #PF(fault-code) If a page fault occurs.
#AC(0)If an unaligned memory access occurs when alignment checking is enabled.
Compatibility mode
Same as 64-bit mode exceptions.
64-bit mode
#GP(0)If the return instruction pointer is non-canonical. If the return instruction pointer is not within the return code segment limit. If the stack segment selector is NULL going back to compatibility mode. If the stack segment selector is NULL going back to CPL3 64-bit mode. If a NULL stack segment selector RPL is not equal to CPL going back to non-CPL3 64-bit mode. If the return code segment selector is NULL. If returning to 32-bit or compatibility mode and the previous SSP from shadow stack (when returning to CPL <3) or from IA32_PL3_SSP (returning to CPL 3) is beyond 4GB.
#GP(selector)If the proposed segment descriptor for a code segment does not indicate it is a code segment. If the proposed new code segment descriptor has both the D-bit and L-bit set. If the DPL for a nonconforming-code segment is not equal to the RPL of the code segment selector. If CPL is greater than the RPL of the code segment selector. If FRED transitions are enabled and CPL is less than the RPL of the code segment selector. If FRED transitions are enabled and CPL = 0 and far RET would enter compatibility mode. If the DPL of a conforming-code segment is greater than the return code segment selector RPL. If a segment selector index is outside its descriptor table limits. If a segment descriptor memory address is non-canonical. If the stack segment is not a writable data segment. If the stack segment descriptor DPL is not equal to the RPL of the return code segment selector. If the stack segment selector RPL is not equal to the RPL of the return code segment selector.
#SS(0)If an attempt to pop a value off the stack violates the SS limit. If an attempt to pop a value off the stack causes a non-canonical address to be referenced.
#NP(selector)If the return code or stack segment is not present. #PF(fault-code) If a page fault occurs.
#AC(0)If alignment checking is enabled and an unaligned memory reference is made while the current privilege level is 3. #CP(Far-RET/IRET) If the previous SSP from shadow stack (when returning to CPL <3) or from IA32_PL3_SSP (returning to CPL 3) is not 4 byte aligned. If return instruction pointer from stack and shadow stack do not match. RORX -- Rotate Right Logical Without Affecting Flags Opcode/ Op/ 64/32- CPUID Description Instruction En bit Feature Mode Flag VEX.LZ.F2.0F3A.W0 F0 /r ib RMI V/V BMI2 Rotate 32-bit r/m32 right imm8 times and load into r32 without RORX r32, r/m32, imm8 affecting arithmetic flags. VEX.LZ.F2.0F3A.W1 F0 /r ib RMI V/N.E. BMI2 Rotate 64-bit r/m64 right imm8 times and load into r64 without RORX r64, r/m64, imm8 affecting arithmetic flags.

Sources