How do AX, AH, AL map onto EAX?

Randy picture Randy · Mar 3, 2013 · Viewed 120.5k times · Source

My understanding of x86 registers say that each register can be accessed by the entire 32 bit code and it is broken into multiple accessible registers.

In this example EAX being a 32 bit register, if we call AX it should return the first 16 bits, and if we call AH or AL it should return the next 8 bits after the 16 bits and AL should return the last 8 bits.

So my question, because I don't truly believe is this is how it operates. If we store the 32 bit value aka EAX storing:

0000 0100 0000 1000 0110 0000 0000 0111

So if we access AX it should return

0000 0100 0000 1000

if we read AH it should return

0000 0100

and when we read AL it should return

0000 0111

Is this correct? and if it is what value does AH truly hold?

Answer

No, that's not quite right.

EAX is the full 32-bit value
AX is the lower 16-bits
AL is the lower 8 bits
AH is the bits 8 through 15 (zero-based)

So AX is composed of AH:AL halves, and is itself the low half of EAX. (The upper half of EAX isn't directly accessible as a 16-bit register; you can shift or rotate EAX if you want to get at it.)

For completeness, in addition to the above, which was based on a 32-bit CPU, 64-bit Intel/AMD CPUs have

RAX, which hold a 64-bit value, and where EAX is mapped to the lower 32 bits.

All of this also applies to EBX/RBX, ECX/RCX, and EDX/RDX. The other registers like EDI/RDI have a DI low 16-bit partial register, but no high-8 part, and the low-8 DIL is only accessible in 64-bit mode: Assembly registers in 64-bit architecture


Writing AL, AH, or AX merges into the full AX/EAX/RAX, leaving other bytes unmodified for historical reasons. (In 32 or 64-bit code, prefer a movzx eax, byte [mem] or movzx eax, word [mem] load if you don't specifically want this merging: Why doesn't GCC use partial registers?)

Writing EAX zero-extends into RAX. (Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?)