58

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?

Community
  • 1
  • 1
Randy
  • 1,400
  • 2
  • 12
  • 30
  • No, your value for AX is wrong. Hack off the last 16 bits. AH simply returns bits 8 through 15 of EAX. – Hans Passant Mar 03 '13 at 21:37
  • 5
    please replace the bit pattern by something which is easier to understand int the context of your question e.g: 0000 0001 0010 0011 ... – Micha Wiedenmann Mar 03 '13 at 21:38
  • Related: [Assembly language - Why are characters stored in register as little endian?](https://stackoverflow.com/q/48645360) re: mapping to memory. – Peter Cordes Jun 09 '21 at 09:33

6 Answers6

108

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), the top half of AX

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.)

x86-64 CPUs extend the integer registers to 64-bit:

  • RAX is the full 64-bit value, with EAX and its sub-components mapped to the lower 32 bits. The upper half of 64-bit registers is only accessible in 64-bit mode, unlike 32-bit registers which can be used in any mode on CPUs that support them.

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 leaves other bytes unmodified in the full AX/EAX/RAX, for historical reasons. i.e. it has to merge a new AL into the full RAX, for example. (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?)

Again, all of this applies to every register, not just RAX. e.g. writing DI or DIL merges into the old RDI, writing EDI zero-extends and overwrites the full RDI. Same for R10B or R10W writes merging, writing R10D leaving R10 independent of the old R10 value.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • how d you call the higher 16-bits, and higher 32bits? Is there a EAXH or AXH? – user97662 Jun 26 '17 at 19:39
  • 1
    @user97662: No, there's no way to access only the upper parts of the registers - you must read the entire register and shift as needed. – 500 - Internal Server Error Jun 26 '17 at 19:54
  • When I was in school (in Russia), we were primarily studying the 16-bit assembly language in DOS. I do remember that general purpose registers adhered to the little endian system, e.g. AX was |AL|AH|. Although I had a hard time at extrapolating this concept onto 32-bit registers. Would something like this be legit for EAX? |AL|AH|EAL|EAH| Or is it just |AL|AH| EAX | ? – wintermute Dec 04 '17 at 06:09
  • 1
    @wintermute: [Why is there not a register that contains the higher bytes of EAX?](https://stackoverflow.com/q/228200) covers the why. [Access higher order bytes of a register in assembly](https://stackoverflow.com/q/48433027) covers what to do instead, especially comments there have some efficient suggestions. – Peter Cordes Sep 30 '22 at 02:09
44

AX is the 16 lower bits of EAX. AH is the 8 high bits of AX (i.e. the bits 8-15 of EAX) and AL is the least significant byte (bits 0-7) of EAX as well as AX.

Example (Hexadecimal digits):

EAX: 12 34 56 78
AX: 56 78
AH: 56
AL: 78
phuclv
  • 37,963
  • 15
  • 156
  • 475
pascalhein
  • 5,700
  • 4
  • 31
  • 44
44
| 0000 0001 0010 0011 0100 0101 0110 0111 | ------> EAX

|                     0100 0101 0110 0111 | ------> AX

|                               0110 0111 | ------> AL

|                     0100 0101           | ------> AH
Sohcahtoa82
  • 619
  • 3
  • 13
Miku Ghoul
  • 634
  • 1
  • 6
  • 7
7

no your ans is Wrong

Selection of Al and Ah is from AX not from EAX

e.g

EAX=0000 0000 0000 0000 0000 0000 0000 0111

So if we call AX it should return

0000 0000 0000 0111

if we call AH it should return

0000 0000

and when we call AL it should return

0000 0111

Example number 2

EAX: 22 33 55 77
AX: 55 77
AH: 55    
AL: 77

example 3

EAX: 1111 0000 0000 0000 0000 0000 0000 0111    
AX= 0000 0000 0000 0111
AH= 0000 0000
AL= 0000 0111  
Tomas Pastircak
  • 2,867
  • 16
  • 28
  • 1
    Any thing to do with endian? If I do `movl $0x01 %eax` assembling with _GAS_, what will the values of `%ax` and `%al` be? One or zero? – Frozen Flame Aug 27 '14 at 03:47
  • @FrozenFlame: No, endianness only applies to memory (including how the `mov $imm32, %eax` instruction is encoded, as `opcode 01 00 00 00`.). The value in %al will be `1`. Left-shifting %eax works if you think of the MSB at the left, LSB at the right within the register. (This can get tricky for vector registers, see https://stackoverflow.com/questions/41351087/convention-for-displaying-vector-registers) – Peter Cordes Sep 19 '17 at 03:46
4

No -- AL is the 8 least significant bits of AX. AX is the 16 least significant bits of EAX.

Perhaps it's easiest to deal with if we start with 04030201h in eax. In this case, AX will contain 0201h, AH wil contain 02h and AL will contain 01h.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
4

The below snippet examines EAX using GDB.

    (gdb) info register eax
    eax            0xaa55   43605
    (gdb) info register ax
    ax             0xaa55   -21931
    (gdb) info register ah
    ah             0xaa -86
    (gdb) info register al
    al             0x55 85
  1. EAX - Full 32 bit value
  2. AX - lower 16 bit value
  3. AH - Bits from 8 to 15
  4. AL - lower 8 bits of EAX/AX
scanjee
  • 311
  • 3
  • 5
  • 1
    you can also print registers in gdb with `p /x $eax` (or omit the `/x` for decimal). And modify them with `set $eax = 0xdeadbeef`, IIRC. See also the bottom of the [x86 tag wiki](https://stackoverflow.com/tags/x86/info) for some gdb tips for asm. – Peter Cordes Sep 19 '17 at 03:41