x86 architecture
opcode encoding




 
upper case letters
 
DREX MVEX
EVEX
VEX mod R/M  
 
 
dst kkk imm.ssss_s' v'_vvvv reg r/m r | m
            Mem mod != 11
      B G E R GPR
        P Q (PR) N (PR) MMX
VD   L H V W (VR) U (VR) vector
      vT rT   mT tile
  {K}   vK rK   mK mask
        rB   mB bounds
    Sreg   ST(i) x87
Address Offset Creg    
X = [DS:rSI] Y = [ES:rDI] Dreg Flags
Imm Jmp Treg only Z is left

 
lower case letters
 
1 2 4 8 16 32 64  
byte word dword qword oword yword zword  
  x = oword or yword   [o,y]
  upper = yword or zword [y,z]
  normal = oword or yword or zword [o,y,z]
  half = qword or oword or yword   [o.q,o,y]
  fourth = dword or qword or oword   o.[d,q,o]
  eighth = word or dword or qword   o.[w,d,q]
only c, g, m,
i, j, k, l, and
r, s are left
var-size = word or dword or qword  
zero-ext = word or dword or dword  
  y = dword or qword   p = w : [z|v|y] a = z : z t = {eh}

The overlap between the integer z and y and the vector y and z could be eliminated.
This can be achieved by renaming {v,z,y} to {i,j,k} or to {int,short,long} or to {i,r,s}.

However, each of these combinations is -- in its own way -- challenging to memorize.
And introducing lower and upper on the integer side would conflict with the vector side.

That said, this cleanup does not seem to be worthwhile.


On the vector side, oword could be renamed to xword, to better match yword and zword.
This would then require that xword be renamed, e.g. to lower, which would match upper.

However, the lower-case letter l is hard to visually distinguish from the upper-case letter I.
Perhaps c could be used instead of l, providing a mental reference to XY Chromosomes?

That said, this cleanup does not seem to be worthwhile.


 
colors and annotations
 
  reserved internal normal special  
reserved internal normal x86-64
reserved internal normal APX
inverted bits are stored inverted
          ...#mod mod can be 0...3
          ...#reg reg can be 0...7
          ...#r/m r/m can be 0...7
          ...v only VEX-encoded form exists
          ...I64 invalid in PM64
          ...D64 defaults to O64 in PM64; 66h results in O16 (implicit RSP references)
          ...Df64 defaults to O64 in PM64; 66h results in O16 in AMD64 but is ignored in EM64T (near branches)
          ...Dv64 defaults to O64 in PM64; 66h results in #UD due to VEX encoding (near branches with masks)
          ...F64 defaults to O64 in PM64; 66h is ignored in AMD64 and EM64T (GDTR/IDTR and CRx/DRx/TRx)
          ...F64 defaults to O64 in PM64; 66h is ignored due to REX2.W1 (PUSHP/POPP)
          ...F64 defaults to O64 in PM64; 66h is impossible due to EVEX.pp=00b (PUSH2(P)/POP2(P))
          ...+n one register explicitly specified, and another n consecutive registers implied
          ... reg op must be distinct from other reg op(s) (VSIB, AMX DP/CPLX/MUL, A512FP16 ADDC/MULC dst)
          ...scc EVEX.v'aaa = source condition code (CCMPscc and CTESTscc) (cc -- with True and False instead of Parity and No Parity)
          ...,dfv EVEX.vvvv = default flag value OSZC (CCMPscc and CTESTscc) (set {OF,SF,ZF,CF} to OSZC, as well as PF=C and AF=0)
  {NF} ... EVEX.NF controls status flag update suppression { ANDN, BLSR, BLSMSK, BLSI, BZHI, BEXTR }, { CFCMOVcc (Bv,)Ev,Gv }, and
{ INC/DEC, NEG, ADD/SUB, MUL/DIV/IMUL/IDIV, AND/OR/XOR, SAL/SAR/SHL/SHR, ROL/ROR, SHLD/SHRD, LZCNT/TZCNT/POPCNT }
  {ND} ... EVEX.ND controls NDD new data destination register Bq (with new zero-upper behavior instead of old preserve-upper behavior)
{ INC/DEC, NOT/NEG, ADD/SUB/ADC/SBB, AND/OR/XOR, SAL/SAR/SHL/SHR, RCL/RCR, ROL/ROR, SHLD/SHRD, ADCX/ADOX, (CF)CMOVcc, IMUL @ AFh }
  {ZU} ... EVEX.ND controls existing destination register to widen it (with new zero-upper behavior instead of old preserve-upper behavior)
{ SETcc Eb with mod=11b (i.e. SET Rb becomes SET Rq, whereas SET Mb remains SET Mb), IMUL @ 69h/6Bh (i.e. IMUL Gv,Ev,Ib/Iz becomes IMUL Gq,Ev,Ib/Iz }



 
instruction encodings
 
 
Fundamentally x86 operands are little-endian and of {transform} ( op {hint} ) {mask} form, arranged in dst,src[,...] order.
 
 
L1OM = {sss,ccccc} ( op {nt} ) {kkk}
 
 
K1OM = {sss} ( op {eh} ) {kkk}
 
 
1
 
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
1 byte opcodes and 2 byte opcodes
instruction prefix(es) #1 opcode
byte(s)
mod
R/M
byte
16-bit
32-bit
SIB
byte
displacement immediate #2, #3
P1 P2 P3 P4 O2 O1 D1 D2 D3 D4 I1 I2 I3 I4
SEG, REP, LOCK, 66h, 67h 0Fh xxh byte/word/dword byte/word/dword
3 byte opcodes, including DREX
instruction prefix(es) opcode
bytes
mod
R/M
byte
16-bit
32-bit
SIB
byte
displacement imm  
P1 P2 P3 P4 O2 O1 O3 D1 D2 D3 D4 I1
SEG, REP, LOCK, 66h, 67h 0Fh 38h xxh byte/word/dword  
3Ah byte
7Ah xxh  
7Bh byte
VEX2 (C5h), VEX3 (C4h), and XOP (8Fh)
instruction prefix(es) #4 opcode
byte
mod
R/M
byte
16-bit
32-bit
SIB
byte
displacement imm  
P1 P2 P3 P4 P5 O1 D1 D2 D3 D4 I1
  SEG, 67h C5h VEX xxh byte/word/dword byte
SEG, 67h C4h VEX1 VEX2 xxh
SEG, 67h 8Fh XOP1 XOP2 xxh byte/word/dword byte
byte/word/dword #1
L1OM misc (62h) and L1OM vector (D6h)
instruction prefix(es) opcode
byte
mod
R/M
byte
16-bit
32-bit
displacement and immediate
P1 P2 P3 P4 P5 P6 P7 O1
  SEG, REP, LOCK, 66h, 67h 62h XBRW
and
oooo
I1 I2 I1 I1  
word byte byte
SIB
byte
D1 D2 D3 D4  
byte/word/dword
SEG, REP, LOCK, 66h, 67h D6h NT, sss,
and
R'R B'B
v or c
and
kkk
xxh D1 D2 D3 D4 I1 I2
byte/word/dword word
MVEX (62h) and EVEX (62h)
instruction prefix(es) #4 opcode
byte
mod
R/M
byte
16-bit
32-bit
SIB
byte
displacement imm  
P1 P2 P3 P4 P5 P6 O1 D1 D2 D3 D4 I1
SEG, 67h 62h MVEX1 MVEX2 MVEX3 xxh byte/word/dword byte
EVEX1 EVEX2 EVEX3
DREX
instruction prefix(es) #5 opcode
bytes
mod
R/M
byte
16-bit
32-bit
SIB
byte
DREX
byte
displacement imm  
P1 P2 P3 P4 O2 O1 O3 D1 D2 D3 D4 I1
SEG, REP, LOCK, 66h, 67h 0Fh 24h xxh byte/word/dword  
25h byte
notes descriptions
#1 In some cases it is possible to encode valid instructions that exceed the traditional 15-byte length limit. For example:

  ; 16-bit mode
  F2 F0 36 66 67 81 84 24 disp32 imm32 = xacquire lock add [ss:esp*1+disp32],imm32
  F3 F0 36 66 67 81 84 24 disp32 imm32 = xrelease lock add [ss:esp*1+disp32],imm32
  
  ; 16-bit mode
  36 67 8F EA 78 12 84 24 disp32 imm32 = lwpins eax,[ss:esp*1+disp32],imm32
  36 67 8F EA 78 12 8C 24 disp32 imm32 = lwpval eax,[ss:esp*1+disp32],imm32
  36 67 8F EA 78 10 84 24 disp32 imm32 =  bextr eax,[ss:esp*1+disp32],imm32
  
  ; 64-bit mode
  64 67 8F EA F8 12 84 18 disp32 imm32 = lwpins rax,[fs:eax+ebx+disp32],imm32
  64 67 8F EA F8 12 8C 18 disp32 imm32 = lwpval rax,[fs:eax+ebx+disp32],imm32
  64 67 8F EA F8 10 84 18 disp32 imm32 =  bextr rax,[fs:eax+ebx+disp32],imm32

It is up to the user to avoid these cases (and the resulting #GP exception).
#2 Most 3DNow! instructions use the immediate byte as a third opcode byte.
#3 Some SSE/SSE2 instructions use the immediate byte as a condition code.
#4 The use of a REPE, REPNE, 66h, or REX prefix will result in a #UD exception.
#5 The use of a REX prefix will result in a #UD exception. The DREX byte is used instead.

 
byte encodings
 
 
type
 
7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0   7 6 5 4 3 2 1 0
mod R/M
and SIB
 
mod
 
reg r/m   scale index base        
 
REX
 
0100b = 4xh W R X B   the REX prefix must immediately precede the opcode byte(s)    
 
DREX
 
D dst (VD) O
C
0
R X B    OC0=0 for reg,r/m
 OC0=1 for r/m,reg
outside PM64, DREX.[DRXB]
are silently ignored if set to 1
   
L1OM
(misc)
 
0110_0010b = 62h
 
  X B R W oooo        
L1OM
(vector)
 
1101_0110b = D6h
 
  N
T
sss R' R B'
X
B   vvvvv
ccccc
kkk    
 
VEX2
 
1100_0101b = C5h   R vvvv L pp   mmmmm = 00001b
is implied for VEX2
   
 
VEX3
 
1100_0100b = C4h   R X B mmmmm   W vvvv L pp    
 
XOP
 
1000_1111b = 8Fh   R X B mmmmm   W vvvv L pp    
 
MVEX
 
0110_0010b = 62h   R X B R' mmmm   W vvvv 0 pp   E sss v' kkk
 
EVEX
 
0110_0010b = 62h   R X B R' 0 mmm   W vvvv 1
U
pp   z LL
RC
b v' aaa
 
REX2
 
1101_1010b = D5h   m R' X' B' W R X B   the REX2 prefix must immediately precede the opcode byte(s)
 
EVEX
 
0110_0010b = 62h   R X B R' B' mmm   W vvvv  U  pp   z LL
RC
b v' aaa
X'
 
EVEX
MAP4
0110_0010b = 62h   R X B R' B' 1 0 0   W vvvv X' pp   0 LL N
D
v' N
F
0 0
 
EVEX
scc / dfv
0110_0010b = 62h   R X B R' B' 1 0 0   W dfv
O
F
dfv
S
F
dfv
Z
F
dfv
C
F
X' pp   0 LL 0 scc
C
3
scc
C
2
scc
C
1
scc
C
0
fields descriptions
inverted bits are stored inverted
W 0 = default operand size
1 = 64-bit operand size
field 4 3 2   1   0 register type register use
REG R' R reg GPR or vector src or dst
VVV v' v vvv GPR or vector src or dst
R/M B' B r/m GPR src or dst
R/M X B r/m vector src or dst
BASE B' B r/m GPR memory reference
INDEX X' X index GPR memory reference
INDEX v' X index vector VSIB memory ref.
note AVX512 predates APX. Therefore X and v' are used instead of B' and X'.
R' and R mod R/M byte reg field extension
B mod R/M byte r/m field extension
SIB byte base field extension
opcode byte reg field extension
X SIB byte index field extension
also:
mod R/M byte r/m field extension (SIB-less MVEX/EVEX)
v' VEX prefix vvvv field extension
also:
SIB byte index field extension (VSIB with MVEX/EVEX)
B' mod R/M byte r/m field extension
SIB byte base field extension
opcode byte reg field extension
X' SIB byte index field extension
m 00000b (1-byte map MAP0), 00001b (2-byte map MAP1), 00010b (0Fh,38h MAP2), 00011b (0Fh,3Ah MAP3)
00100b (MAP4 incl. groups), 00101b (2-byte map MAP5), 00110b (0Fh,38h MAP6), 00111b (0Fh,3Ah MAP7)

01000b (XOP 8 with imm), 01001b (XOP 9 without imm), 01010b (XOP A with imm)
pp 00b (none), 01b (66h), 10b (F3h), 11b (F2h)
LL or RC 00b (128-bit), 01b (256-bit), 10b (512-bit), 11b (reserved) or 00b (RN), 01b (RD), 10b (RU), 11b (RZ)
U and X' first, the bit indicated 0=MVEX (aka K1OM) versus 1=EVEX (aka AVX512) (swizzling replaced by vector length) (eviction hint replaced by zeroing)
then, the bit indicated 0=512-bit (AVX512) versus 1=256-bit (AVX10.2) for {er} and {sae} variants (mod=11b && b=1) (leading bold !!)
now, the bit also serves (with inverted polarity) as X' together with X, to support the full 32 GPRs (mod<>11b) (and so MVEX is gone)



main page

© 1996-2024 by Christian Ludloff. All rights reserved. Use at your own risk.