Extensions
Forms
4 (4 Legacy)
Data
Intel XED v2026.08.23

RET pops 8 bytes and jumps there. Nothing checks that a CALL put them on the stack, so a function whose return address was overwritten, by a buffer overflow for example, returns wherever the new bytes point. CET’s shadow stacks close that hole: when they are enabled, RET also pops the copy that CALL wrote to the shadow stack and raises #CP if the two differ. Intel and AMD both have shadow stacks; on Linux the loader turns them on for programs whose ELF notes say they are built for it.

The forms:

  • RET (C3) is the return of all ordinary 64-bit code.
  • RET imm16 (C2) adds imm16 to RSP after the pop, releasing the stack arguments that the caller passed. 32-bit conventions in which the callee cleans up, such as __stdcall (see the 32-bit Windows conventions), end in it; in the 64-bit ABIs the caller owns its argument area, so compilers emit a plain RET.
  • Far RET (CB, CA) pops RIP and then CS. Its default operand size in 64-bit mode is 32 bits, not 64: without REX.W it pops a 4-byte offset and a 4-byte slot for CS, so a frame built with two 8-byte PUSHes, as when 64-bit code enters a compatibility-mode segment, needs the REX.W form (lretq in AT&T syntax).

Things to know:

  • Faults. A non-canonical return address raises #GP(0) at the RET, before RSP moves, as Zen 5 recorded: the bad address is still on top of the stack.
  • Prediction. Processors predict a RET from a stack of the addresses that CALLs pushed (52 entries per thread on Zen 5, by AMD’s optimization guide). A RET whose address did not come from its matching CALL, such as a PUSH of an address followed by RET to jump there, is mispredicted; Intel’s optimization manual asks for calls and returns in pairs.
  • 66 prefix. Intel’s manual fixes the operand size of near branches at 64 bits in 64-bit mode. AMD’s lets a 66 prefix make a near RET 16 bits: a 2-byte pop, with RIP cut to 16 bits.
  • Straight-line speculation. Intel’s manual promises that the bytes after a near RET are not executed speculatively unless they are also a branch target or a predicted one. It makes no such promise after an indirect JMP or CALL.

In the optimization guide

What the optimization guide says about RET, a line per claim. Each links to the claim in the guide, with its sources and where they differ.

Branches

  • Calls and returns: Returns are predicted by a return stack, which every call pushes and every return pops.
  • Calls and returns: The return stack predicts returns only while calls and returns pair up, so pushing an address and jumping, or returning to a computed address, costs mispredictions.
  • Calls and returns: A call that is the last thing a function does can become a jump to the callee, whose return then goes straight to the original caller.
  • Calls and returns: Even predicted calls and returns cost time: each leaves the predictor idle for a cycle on Zen 3 and Zen 4, a return for two on Zen 5, and Agner Fog measured one every two cycles.

Bulldozer to Excavator

  • Branches: The return address stack has 24 entries, so each call should have its ret: a deeper chain loses the oldest and an unpaired call desynchronises it, except a call to the very next instruction, which the core recognises.

Jaguar and Puma

  • Branches: A 16-entry return stack that a call to the next instruction puts out of step, and no need for rep ret.

Sandy Bridge and Ivy Bridge

  • Branches: The return stack buffer holds 16 near return addresses.

Silvermont to Goldmont Plus

  • Branches: The return stack buffer holds 16 entries on Silvermont and Goldmont, twice the in-order Atom’s.

Skylake to Cooper Lake

  • The JCC erratum: Under rare conditions a jump that crosses a 64-byte line could make these cores misbehave (erratum SKX102).

Zen and Zen+

  • Branches: The return address stack has 32 entries, of which 31 can be used, and 15 per thread with two threads.

Zen 2

  • Branches: The return address stack has 32 entries, 31 of them usable, and 15 per thread with two threads.

Zen 3

  • Branches: The return address stack has 32 entries per thread.
  • Integer execution: PUSH, POP, CALL and RET update RSP without a dependency, and loads, stores, lea and mov from RSP can use the tracked value.

Zen 4

  • Branches: The return address stack has 32 entries per thread, against 52 on Zen 5.
  • Integer execution: PUSH, POP, CALL and RET update RSP without a dependency, and loads, stores, lea and mov from RSP can use the tracked value.

Zen 5

  • Branches: The return address stack has 52 entries per thread.
  • Integer execution: PUSH, POP, CALL and RET update RSP without a dependency, and loads, stores, lea and add or sub of a small immediate through RSP can use the tracked value.

Vulnerability mitigations

Mitigations of these processor vulnerabilities use RET:

Forms

Every encoding of RET that Intel XED knows, one row per XED instruction form (iform). How to read the notation.
InstructionEncodingRequires
RET imm16 RET_NEAR_IMMwC2 iwBase instruction set
RET RET_NEARC3Base instruction set
RET imm16 RET_FAR_IMMwCA iwBase instruction set
RET RET_FARCBBase instruction set

Latency and throughput

What the scheduling models of LLVM 23.1.2 give for each form, not measurements: latency / reciprocal throughput in cycles, the ports under them. A row is a model, or models that agree; a dash, a form that its processors lack. Memory forms: latency from the address, ports without the load and store units. Which processors each model covers.
Modelimm16RET
Sandy Bridge6 / 1p5 p231 / 1p5
Haswell1 / 2p0123567 / 1p012356
Broadwell, Skylake, Skylake-SP, Ice Lake6 / 0.5p02367 / 1p012356
Alder Lake, Sapphire Rapids6 / 1p0 p2 p3 p6 p107 / 0.5p0 p2 p3 p6 p10
Lunar Lake6 / 0.67p0 p2 p4 p20 p21 p227 / 0.33p0 p2 p4 p20 p21 p22
Bonnell1 / 1p0179 / 39.5p01
Silvermont4 / 1IEC1 MEC4 / 1IEC1 MEC
Piledriver5 / 1.5AGLU01 Branch EX1 Load5 / 1.5AGLU01 Branch EX1 Load
Zen5 / 0.5AGU0 AGU1 ALU0 ALU1 ALU2 ALU31 / 0.5ALU0 ALU3
Zen 25 / 0.33AGU0 AGU1 AGU2 ALU0 ALU1 ALU2 ALU31 / 0.5ALU0 ALU3
Zen 3, Zen 45 / 0.5AGU0 AGU1 AGU2 ALU0 BRU1 LSU Load5 / 0.5AGU0 AGU1 AGU2 ALU0 BRU1 LSU Load
Jaguar4 / 1ALU0 ALU1 LAGU4 / 1ALU0 ALU1 LAGU

Operation

What the forms do, in pseudocode that our tests run against results recorded on real processors. How to read.

RET
w = OSIZE                        # the size of the return address:
if OSIZE == 16:                  # with 66, 2 bytes on AMD's (APM,
    if INTEL:                    # Zen 5)
        w = 64                   # ignored: SDM
t = load(rsp, w)                 # 8 bytes, or 2 zero-extended
if not canonical(t):
    fault(GP, 0)                 # RSP stays as it was
rsp = rsp + w // 8
rip = t

Run on AMD Zen 5 (EPYC 9645): 4 cases. Its branches for Intel's processors were not run: no Intel processor ran these forms.

RET imm16
w = OSIZE                        # as RET's
if OSIZE == 16:
    if INTEL:
        w = 64                   # ignored: SDM
t = load(rsp, w)
if not canonical(t):
    fault(GP, 0)
rsp = rsp + w // 8 + size        # and size bytes more
rip = t

Run on AMD Zen 5 (EPYC 9645): 6 cases. Its branches for Intel's processors were not run: no Intel processor ran these forms.

RET
n = OSIZE // 8
off = load(rsp, OSIZE)
sel = load(rsp + n, OSIZE) & 0xFFFF
rsp = rsp + 2 * n                # to an outer privilege level, RSP
cs = sel                         # and SS are popped too; with the
rip = off                        # checks of the descriptor

Not run on a processor: a far return loads CS from a descriptor table, which the probe does not record.

RET imm16
n = OSIZE // 8
off = load(rsp, OSIZE)
sel = load(rsp + n, OSIZE) & 0xFFFF
rsp = rsp + 2 * n + size
cs = sel
rip = off

Not run on a processor: a far return loads CS from a descriptor table, which the probe does not record.

Operands

What each form reads and writes, as Intel XED records it: the operands of its syntax, in order, and the implicit ones that the syntax does not name. How to read.
OperandKindAction
RET imm16
imm16explicitread
stackimplicitread
rSPimplicitread, write
rIPimplicitwrite
RET
stackimplicitread
rSPimplicitread, write
rIPimplicitwrite

Flags

None: XED records no flag that the forms test or change.

Attributes

What else XED records about the forms. How to read.

RET imm16 RET
far transfer; may abort a TSX transaction

CPUID and processors

Each form belongs to an XED ISA set. A form can be used when the processor reports every CPUID bit of one of its ISA set's alternatives.

CPUID requirements and processors of the XED ISA sets above. Alternatives are separated by “or”; processors follow XED’s chip model, whose AMD processors end with Zen 2, and the CPU data of this site for Zen 3 to Zen 6.
ISA setCPUIDProcessors
I86

No CPUID bit: part of the base instruction set.

Every x86-64 processor in XED’s model and Zen 3 to Zen 6

More General-purpose instructions

All 109 General-purpose instructions

Sources

  1. Intel XED v2026.08.23 (commit 0bcb6237345c): forms, encodings, operands, flags, exception classes, attributes, ISA sets, CPUID bits and chip model.
  2. The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s -march feature sets and AMD’s Processor Programming References, which the page of each processor cites.
  3. LLVM 23.1.2's x86 scheduling models (commit 85ac56026243): the latency, reciprocal throughput and ports of each form, as llvm-mca reports them.
  4. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026): Volume 2B, page 4-569 (RET)
  5. Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 1 (253665-093, September 2026)
  6. AMD64 Architecture Programmer's Manual, Volume 2: System Programming (24593, rev. 3.46, October 2026)
  7. AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and System Instructions (24594, rev. 3.39, October 2026)
  8. Linux kernel documentation: Control-flow Enforcement Technology (CET) Shadow Stack
  9. Intel 64 and IA-32 Architectures Optimization Reference Manual, Volume 1 (248966-051, October 2026)
  10. Software Optimization Guide for the AMD Zen5 Microarchitecture (58455, rev. 1.00, August 2024), Wayback Machine copy of AMD's ZIP

The tables are derived from Intel XED, Copyright Intel Corporation, licensed under the Apache License 2.0; x86-64.net converted and reformatted them. The timings come from LLVM's scheduling models, part of the LLVM Project, licensed under the Apache License 2.0 with LLVM Exceptions. The text is our own.