The instruction format
An x86 instruction is 1 to 15 bytes long. Its length is not stored anywhere: it follows from the bytes themselves, read in order. That is why a disassembler must decode each instruction to find where the next one starts, and why the same bytes can mean different instructions when decoding starts at a different place. In order, an instruction has these parts, all but the opcode optional:
PrefixesLegacy prefixes: LOCK, REP, segment overrides, operand size, address size0–4 bytes, up to 14REXIn 64-bit mode: REX (40–4F) or APX’s REX2 (D5 and one byte)0–2 bytesVEXOr EVEX or XOP: a prefix that carries the map, the mandatory prefix, register bits and the vector length2–4 bytesOpcodeOne byte, after any escape bytes (0F, 0F 38, 0F 3A) in legacy code1–3 bytesModRMThe operands: a register, and a register or memory0–1 byteSIBScale, index and base for a memory operand0–1 byteDispThe displacement of a memory operand0, 1, 2, 4 or 8 bytesImmAn immediate value0, 1, 2, 4 or 8 bytes
All multi-byte values (displacements, immediates) are little-endian. The bytes on this page are written in hexadecimal; the disassembly beside them is the explorer’s disassembler’s own output, which matches llvm-objdump’s Intel syntax except where the notes at the end say. Branch targets assume the instruction is at address 0x1000. The opcodes themselves are in the opcode maps.
Legacy prefixes
The legacy prefixes fall into four groups. An instruction may have at most one from each group, in any order. Where there is more than one from a group, the disassembler takes the last one.
| Group | Byte | Name | What it does |
|---|---|---|---|
| 1 | F0 | LOCK | Makes a read-modify-write of memory atomic. Allowed only on ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG, CMPXCHG8B, CMPXCHG16B, DEC, INC, NEG, NOT, OR, SBB, SUB, XADD, XCHG and XOR with a memory destination; elsewhere #UD. |
| 1 | F2 | REPNE / REPNZ | Repeats CMPS or SCAS while not equal. On a near branch it is MPX’s BND; with LOCK or on XCHG it is XACQUIRE (HLE). Before a 0F opcode it is often a mandatory prefix: F2 0F 58 is addsd. |
| 1 | F3 | REP / REPE / REPZ | Repeats a string instruction. With LOCK, on XCHG or on a MOV to memory it is XRELEASE (HLE). As a mandatory prefix, F3 0F 58 is addss and F3 90 is pause. |
| 2 | 2E, 36, 3E, 26, 64, 65 | CS, SS, DS, ES, FS, GS | Segment override for the memory operand. In 64-bit mode CS, SS, DS and ES are ignored and only FS and GS (whose bases are set through MSRs) do anything. On Jcc, 2E and 3E were branch hints (not taken, taken) for the Pentium 4; on an indirect branch, 3E is CET’s NOTRACK. |
| 3 | 66 | Operand size | Switches between 16-bit and 32-bit operands (see Operand and address size). Before a 0F opcode it is often a mandatory prefix: 66 0F 58 is addpd. |
| 4 | 67 | Address size | Switches between 16-bit and 32-bit addresses, or in 64-bit mode between 64-bit and 32-bit. |
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
26 8B 07 | 16 | mov ax, word ptr es:[bx] | 26 is the ES override; 8B is MOV Gv, Ev; ModRM 07 is [bx]. |
66 B8 34 12 | 32 | mov ax, 0x1234 | 66 makes the operand 16 bits, so the immediate is two bytes. |
67 8B 07 | 32 | mov eax, dword ptr [bx] | 67 switches to 16-bit addressing, in which ModRM 07 is [bx]. |
F0 0F C1 03 | 32 | lock xadd dword ptr [ebx], eax | An atomic fetch-and-add. |
F3 A4 | 32 | rep movsb byte ptr es:[edi], byte ptr [esi] | REP on a string move. |
F2 AE | 32 | repne scasb al, byte ptr es:[edi] | REPNE on a scan. |
0F 58 C166 0F 58 C1F3 0F 58 C1F2 0F 58 C1 | 64 | addps xmm0, xmm1addpd xmm0, xmm1addss xmm0, xmm1addsd xmm0, xmm1 | The mandatory prefix picks the instruction: none, 66, F3 or F2. |
66 F2 0F 58 C1 | 64 | addsd xmm0, xmm1 | F2 takes precedence over 66 as the mandatory prefix. |
F2 E8 00 00 00 00 | 64 | bnd call 0x1006 | F2 on a call is BND. |
F2 F0 0F C1 03 | 64 | xacquire lock xadd dword ptr [rbx], eax | F2 with LOCK is XACQUIRE. |
F3 88 03 | 64 | xrelease mov byte ptr [rbx], al | F3 on a MOV to memory is XRELEASE. |
The 15-byte limit
No instruction may be longer than 15 bytes. Prefixes can be repeated, so a longer one
can be written, but the processor raises #GP when it reaches the 16th byte. The
disassembler shows such bytes as (bad), one byte long, as LLVM does.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
26 × 14, 90 | 64 | nop | Fourteen prefixes and an opcode: 15 bytes, the most allowed. |
26 × 15, 90 | 64 | (bad) | 16 bytes: too long. |
66 66 66 2E 0F 1F 84 00 00 00 00 00 | 64 | nop word ptr cs:[rax + rax] | A 12-byte NOP of the kind compilers pad code with: repeated 66 prefixes, a CS override, and 0F 1F /0 with a SIB byte and a disp32. |
REX
In 64-bit mode the bytes 40 to 4F are not INC and DEC but the
REX prefix, which AMD added with x86-64. Its low four bits extend the instruction:
| Bit | Name | What it does |
|---|---|---|
| 7–4 | – | 0100 |
| 3 | W | 1: a 64-bit operand size. It takes precedence over 66. |
| 2 | R | The fourth bit of ModRM.reg. |
| 1 | X | The fourth bit of SIB.index. |
| 0 | B | The fourth bit of ModRM.rm, of SIB.base, or of the register in the opcode’s low three bits. |
With R, X and B, sixteen general registers (and xmm0 to xmm15) can be named. Any REX
prefix, even 40 with no bits set, changes the byte registers: register
numbers 4 to 7 become SPL, BPL, SIL and DIL instead of AH, CH, DH and BH, which can then
not be used. REX must come straight before the opcode (or the 0F escape): a REX followed
by a legacy prefix is ignored, and only the last of several REX prefixes counts.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
48 89 C8 | 64 | mov rax, rcx | REX.W: 64-bit operands. ModRM C8: mod 11, reg 001 (rcx), rm 000 (rax). |
4C 89 C0 | 64 | mov rax, r8 | REX.W and REX.R: reg becomes 1000, r8. |
41 50 | 64 | push r8 | REX.B extends the register in the opcode, 50 + 0. |
42 8B 04 08 | 64 | mov eax, dword ptr [rax + r9] | REX.X extends SIB.index (001) to 1001, r9. |
88 F040 88 F0 | 64 | mov al, dhmov al, sil | Register 6 is DH without REX and SIL with any REX. |
48 66 89 C8 | 64 | mov ax, cx | The REX is not straight before the opcode, so it is ignored; 66 gives 16 bits. |
66 48 89 C8 | 64 | mov rax, rcx | REX.W takes precedence over 66. |
48 41 89 C8 | 64 | mov r8d, ecx | Only the last REX counts: 41 (B), not 48 (W). |
REX2 (APX)
Intel’s APX (Advanced Performance Extensions) doubles the general registers to 32,
R16 to R31. For legacy instructions it adds REX2, two bytes in 64-bit mode:
D5, which is AAD outside 64-bit mode and invalid in it, and a payload
byte:
| Bit | Name | What it does |
|---|---|---|
| 7 | M0 | The opcode map: 0 for the one-byte map, 1 for the 0F map, whose escape byte is then left out. |
| 6 | R4 | The fifth bit of ModRM.reg. |
| 5 | X4 | The fifth bit of SIB.index. |
| 4 | B4 | The fifth bit of ModRM.rm, SIB.base or the opcode register. |
| 3–0 | W, R, X, B | As in REX. |
REX2 cannot be used with a REX prefix, and not with the instructions in rows 4, 7 and E
of the one-byte map, row A except JMPABS, or rows 3 and 8 of the 0F map (WRMSR to
GETSEC and the escapes, and Jcc rel32); there it is #UD. With W = 1, PUSH and POP
(50 to 5F) become PUSHP and POPP, and A1 with W = 0
is JMPABS. The fifth bits only
apply to general registers.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
D5 10 8B C1 | 64 | mov eax, r17d | Payload 10: B4. ModRM C1: rm 001 becomes 10001, r17. |
D5 50 89 C8 | 64 | mov r16d, r17d | Payload 50: R4 and B4. reg 001 becomes 17, rm 000 becomes 16. |
D5 44 89 C8 | 64 | mov eax, r25d | Payload 44: R4 and R. reg 001 becomes 11001, r25. |
D5 18 89 C8 | 64 | mov r16, rcx | Payload 18: B4 and W. |
D5 C0 AF C1 | 64 | imul r16d, ecx | Payload C0: M0 (the 0F map, so AF is 0F AF) and R4. |
D5 08 50 | 64 | pushp rax | W = 1 on PUSH: the PPX hint. |
D5 00 A1 00 88 11 22 33 44 55 66 | 64 | jmpabs 0x6655443322118800 | A1 with W = 0: a jump to the 64-bit address that follows. |
D5 01 74 00 | 64 | (bad) | Jcc (row 7) cannot take REX2. |
40 D5 10 89 C8 | 64 | (bad) | REX followed by REX2. |
VEX
Intel’s AVX (2011) brought the VEX prefix, which packs into two or three bytes what
the legacy encoding spreads over a mandatory prefix, REX and escape bytes, and adds a
third register operand (vvvv) and the vector length (L). Several of its fields are
stored inverted (marked with a bar), so that in 32-bit code the byte after
C4 or C5 has both top bits set, which LES and LDS cannot
have: there, C4 or C5 is VEX only when the next byte is
C0 or above.
| Form | Byte 0 | Byte 1 | Byte 2 |
|---|---|---|---|
| Two-byte | C5 | R̄ v̄v̄v̄v̄ L pp | – |
| Three-byte | C4 | R̄ X̄ B̄ m-mmmm | W v̄v̄v̄v̄ L pp |
- R̄, X̄, B̄: REX.R, X and B, inverted; the two-byte form has only R. Outside 64-bit mode R̄ and X̄ are 1 (which is what puts the byte at C0 or above) and B̄ is ignored.
- m-mmmm: the opcode map. 1 is the 0F map, 2 is 0F 38, 3 is 0F 3A; 5 and 7 hold a few recent instructions (AMX-FP8, AMX-MOVRS and the MSR-IMM forms). The two-byte form always means map 1.
- W: REX.W for general-register operands, or an opcode bit; ignored by many instructions (WIG).
- v̄v̄v̄v̄: a register operand, inverted. Unused, it must be 1111. Outside 64-bit mode only eight registers exist, but the top bit must still be 1.
- L: the vector length, 0 for 128 bits (xmm) and 1 for 256 (ymm). Scalar instructions ignore it (LIG) or need 0 (LZ).
- pp: the mandatory prefix: 00 none, 01 66, 10 F3, 11 F2.
A 66, F2, F3, LOCK or REX prefix before VEX is #UD, and the disassembler shows the bytes
as (bad). Some four-operand instructions name a fourth register in the top
four bits of an immediate byte (is4); outside 64-bit mode its top bit is ignored.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
C5 F8 58 C1 | 64 | vaddps xmm0, xmm0, xmm1 | F8 = 1 1111 0 00: R̄ = 1, v̄ = 1111 (xmm0), L = 0, pp = none. Map 1, opcode 58. |
C5 F9 58 C1C5 FA 58 C1C5 FB 58 C1 | 64 | vaddpd xmm0, xmm0, xmm1vaddss xmm0, xmm0, xmm1vaddsd xmm0, xmm0, xmm1 | pp = 01, 10 and 11: 66, F3 and F2. |
C5 F4 58 C2 | 64 | vaddps ymm0, ymm1, ymm2 | F4 = 1 1110 1 00: v̄ = 1110 is register 1; L = 1 makes it 256 bits. |
C5 78 58 C1C5 B8 58 C1 | 64 | vaddps xmm8, xmm0, xmm1vaddps xmm0, xmm8, xmm1 | R̄ = 0 gives reg 1000; v̄ = 0111 gives register 8. |
C4 C1 78 58 C1 | 64 | vaddps xmm0, xmm0, xmm9 | Three-byte form: C1 = 1 1 0 00001: B̄ = 0, so rm 001 becomes 1001; map 1. |
C4 E2 79 18 00 | 64 | vbroadcastss xmm0, dword ptr [rax] | E2: map 2 (0F 38). 79 = 0 1111 0 01: W0, pp = 66. |
C4 E3 79 4A C2 30 | 64 | vblendvps xmm0, xmm0, xmm2, xmm3 | Map 3, opcode 4A; the immediate 30 names xmm3 in its top four bits (is4). |
C4 E2 70 F2 C3 | 64 | andn eax, ecx, ebx | BMI1 on general registers: v̄ = 1110 is ECX. |
C5 F8 58 C1 | 32 | vaddps xmm0, xmm0, xmm1 | In 32-bit code too, since F8 is above BF. |
C5 00 | 32 | lds eax, fword ptr [eax] | 00 is below C0, so C5 is LDS. |
C5 B8 58 C1 | 32 | (bad) | B8 is below C0, so this is LDS with ModRM B8, which needs a disp32 that is cut short here. |
66 C5 F8 58 C1 | 64 | (bad) | 66 before VEX. |
EVEX
AVX-512 (2016) brought EVEX, four bytes starting with 62, which was BOUND.
It reaches 32 vector registers (xmm, ymm or zmm 0 to 31), adds the opmask registers
k1 to k7 for masking, 512-bit vectors, broadcast, rounding control and a compressed
8-bit displacement. In 32-bit code, as with VEX, 62 is EVEX only when the
next byte is C0 or above.
| Byte | Bit 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|---|---|---|---|---|---|---|---|---|
| P0 | R̄ | X̄ | B̄ | R̄′ | B4 (APX; else 0) | mmm: the map | ||
| P1 | W | v̄v̄v̄v̄ | 1 (APX: X̄4) | pp | ||||
| P2 | z | L′L | b | V̄′ | aaa | |||
- R̄, X̄, B̄, W, v̄v̄v̄v̄, pp: as in VEX.
- R̄′ and V̄′: the fifth bits of ModRM.reg and of vvvv, inverted, for registers 16 to 31. For a vector register in ModRM.rm, X̄ is the fifth bit.
- mmm: the map. 1, 2 and 3 are the 0F, 0F 38 and 0F 3A maps, as in VEX; 5 and 6 hold AVX-512 FP16 and AVX10.2; 4 holds APX’s promoted legacy instructions.
- z: with a mask, 1 zeroes the masked-off elements ({z}), 0 leaves them as they were (merging).
- L′L: the vector length, 00 for 128 bits, 01 for 256 and 10 for 512;
11 is reserved, and the disassembler shows it as
(bad). - b: with a memory operand, broadcast; with register operands, rounding control or suppress-all-exceptions.
- aaa: the opmask register, k1 to k7; 000 means no masking.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
62 F1 7C 48 58 C2 | 64 | vaddps zmm0, zmm0, zmm2 | P0 F1: R̄X̄B̄R̄′ = 1111, map 1. P1 7C: W0, v̄ = 1111, pp none. P2 48: L′L = 10 (512 bits), V̄′ = 1, no mask. |
62 E1 7C 48 58 C2 | 64 | vaddps zmm16, zmm0, zmm2 | R̄′ = 0: reg 00000 becomes 10000. |
62 F1 7C 40 58 C2 | 64 | vaddps zmm0, zmm16, zmm2 | V̄′ = 0: vvvv 0000 becomes 10000. |
62 B1 7C 48 58 C2 | 64 | vaddps zmm0, zmm0, zmm18 | X̄ = 0: rm 010 becomes 10010 for a register. |
62 D1 7C 48 58 C262 71 7C 48 58 C2 | 64 | vaddps zmm0, zmm0, zmm10vaddps zmm8, zmm0, zmm2 | B̄ = 0 and R̄ = 0, as in VEX. |
62 F1 7C 68 58 C2 | 64 | (bad) | L′L = 11 is reserved. |
62 F1 7C 48 58 C2 | 32 | vaddps zmm0, zmm0, zmm2 | F1 is above BF, so 62 is EVEX in 32-bit code too. |
62 00 | 32 | bound eax, dword ptr [eax] | 00 is below C0, so 62 is BOUND. |
Masking
With aaa ≠ 0, only the elements whose bit is set in the mask register are written; the rest are kept, or with z = 1 set to zero. k0 cannot be a write mask, since aaa = 000 means none. Some instructions require a mask (gathers and scatters) and some cannot take zeroing (stores).
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
62 F1 7C 49 58 C2 | 64 | vaddps zmm0 {k1}, zmm0, zmm2 | P2 49: aaa = 001, merging. |
62 F1 7C 4B 58 C2 | 64 | vaddps zmm0 {k3}, zmm0, zmm2 | aaa = 011. |
62 F1 7C C9 58 C2 | 64 | vaddps zmm0 {k1} {z}, zmm0, zmm2 | P2 C9: z = 1, zeroing. |
Broadcast
With a memory operand and b = 1, one element is read and copied to every position of
the vector: {1to16} for 32-bit elements in 512 bits. The element size
follows W (or the instruction), and only instructions whose tuple type allows it can
broadcast.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
62 F1 7C 58 58 00 | 64 | vaddps zmm0, zmm0, dword ptr [rax]{1to16} | P2 58: b = 1, L′L = 10: one dword to sixteen. |
62 F1 FD 58 58 40 01 | 64 | vaddpd zmm0, zmm0, qword ptr [rax + 0x8]{1to8} | W1 and pp = 66: double precision, one qword to eight. |
The compressed displacement, disp8×N
With EVEX, an 8-bit displacement (ModRM.mod = 01) is multiplied by N, the size of the memory operand or of one element, so that one byte reaches further. N comes from the instruction’s tuple type, the vector length and broadcast: for a full-vector operand (FV) it is the vector size, 64 for 512 bits, or the element size with broadcast; for a scalar (T1S) the element size; and so on through the table of tuple types in volume 2 of Intel’s manual, in its section on the compressed displacement. A 32-bit displacement is never scaled.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
62 F1 7C 48 58 40 01 | 64 | vaddps zmm0, zmm0, zmmword ptr [rax + 0x40] | disp8 = 1, N = 64 (a full 512-bit vector): 0x40. |
62 F1 7C 58 58 40 01 | 64 | vaddps zmm0, zmm0, dword ptr [rax + 0x4]{1to16} | With broadcast N is one element, 4. |
62 F1 7E 08 10 40 01 | 64 | vmovss xmm0, dword ptr [rax + 0x4] | A scalar (T1S) of 4 bytes: N = 4. |
Rounding and suppress-all-exceptions
When both operands are registers, b = 1 means something else: for an instruction that rounds, L′L is no longer the length but the rounding mode, and the vector is 512 bits (or scalar); for one that only compares or converts exactly, b = 1 suppresses floating-point exceptions ({sae}). LLVM writes the mode as an extra operand.
| L′L | Mode |
|---|---|
| 00 | {rn-sae}: to nearest, ties to even |
| 01 | {rd-sae}: down, towards −∞ |
| 10 | {ru-sae}: up, towards +∞ |
| 11 | {rz-sae}: towards zero |
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
62 F1 7C 18 58 C2 | 64 | vaddps zmm0, zmm0, zmm2, {rn-sae} | P2 18: b = 1, L′L = 00. |
62 F1 7C 38 58 C2 | 64 | vaddps zmm0, zmm0, zmm2, {rd-sae} | L′L = 01. |
62 F1 7C 78 58 C2 | 64 | vaddps zmm0, zmm0, zmm2, {rz-sae} | L′L = 11, which would be reserved as a length. |
62 F1 7C 18 2E C1 | 64 | vucomiss xmm0, xmm1, {sae} | A compare: b = 1 is {sae}. |
APX’s EVEX fields
APX uses EVEX in two ways. It promotes legacy instructions into EVEX map 4, and some VEX instructions (BMI1, BMI2, CMPccXADD, the AMX tile loads and others) into EVEX maps 2 and 3, so that they can reach R16 to R31 and new behaviour. In these forms some fields change meaning:
- B4 (P0 bit 3) and X̄4 (P1 bit 2, inverted) are the fifth bits of a general register in ModRM.rm or SIB.base, and of SIB.index. R̄′ and V̄′ give the fifth bits of ModRM.reg and vvvv, as for vectors. B4 is stored as it is, not inverted.
- ND (P2 bit 4, b’s place): a new data destination. The result goes
to the register in vvvv and both sources are kept:
add rdx, rax, rcx. For a few instructions ND is part of the opcode instead (SETZUcc, IMULZU, PUSH2, POP2). - NF (P2 bit 2, in aaa): no flags. The instruction leaves EFLAGS
alone, shown as
{nf}. - z, L′L and aaa bits 1 and 0 must be 0, and in map 4 pp = 01 is the 66 operand-size prefix, unless the opcode takes it.
- CCMPscc and CTESTscc use P2 bits 3–0 for their condition and vvvv, not inverted, for the default flags.
- LOCK may come before a map 4 instruction, for the forms that take it.
An APX form with neither ND nor NF reads the same as the legacy instruction, so LLVM
writes {evex} before it. APX is for 64-bit mode only.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
62 F4 EC 18 01 C8 | 64 | add rdx, rax, rcx | Map 4 (P0 F4). P1 EC: W1, v̄ = 1101 (rdx). P2 18: ND = 1. Opcode 01 is ADD Ev, Gv. |
62 F4 FC 0C 01 C8 | 64 | {nf} add rax, rcx | P2 0C: NF = 1. |
62 F4 7C 1C 01 C8 | 64 | {nf} add eax, eax, ecx | P2 1C: ND and NF. |
62 FC FC 08 01 C8 | 64 | {evex} add r16, rcx | P0 FC: B4 = 1, so rm 000 becomes 10000. |
F0 62 F4 7C 08 01 03 | 64 | lock {evex} add dword ptr [rbx], eax | LOCK before a map 4 instruction. |
62 F4 7C 0C 38 C1 | 64 | ccmpl {dfv=of,sf,zf,cf} cl, al | Opcode 38 is CCMP. P2 0C: condition 1100, l. v̄ = 1111 read as is: all four default flags. |
62 F4 64 08 38 C1 | 64 | ccmps {dfv=of,sf} cl, al | P1 64: vvvv = 1100, OF and SF. P2 08: condition 1000, s. |
62 F2 7C 08 F2 C362 F2 7C 0C F2 C362 FA 7C 08 F2 C3 | 64 | andn eax, eax, ebx{nf} andn eax, eax, ebxandn eax, eax, r19d | BMI1’s ANDN promoted into EVEX map 2, without {evex}; then with NF; then with B4. |
62 F4 7C 08 01 C8 | 32 | (bad) | Map 4 outside 64-bit mode. |
XOP and 3DNow!
AMD’s XOP prefix (Bulldozer, 2011) is laid out like three-byte VEX, but starts with
8F, which is POP r/m. It is told apart by its map field, 8, 9 or 10: POP
needs ModRM.reg = 000, so its ModRM byte’s low five bits are always below 8. Map 8 holds
instructions with an immediate byte, map 9 those without, and map 10 those with a
32-bit immediate; AMD’s TBM and LWP use maps 9 and 10.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
8F E8 78 A2 C2 30 | 64 | vpcmov xmm0, xmm0, xmm2, xmm3 | E8: R̄X̄B̄ = 111, map 8. 78: W0, v̄ = 1111, L = 0. The fourth register is in the immediate. |
8F E8 F8 A2 C2 30 | 64 | vpcmov xmm0, xmm0, xmm3, xmm2 | W1 swaps the last two sources. |
8F E8 78 CC C1 00 | 64 | vpcomltb xmm0, xmm0, xmm1 | VPCOMB with predicate 0, shown by its predicate name. |
8F E9 78 01 C9 | 64 | blcfill eax, ecx | Map 9, TBM; the destination is in vvvv. |
8F C0 | 32 | pop eax | C0’s low five bits are 0: POP. |
AMD’s 3DNow! (K6-2, 1998) used yet another scheme: 0F 0F, the ModRM byte
and any SIB and displacement, and then an immediate-like byte that is the real opcode.
0F 0F C1 9E is pfadd mm0, mm1 and 0F 0F C1 B4 is
pfmul mm0, mm1. See the 3DNow!
page.
The opcode
In legacy code the opcode is one byte from the one-byte map, or 0F and a
byte from the two-byte map, or 0F 38 or 0F 3A and a byte from a
three-byte map. VEX, EVEX, REX2 and XOP name the map in their own fields and leave the
escape bytes out. Within a map, an opcode may also depend on the mandatory prefix, on
ModRM.reg (an opcode extension, written /0 to /7), on whether
ModRM.mod is 11, on the whole ModRM byte, on W or on L. Some one-byte opcodes hold a
register in their low three bits (50+r, B8+r). The maps are on
the Opcode maps page.
ModRM
Most instructions with operands have a ModRM byte after the opcode:
| Bits | Field | Meaning |
|---|---|---|
| 7–6 | mod | 11: rm is a register. 00, 01, 10: rm is memory, with no displacement, an 8-bit one or a 32-bit one (16-bit in 16-bit addressing). |
| 5–3 | reg | A register operand, or an opcode extension (/0 to /7). |
| 2–0 | rm | A register, or the base of the memory operand. |
With 32-bit and 64-bit addressing, two rm values are special:
| rm | mod 00 | mod 01 | mod 10 | mod 11 |
|---|---|---|---|---|
| 000–011, 110, 111 | [reg] | [reg + disp8] | [reg + disp32] | reg |
| 100 | a SIB byte follows | SIB + disp8 | SIB + disp32 | reg (ESP, RSP …) |
| 101 | disp32 alone; in 64-bit mode RIP + disp32 | [EBP + disp8] | [EBP + disp32] | reg (EBP, RBP …) |
The register numbers are 0 eax, 1 ecx, 2 edx, 3 ebx, 4 esp, 5 ebp, 6 esi and 7 edi (and their 8-, 16- and 64-bit forms), extended to 8–15 by REX and 16–31 by REX2 or EVEX. The special cases go by the low three bits, so R12 needs a SIB byte like RSP, and R13 with mod 00 means disp32 like RBP; their plain forms take a SIB byte or a zero disp8.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
8B C1 | 32 | mov eax, ecx | ModRM C1: mod 11, reg 000, rm 001. |
8B 45 FC | 32 | mov eax, dword ptr [ebp - 0x4] | mod 01, rm 101: EBP and disp8 FC (−4), a local variable. |
8B 05 78 56 34 12 | 32 | mov eax, dword ptr [0x12345678] | mod 00, rm 101: an absolute address. |
41 8B 45 00 | 64 | mov eax, dword ptr [r13] | R13 needs mod 01 and a zero disp8. |
SIB
A SIB byte follows ModRM when rm is 100 and mod is not 11. The address is base + index × scale + displacement.
| Bits | Field | Meaning |
|---|---|---|
| 7–6 | scale | 00 × 1, 01 × 2, 10 × 4, 11 × 8. |
| 5–3 | index | The index register. 100 (with REX.X = 0) means no index, since ESP cannot be one. |
| 2–0 | base | The base register. 101 with mod 00 means no base and a disp32. |
An index of 100 with a scale above 1, or where a SIB byte was not needed, still means no
index; LLVM writes it as eiz or riz, GNU’s name for a zero index
register, so that the encoding can be seen, and so does the disassembler. Gathers and
scatters use a vector register as the index (VSIB).
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
8B 04 24 | 32 | mov eax, dword ptr [esp] | SIB 24: no index, base ESP. |
8B 44 24 08 | 32 | mov eax, dword ptr [esp + 0x8] | The same with disp8 8, a stack argument. |
8B 84 C8 00 01 00 00 | 32 | mov eax, dword ptr [eax + 8*ecx + 0x100] | SIB C8: scale 8, index ECX, base EAX; disp32 0x100. |
8B 04 8D 00 10 00 00 | 32 | mov eax, dword ptr [4*ecx + 0x1000] | SIB 8D: base 101 with mod 00, so no base, and a disp32: an array lookup. |
8B 04 60 | 32 | mov eax, dword ptr [eax + 2*eiz] | SIB 60: scale 2 but index 100, no index. |
4D 8B 0C 24 | 64 | mov r9, qword ptr [r12] | R12 as a base needs a SIB byte. |
8B 04 25 78 56 34 12 | 64 | mov eax, dword ptr [0x12345678] | In 64-bit mode an absolute disp32 needs a SIB byte, since ModRM rm 101 is RIP-relative. |
16-bit addressing
With a 16-bit address size (16-bit code, or 67 in 32-bit code) there is no SIB byte, and rm picks one of eight base and index pairs. The forms with BP use SS by default; the others DS.
| rm | mod 00 | mod 01 | mod 10 |
|---|---|---|---|
| 000 | [bx + si] | [bx + si + disp8] | [bx + si + disp16] |
| 001 | [bx + di] | [bx + di + disp8] | [bx + di + disp16] |
| 010 | [bp + si] | [bp + si + disp8] | [bp + si + disp16] |
| 011 | [bp + di] | [bp + di + disp8] | [bp + di + disp16] |
| 100 | [si] | [si + disp8] | [si + disp16] |
| 101 | [di] | [di + disp8] | [di + disp16] |
| 110 | disp16 alone | [bp + disp8] | [bp + disp16] |
| 111 | [bx] | [bx + disp8] | [bx + disp16] |
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
8B 00 | 16 | mov ax, word ptr [bx + si] | rm 000. |
8B 07 | 16 | mov ax, word ptr [bx] | rm 111. |
8B 40 10 | 16 | mov ax, word ptr [bx + si + 0x10] | mod 01: disp8 0x10. |
8B 42 08 | 16 | mov ax, word ptr [bp + si + 0x8] | rm 010, in SS. |
8B 46 FE | 16 | mov ax, word ptr [bp - 0x2] | mod 01, rm 110: [bp] needs a displacement. |
8B 06 34 12 | 16 | mov ax, word ptr [0x1234] | mod 00, rm 110: a disp16 alone. |
RIP-relative addressing
In 64-bit mode, ModRM mod 00 with rm 101 no longer means an absolute disp32: it means RIP + disp32, counted from the end of the instruction. Code can then reach its data wherever it is loaded, which is how almost all 64-bit code addresses globals, constants and import table slots. With a 67 prefix it is EIP-relative. The explorer works out the address each one refers to, and names it when it is a known symbol such as an imported function.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
8B 05 78 56 34 12 | 64 | mov eax, dword ptr [rip + 0x12345678] | The same bytes as the absolute load in 32-bit code. At 0x1000, six bytes long: it reads 0x1006 + 0x12345678 = 0x1234667E. |
48 8D 05 F9 FF FF FF | 64 | lea rax, [rip - 0x7] | disp32 −7 from the end of this seven-byte instruction: its own address, 0x1000. |
FF 15 10 20 00 00 | 64 | call qword ptr [rip + 0x2010] | A call through the slot at 0x1006 + 0x2010 = 0x3016, typically an import address table entry. |
67 8B 05 78 56 34 12 | 64 | mov eax, dword ptr [eip + 0x12345678] | With 67: 32-bit address size, EIP-relative. |
Displacements and immediates
A displacement follows ModRM and SIB: 1 byte (mod 01, sign-extended),
or 4 bytes (mod 10, and the disp32-only forms), or 2 bytes in 16-bit addressing. With
EVEX, a 1-byte displacement is scaled (disp8×N). The accumulator
moves A0 to A3 instead hold a memory offset (moffs) of the
address size, which is 8 bytes in 64-bit mode.
An immediate comes last. Its size is in the opcode’s operand notation:
a byte (ib), a word (iw), or the operand size limited to 32 bits
(iz: 2 or 4 bytes, sign-extended to 64 bits with REX.W). Only
B8+r with REX.W takes a full 8-byte immediate. ENTER takes a word and a
byte, and the far JMP and CALL a 4- or 6-byte far pointer. A byte immediate to an
arithmetic instruction (83) is sign-extended.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
81 C3 78 56 34 12 | 32 | add ebx, 0x12345678 | Group 1 /0 with a 4-byte immediate. |
83 C3 FF | 32 | add ebx, -0x1 | The same with a sign-extended byte. |
B8 78 56 34 12 | 64 | mov eax, 0x12345678 | B8 + 0 with a 4-byte immediate. |
48 C7 C0 FF FF FF FF | 64 | mov rax, -0x1 | C7 /0 with REX.W: a 4-byte immediate sign-extended to 64 bits. |
48 B8 88 77 66 55 44 33 22 11 | 64 | movabs rax, 0x1122334455667788 | B8 + 0 with REX.W: an 8-byte immediate. |
A1 88 77 66 55 44 33 22 11 | 64 | movabs eax, dword ptr [0x1122334455667788] | moffs: an 8-byte address in 64-bit mode. |
67 A1 78 56 34 12 | 64 | mov eax, dword ptr [0x12345678] | With 67, a 4-byte address. |
C8 10 00 01 | 32 | enter 0x10, 0x1 | A word and a byte. |
EA 00 01 00 F0 | 16 | ljmp 0xf000:0x100 | A far pointer: the offset, then the selector. |
E8 00 01 00 00 | 64 | call 0x1105 | A 4-byte relative displacement, from the end of the instruction: 0x1005 + 0x100. |
74 FE | 64 | je 0x1000 | A 1-byte displacement of −2: a jump to itself. |
Operand and address size
The code segment says whether code is 16-bit, 32-bit or 64-bit, and that gives the
default operand and address sizes. Prefixes change them for one instruction. Byte
operands are not a size setting: they have opcodes of their own (the even opcode of a
pair, such as 88 beside 89).
| Code | Operand size | With 66 | With REX.W | Address size | With 67 |
|---|---|---|---|---|---|
| 16-bit | 16 | 32 | – | 16 | 32 |
| 32-bit | 32 | 16 | – | 32 | 16 |
| 64-bit | 32 | 16 | 64 (over 66) | 64 | 32 |
In 64-bit mode some instructions are 64-bit by default, and a 66 prefix gives 16 bits (there is no 32-bit form): PUSH, POP, PUSHF, POPF, LEAVE, ENTER and the near RET. The near branches, relative and indirect (JMP, CALL, Jcc, LOOP), always use 64 bits on Intel’s processors. The string instructions, LOOP and JrCXZ take their count and pointer registers by the address size.
| Bytes | Mode | Disassembly | How it reads |
|---|---|---|---|
89 C8 | 16 | mov ax, cx | The default in 16-bit code. |
66 89 C8 | 16 | mov eax, ecx | 66 in 16-bit code gives 32 bits. |
66 67 8B 00 | 16 | mov eax, dword ptr [eax] | 66 and 67 together: 32-bit operand and address. |
89 C8 | 64 | mov eax, ecx | The default in 64-bit code is 32 bits. |
66 89 C8 | 64 | mov ax, cx | 66: 16 bits. |
5066 50 | 64 | push raxpush ax | PUSH is 64-bit by default; 66 gives 16 bits. |
66 50 | 32 | push ax | In 32-bit code 66 gives 16 bits as usual. |
67 8B 00 | 64 | mov eax, dword ptr [eax] | 67: 32-bit address. |
66 E8 00 01 00 00 | 64 | call 0x1106 | 66 on a near call in 64-bit mode is ignored, as on Intel processors (see below). |
66 E8 00 01 | 32 | call 0x1104 | In 32-bit code 66 gives a 16-bit displacement. |
Where the disassembler differs from LLVM
The disassembler’s text matches llvm-objdump’s Intel syntax, except where LLVM is wrong about what a processor does or loses information. There it follows Intel’s manual, or AMD’s for AMD-only instructions:
- 66 on near branches in 64-bit mode is ignored, as Intel’s processors ignore it. AMD’s honour it, and LLVM decodes it AMD’s way.
- 16-bit code: 66 is taken as a mandatory prefix there too, as
processors take it (
66 0F 58isaddpdin any mode); LLVM does not. - F2 on Jcc rel32 is shown as BND (MPX), which LLVM loses.
- Display: a disp16 alone, a 64-bit moffs and a far selector are shown unsigned; a disp32 alone is shown signed.
- is4 registers (imm8 bits 7–4) outside 64-bit mode ignore bit 7, as binutils does.
- MOV to and from control and debug registers ignores ModRM.mod, as
processors do; a legacy prefix before VEX, EVEX or XOP, and a reserved EVEX L′L, are
shown as
(bad), since they raise #UD.
Links
Reference
- Intel 64 and IA-32 Architectures Software Developer’s Manuals – volume 2, chapter 2, describes the instruction format, VEX and EVEX; appendix A has the opcode maps
- AMD64 Architecture Programmer’s Manual, Volume 3 – AMD’s chapter 1 on the instruction encoding, with REX, VEX and XOP, and its opcode maps
- Intel Advanced Performance Extensions (Intel APX) – Intel’s introduction to APX, with a link to its architecture specification, which defines REX2 and the EVEX extensions
- x86 and amd64 instruction reference – Félix Cloutier’s web copy of the instruction pages of Intel’s manual