How do the x86_64 register names %rax, %eax, %ax, %al relate to each other?
They are nested views of the same physical 64-bit register: %rax is all 64 bits, %eax the low 32, %ax the low 16, and %al the low 8 — so the size suffix on an instruction often shows up as a different register name.
* %rax ⊃ %eax ⊃ %ax ⊃ %al are nested views of one physical register; writing %eax zeros the upper 32 bits, %ax/%al do not. *
A single 64-bit general-purpose register can be addressed at four widths, and the name tells you which:
| Width | Bits | Example name |
|---|---|---|
| 64-bit (quad) | 0-63 | %rax |
| 32-bit (long) | 0-31 | %eax |
| 16-bit (word) | 0-15 | %ax |
| 8-bit (byte) | 0-7 | %al |
This is why a card might mention "the result is in %eax" and another "in %rax" — they're the same register, just looked at 32 vs 64 bits wide. The numbered registers follow the same idea with a suffix: %r8 / %r8d (32) / %r8w (16) / %r8b (8).
The crucial x86_64 quirk: writing to a 32-bit name (%eax) automatically zeros the upper 32 bits of the full register. Writing to %ax or %al does not — those leave the higher bytes untouched. This is exactly why xor %eax, %eax clears all of %rax, and why the compiler prefers 32-bit operations when it wants a clean zero-extended value.
Reading tip: the operand width in disassembly tells you the C type — a 32-bit register (%eax) usually means an int, a 64-bit one (%rax) a long or a pointer.
Go deeper: