System
CET
Control-flow Enforcement Technology: shadow stacks, which hold a copy of every return address that ordinary stores cannot change, and indirect branch tracking, which allows indirect jumps only to ENDBR instructions.
- CPUID
- CET
CPUID.(EAX=07H,ECX=0):ECX[7] - Instructions
- 14 mnemonics
- Processors
- Tiger Lake, Alder Lake, Arrow Lake, Panther Lake, Nova Lake, Sapphire Rapids, Emerald Rapids, Granite Rapids, Diamond Rapids, Sierra Forest, Clearwater Forest, Zen 3, Zen 4, Zen 5, Zen 6
Note: Zen 3 to Zen 6 have the shadow stacks of CET but not its indirect branch tracking, so ENDBR32 and ENDBR64 run on them as hint NOPs. AMD's references for Zen 3, Zen 4 and Zen 5 (55898, 55901, 57238) set CPUID_Fn00000007_ECX_x00[CET_SS] (bit 7) and leave bit 20 of CPUID_Fn00000007_EDX_x00, which Intel gives to indirect branch tracking, reserved and clear.
Note: Zen 6 is listed because Zen 5 has these instructions. GCC's -march sets, which give the other features of Zen 6, leave them out, and AMD has not yet published a Processor Programming Reference for Zen 6.
Control-flow Enforcement Technology defends against attacks that redirect a program by overwriting return addresses or function pointers. It has two parts, each with its own CPUID bit:
- Shadow stacks. CALL pushes the return address on the normal
stack and on a second stack that ordinary stores cannot write; RET
compares the two and raises a control-protection exception if they
differ. RDSSPQ reads the shadow-stack pointer,
INCSSPQ pops entries as
longjmpmust, RSTORSSP and SAVEPREVSSP switch between shadow stacks, WRSSQ writes to one where the operating system allows it, and WRUSSQ lets the kernel write a user shadow stack. SETSSBSY and CLRSSBSY manage the kernel’s shadow stacks where FRED is not used. - Indirect branch tracking. An indirect call or jump must land on ENDBR64 (or ENDBR32), which compilers place at function entries; other targets fault.
ENDBR64 and RDSSPQ execute as NOPs on processors without CET, so a binary built for it still runs everywhere. Linux supports shadow stacks for user programs, which the dynamic loader enables for binaries marked for it, and indirect branch tracking in the kernel. XED puts all CET instructions in one ISA set, whose CPUID requirement is the shadow stack bit.
Instructions
| Mnemonic | Summary | Forms |
|---|---|---|
| CLRSSBSY | Clears the busy flag of a supervisor shadow-stack token in memory and zeroes the shadow-stack pointer; not with FRED. | 1 |
| ENDBR32 | Marks a valid target of an indirect call or jump in 32-bit code for CET indirect branch tracking; a NOP on other processors. | 1 |
| ENDBR64 | Marks a valid target of an indirect call or jump in 64-bit code for CET indirect branch tracking; a NOP on other processors. | 1 |
| INCSSPD | Pops and discards the number of 4-byte shadow-stack entries given in the low byte of a register, as unwinding the stack needs; CET. | 1 |
| INCSSPQ | Pops and discards the number of 8-byte shadow-stack entries given in the low byte of a register, as unwinding the stack needs; CET. | 1 |
| RDSSPD | Copies the low 32 bits of the shadow-stack pointer into a register; a NOP where shadow stacks are off, which code can test for. | 1 |
| RDSSPQ | Copies the 64-bit shadow-stack pointer into a register; a NOP where shadow stacks are off, which code can test for. | 1 |
| RSTORSSP | Switches the shadow-stack pointer to the one in a restore token in memory, the way user-space stack switching works under CET. | 1 |
| SAVEPREVSSP | Pushes a restore token onto the shadow stack that RSTORSSP switched away from, so it can be resumed later; CET. | 1 |
| SETSSBSY | Marks the supervisor shadow-stack token at IA32_PL0_SSP busy and loads the shadow-stack pointer from it; not with FRED. | 1 |
| WRSSD | Writes a 32-bit value to the current privilege level's shadow stack, where the operating system allows such writes. | 1 |
| WRSSQ | Writes a 64-bit value to the current privilege level's shadow stack, where the operating system allows such writes. | 1 |
| WRUSSD | Lets ring-0 code write a 32-bit value to a user-mode shadow stack. | 1 |
| WRUSSQ | Lets ring-0 code write a 64-bit value to a user-mode shadow stack. | 1 |
CPUID and processors
XED splits CET into 1 ISA set. Software can use a form when the processor reports every CPUID bit of one alternative of the form's ISA set.
| ISA set | CPUID | Processors |
|---|---|---|
CET | CET | Tiger Lake, Alder Lake, Arrow Lake, Panther Lake, Nova Lake, Sapphire Rapids, Emerald Rapids, Granite Rapids, Diamond Rapids, Sierra Forest, Clearwater Forest, Zen 3, Zen 4, Zen 5, Zen 6 Note: Zen 3 to Zen 6 have the shadow stacks of CET but not its indirect branch tracking, so ENDBR32 and ENDBR64 run on them as hint NOPs. AMD's references for Zen 3, Zen 4 and Zen 5 (55898, 55901, 57238) set CPUID_Fn00000007_ECX_x00[CET_SS] (bit 7) and leave bit 20 of CPUID_Fn00000007_EDX_x00, which Intel gives to indirect branch tracking, reserved and clear. Note: Zen 6 is listed because Zen 5 has these instructions. GCC's -march sets, which give the other features of Zen 6, leave them out, and AMD has not yet published a Processor Programming Reference for Zen 6. |
Sources
- Intel XED v2026.08.23 (commit
0bcb6237345c): forms, encodings, ISA sets, CPUID bits and chip model. - The CPU data of x86-64.net: Zen 3 to Zen 6, from GCC’s
-marchfeature sets and AMD’s Processor Programming References, which the page of each processor cites. - Intel 64 and IA-32 Architectures Software Developer's Manual, Volume 2 (325383-093, September 2026)
- Linux kernel documentation: Control-flow Enforcement Technology (CET) Shadow Stack
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 text is our own.