Classic.Ars: An Introduction to 64-bit Computing and x86-64

Ars explains the theory and praxis of 64 bit computing.

Switching Modes

Full binary compatibility with existing x86 code, both 32-bit and older 16-bit flavors, is one of x86-64's greatest strengths. x86-64 accomplishes this using a nested series of modes. The first and least interesting mode is legacy mode. When in legacy mode, the processor functions exactly like a standard x86 CPU--it runs a 32-bit OS and 32-bit code exclusively, and none of x86-64's added capabilities are turned on.

In short, the Hammer in legacy mode will look like just another Athlon.

It's in the 64-bit long mode that things start to get interesting. To run application software in long mode you need a 64-bit OS. Long mode provides two sub-modes--64-bit mode and compatibility mode--in which the OS can run either x86-64 or vanilla x86 code. The following diagram should help you visualize how this works:

(In the diagram above, "x86 Apps" includes both 32-bit and 16-bit x86 applications.)

So, legacy x86 code (both 32-bit and 16-bit) runs under a 64-bit OS in compatibility mode, and x86-64 code runs under a 64-bit OS in 64-bit mode. Only code running in long mode's 64-bit sub-mode can take advantage of all the new features of x86-64. Legacy x86 code running in long mode's compatibility sub-mode, for example, cannot see the extended parts of the registers, cannot use the eight extra registers, and is limited to the first 4GB of memory.

These modes are set for each segment of code on a per-segment basis by means of two bits in the segment's code segment descriptor. The chip examines these two bits so that it knows whether to treat a particular chunk of code as 32-bit or 64-bit. This chart from AMD shows the relevant features of each mode:

We've already discussed how only the integer and address operations are really affected by the shift to 64 bits, so it makes sense that only those instructions would be affected by the change. If all the addresses are now 64-bit, then there's no need to change anything about the address instructions apart from their default pointer size. If a LOAD in 32-bit legacy mode takes a 32-bit address pointer, then a LOAD in 64-bit mode takes a 64-bit address pointer.

Integer instructions, on the other hand, are a different matter. You don't always need to use 64-bit integers, and there's no need to take up cache space and memory bandwidth with 64-bit integers if your application needs only smaller 32- or 16-bit ones. So it's not in the programmer's best interest to have the default integer size be 64 bits. Hence the default data size for integer instructions is 32 bits, and if you want to use a larger or smaller integer then you must add an optional prefix to the instruction that overrides the default. This prefix, which AMD calls the REX prefix (presumably for "register extension"), is one byte in length. This means that 64-bit instructions are one byte longer, a fact that makes for slightly increased code sizes.

Increased code size is bad, because bigger code takes up more cache and more bandwidth. However, the effect of this prefix scheme on real-world code size will depend on the number of 64-bit integer instructions in a program's instruction mix. AMD estimates that the average increase in code size from x86 code to equivalent x86-64 code is less than 10%, mostly due to the prefixes.

It's essential to AMD's plans for x86-64 that there be no performance penalty for running in legacy or compatibility mode versus long mode. The two backwards compatibility modes don't give you the performance enhancing benefits of x86-64 (specifically, more registers), but they don't incur any added overhead, either. A legacy 32-bit program simply ignores x86-64's added features, so they don't affect it one way or the other. AMD intends for x86-64 to be a straightforward upgrade from x86, and this means best in class 32-bit performance along with 64-bit support.

Out with the old

In addition to fattening up the x86 ISA by increasing the number and sizes of its registers, x86-64 also slims it down by kicking out some of the older and less frequently used features that have been kept thus far in the name of backward compatibility.

When AMD's engineers started looking for legacy x86 features to jettison, the first thing to go was the segmented memory model. Programs written to the x86-64 ISA will use a flat, 64-bit virtual address space. Furthermore, legacy x86 applications running in long mode's compatibility sub-mode must run in protected mode. Support for real mode and virtual-8086 mode are absent in long mode and available only in legacy mode. This isn't too much of a hassle, though, since, except for a few fairly old legacy applications, modern x86 apps use protected mode.