Intel x86 Assembly Language & Microarchitecture 64-bit registers


AMD is a processor manufacturer that had licensed the design of the 80386 from Intel to produce compatible - but competing - versions. They made internal changes to the design to improve throughput or other enhancements to the design, while still being able to execute the same programs.

To one-up Intel, they came up with 64-bit extensions to the Intel 32-bit design and produced the first 64-bit chip that could still run 32-bit x86 code. Intel ended up following AMD's design in their versions of the 64-bit architecture.

The 64-bit design made a number of changes to the register set, while still being backward compatible:

  • The existing general-purpose registers were extended to 64 bits, and named with an R prefix: RAX, RBX, RCX, RDX, RSI, RDI, RBP, and RSP.

    Again, the bottom halves of these registers were the same E-prefix registers as before, and the top halves couldn't be independently accessed.

  • 8 more 64-bit registers were added, and not named but merely numbered: R8, R9, R10, R11, R12, R13, R14, and R15.
    • The 32-bit low half of these registers are R8D through R15D (D for DWORD as usual).
    • The lowest 16 bits of these registers could be accessed by suffixing a W to the register name: R8W through R15W.
  • The lowest 8 bits of all 16 registers could now be accessed:
    • The traditional AL, BL, CL, and DL;
    • The low bytes of the (traditionally) pointer registers: SIL, DIL, BPL, and SPL;
    • And the low bytes of the 8 new registers: R8B through R15B.
    • However, AH, BH, CH, and DH are inaccessible in instructions that use a REX prefix (for 64bit operand size, or to access R8-R15, or to access SIL, DIL, BPL, or SPL). With a REX prefix, the machine-code bit-pattern that used to mean AH instead means SPL, and so on. See Table 3-1 of Intel's instruction reference manual (volume 2).

Writing to a 32-bit register always zeros the upper 32 bits of the full-width register, unlike writing to an 8 or 16-bit register (which merges with the old value, which is an extra dependency for out-of-order execution).