Article by Ayman Alheraki on May 12 2026 12:58 PM
x86-64 architecture extends the original x86 CPU register set from 8 to 16 general-purpose registers while maintaining full backward compatibility. This is achieved using a mechanism called the REX prefix, which adds one additional bit to existing 3-bit register fields.
Registers are the fastest storage units inside the CPU. They are used for:
Arithmetic and logical operations
Function calls and return values
Memory addressing
Loop control
System-level execution
In x86-64, registers are 64-bit wide, but can also be accessed in smaller forms:
| Size | Example |
|---|---|
| 64-bit | RAX |
| 32-bit | EAX |
| 16-bit | AX |
| 8-bit | AL / AH |
In the original x86 architecture:
Registers were encoded using 3 bits
This allowed only 8 registers
$2^3 = 8$
| Binary | Decimal | Register | Role |
|---|---|---|---|
| 000 | 0 | RAX | Arithmetic, return value |
| 001 | 1 | RCX | Loop counter |
| 010 | 2 | RDX | Multiplication/division helper |
| 011 | 3 | RBX | General purpose |
| 100 | 4 | RSP | Stack pointer |
| 101 | 5 | RBP | Frame pointer |
| 110 | 6 | RSI | Source index |
| 111 | 7 | RDI | Destination index |
Modern software requires:
More function arguments
More temporary registers for optimization
Reduced memory access overhead
Thus, AMD introduced 8 additional registers:
R8 to R15
However, the instruction encoding format could not be changed for backward compatibility.
The REX prefix is a single byte added before the opcode:
0100WRXB
It is always in the range:
xxxxxxxxxx0x40 to 0x4F
| Bit | Function |
|---|---|
| W | 64-bit operand size |
| R | Extends REG field |
| X | Extends SIB index field |
| B | Extends R/M or base field |
x86 uses a 3-bit register field. REX adds one additional bit.
Thus, registers become 4-bit values:
$\text{Register ID} = (\text{REX bit} \ll 3) + \text{3-bit field}$
| REX | 3-bit | 4-bit | Decimal | Register | Description |
|---|---|---|---|---|---|
| 0 | 000 | 0000 | 0 | RAX | Arithmetic / return value |
| 0 | 001 | 0001 | 1 | RCX | Loop counter |
| 0 | 010 | 0010 | 2 | RDX | Multiply/divide |
| 0 | 011 | 0011 | 3 | RBX | General purpose |
| 0 | 100 | 0100 | 4 | RSP | Stack pointer |
| 0 | 101 | 0101 | 5 | RBP | Frame pointer |
| 0 | 110 | 0110 | 6 | RSI | Source index |
| 0 | 111 | 0111 | 7 | RDI | Destination index |
| 1 | 000 | 1000 | 8 | R8 | Function arguments / temporary |
| 1 | 001 | 1001 | 9 | R9 | Function arguments / temporary |
| 1 | 010 | 1010 | 10 | R10 | Temporary register |
| 1 | 011 | 1011 | 11 | R11 | Scratch register |
| 1 | 100 | 1100 | 12 | R12 | Callee-saved register |
| 1 | 101 | 1101 | 13 | R13 | Base/index register |
| 1 | 110 | 1110 | 14 | R14 | Callee-saved register |
| 1 | 111 | 1111 | 15 | R15 | Callee-saved register |
REX = 1
3-bit = 010
$(1 \ll 3) + 2 = 10$
Result: R10
REX = 1
3-bit = 101
$(1 \ll 3) + 5 = 13$
Result: R13
REX extends multiple instruction fields:
| Field | Extended by |
|---|---|
| REG field | REX.R |
| R/M field | REX.B |
| SIB index | REX.X |
| Operand size | REX.W |
xxxxxxxxxxmov r10, rax
xxxxxxxxxx4C 89 D0
Binary:
xxxxxxxxxx01001100
Breakdown:
W = 1 → 64-bit operation
R = 1 → REG extended
X = 0
B = 0
Binary:
xxxxxxxxxx11010000
Split:
REG = 010
R/M = 000
REG becomes R10
R/M remains RAX
xxxxxxxxxxmov r10, rax
Arithmetic operations
Function return values
Loop counter
Shift operations
Multiplication/division support
General-purpose storage
Stack pointer (critical system register)
Stack frame base pointer
String and memory operations
Function arguments and compiler temporary registers
| Argument | Register |
|---|---|
| 1st | RDI |
| 2nd | RSI |
| 3rd | RDX |
| 4th | RCX |
| 5th | R8 |
| 6th | R9 |
The REX system does not change the original x86 encoding. It only adds one extra bit:
Old registers: 000–111 (RAX–RDI)
Extended registers: 1000–1111 (R8–R15)
x86-64 register encoding can be understood as:
Original 3-bit field defines base register
REX adds the missing most significant bit
So:
0xxx = legacy registers
1xxx = extended registers
x86-64 achieves register expansion without breaking compatibility by using a simple but powerful idea: a single prefix byte (REX) that extends existing 3-bit register fields into 4-bit addressing space, enabling 16 general-purpose registers while preserving the entire legacy x86 ecosystem.