Douglas Crockford

Blog

Books

Videos

2024 Appearances

JavaScript

Misty

JSLint

JSON

Github

Electric Communities

Mastodon/Layer8

Flickr Photo Album

ResearchGate

LinkedIn

Pronouns: pe/per

About

x64 Register Names

  AMD Improved
0 rax r0
1 rcx r1
2 rdx r2
3 rbx r3
4 rsp rsp
5 rbp r5
6 rsi r6
7 rdi r7
8 r8 r8
9 r9 r9
a r10 r10
b r11 r11
c r12 r12
d r13 r13
e r14 r14
f r15 r15

AMD elevated the Intel Architecture to 64 bits. They doubled the size of the general registers from 32 bits to 64 bits and doubled the number of general registers from 8 to 16. They gave the new registers names based on numbers, startling correctly at zero. But they let the original 8 Intel registers keep their original names, slapping on an r (for register) prefix. The names are confusing, error prone, and weird. What is the difference between rbx and rbp? What is the difference between rdx and rdi? Humans are pretty good at distinguishing single letters and simple sequences of numbers, but we are less good at handling single letter differences in random strings of letters.

high low
a
b c
d e
h l
ix
iy

To understand how the names got that way, we have to look at the Z80, a popular 8 bit processor from Zilog. It was an upgrade of Intel's 8080, being binary compatible but with new instructions and registers that made it a little easier to program and a little bit faster.

It had seven 8 bit registers (a b c d e h l) that could be paired to make 16 bit registers (bc de hl). In addition, Zilog added two so-called index registers (ix iy).

Recognizing the crappiness of its 8 bit architecture, Intel intended to take a great leap forward with its brilliant 432 project, which they called a micro mainframe, with excellent support for high level languages like Ada. Unfortunately, they allowed their design to become far too complex, and it became a spectacular failure. Meanwhile, Zilog, Motorola, and National Semiconductor were launching their 16 and 32 bit architectures, and Intel had nothing to compete with.

So there was a crash effort to make a 16 bit device that would keep them afloat until they could make something better. They did not have time for performance or elegance, so they went for compatibility. They designed a chip that was assembly language compatible with the Z80. The goal was that would feed your Z80 asm files to an Intel assembler, and out came code that ran on the new 8086 chip.

The compatibility play did not work. The stuff that ran on the Z80 was happy to stay on the Z80, which was much cheaper than the 8086. So they released a new assembly language specifically for the 8086 and gave the registers new names.

Z80 8086
a ah
bc cx
de dx
hl bx
sp sp
  bp
ix si
iy di

The first four registers have two halves. For example, the bx register has two halves (bh bl). That was for Z80 compatibility. It is not something you would expect to see in a well designed architecture.

The original 8086 contained several specialized instructions that used certain registers in unique ways. Most of those instructions have fallen out of favor, but ax and dx still have a special relationship with multiplication and division. AMD kept those names as they were. I prefer to use the simple numbered names. Less baggage. But I will continue to use rsp instead of r4. It is weird that they put the stack pointer in the middle of the list.

Another alternative would be to give each register a single letter name, like the 8080 did, but it seems likely that Intel will double the number of registers again to remain competitive with ARM64 and RISC-V. Twenty six letters just ain't enough.

IBM went shopping for a CPU for their PC, bought Intel, and the rest, sadly, is history. The 8086 was the worst of its class, and it was the winner. It established what has become known as the Intel Architecture, which has been an on-going embarrassment for Intel. Intel tried to supplant it with the 960, 860, and Iridium. All failed. AMD did a clever hack to make what is now known as x64. Hopefully, that eventually falls to RISC-V or something better.

The Microsoft and Unix worlds have slightly incompatible conventions for subroutine calling. Neither makes a lot of sense. Some registers are considered volatile (used for parameters and temporary values). A subroutine is allowed to clobber these. Some registers are considered nonvolatile. A subroutine must save the values before it uses the registers, and must restore the values before it returns.

This is the union of the two conventions:

volatile r0 r1 r2   r8 r9 r10 r11  
non-volatile   r3 r5   r12 r13 r14 15