Instructions
x86-64MOVZX / MOVSX / MOVSXD
Zero-extending and sign-extending moves that widen a smaller source operand into a larger destination — essential for understanding type promotions in decompiler output.
MOVZX (Move with Zero-Extension) and MOVSX (Move with Sign-Extension) copy
a narrower source into a wider destination, filling the upper bits with zeros or
with copies of the source's sign bit respectively. Neither modifies EFLAGS.
Syntax
movzx eax, bl ; eax = zero_extend(BL) → upper 3 bytes cleared
movzx eax, word [rdi] ; eax = zero_extend(u16 from memory)
movzx rax, al ; rax = zero_extend(AL) → zero-extends to 64 bits
movsx eax, bl ; eax = sign_extend(BL) → 0xFF if BL=0xFF (-1 signed)
movsx rax, eax ; rax = sign_extend(EAX) → same as MOVSXD
movsxd rax, edi ; rax = sign_extend(32-bit EDI) → 64-bitZero-extend vs sign-extend
// Source C
uint8_t u = 0xC0; // 192
int8_t s = 0xC0; // -64
// Assembly for widening to int
movzx eax, al // eax = 0x000000C0 = 192 (unsigned)
movsx eax, al // eax = 0xFFFFFFC0 = -64 (signed)MOVSXD
MOVSXD sign-extends a 32-bit source into a 64-bit destination — the most
common form is movsxd rax, eax (canonicalise a 32-bit result to 64-bit
signed). Note: mov eax, eax zero-extends, while movsxd rax, eax
sign-extends.
Reverse-engineering notes
- The presence of
movsxtells you the compiler treats the source as a signed type;movzxmeans unsigned. This directly informs variable type recovery in decompilers. movzx eax, byte [rdi + rcx]is the canonical array byte-read pattern.- On x86-64, any 32-bit write implicitly zero-extends to 64 bits, so
movzx eax, alandmov eax, eax(after setting AL) are equivalent — decompilers sometimes emit the latter. movsxdis common when a 32-bit loop index is used as a 64-bit pointer offset:movsxd rcx, ecxthenmov [rbx + rcx*8], rax.