| ||
The Intel 80x86 processor family has internal storage that is referred to as registers. These have been organized into seven groups: general-purpose data registers, segment registers, status registers, control registers, FPU registers used by the FPU (floating-point unit), MMX registers, and XMM registers. Please note that the FPU and MMX registers share storage area and thus are mutually exclusive (only one of them can be used at a time). Each has its own set of functionality.
The following registers and their ranges are for dealing with the SIMD instruction sets directly. They do not include system registers.
SIMD Instruction Set | Regs | IA-32 | EM64T | Bits |
---|---|---|---|---|
MMX | mm# | (07) | (07) | 64 |
3DNow! | mm# | (07) | (07) | 64 |
3DNow! Extensions (3DNow!+) | mm# | (07) | (07) | 64 |
3DNow! MMX Extensions (MMX+) | mm# | (07) | (07) | 64 |
SSE | xmm# | (07) | (815) | 128 |
SSE2 | xmm# | (07) | (815) | 128 |
SSE3 | xmm# | (07) | (815) | 128 |
The general-purpose registers are organized into two groups of eight registers: The RAX, RBX, RCX, and RDX general registers each have an 8-, 16-, 32-, and 64-bit form, as well as the index registers RSI and RDI, and the stack pointers RBP and RSP. The second set of eight are new registers R8R15. The instruction pointer RIP has a 16-, 32-, and 64-bit form depending on which mode the processor is running in.
No 64-bit | There is a special case where the AH, BH, CH, and DH are not accessible when the REX prefix is used. REX is used for all extended 64-bit registers as well as SIL, DIL, BPL, and SPL register access. |
64 | RAX | RBX | RCX | RDX | RSI | RDI | RBP | RSP | RIP |
---|---|---|---|---|---|---|---|---|---|
32 | EAX | EBX | ECX | EDX | ESI | EDI | EBP | ESP | |
16 | AX | BX | CX | DX | SI | DI | BP | SP | |
8 | AL | BL | CL | DL | SIL | DIL | BPL | SPL |
64 | R8 | R9 | R10 | R11 | R12 | R13 | R14 | R15 |
---|---|---|---|---|---|---|---|---|
32 | R8D | R9D | R10D | R11D | R12D | R13D | R14D | R15D |
16 | R8W | R9W | R10W | R11W | R12W | R13W | R14W | R15W |
8 | R8B | R9B | R10B | R11B | R12B | R13B | R14B | R15B |
32 | EAX | EBX | ECX | EDX | ESI | EDI | EBP | ESP | EIP |
---|---|---|---|---|---|---|---|---|---|
16 | AX | BX | CX | DX | SI | DI | BP | SP | IP |
8 | AL | BL | CL | DL |
The general-purpose registers are used as memory pointers, address calculations (displacement w/scaling), logical bit, and mathematical operations. There is an exception as the RSP register is the stack pointer and has limitations such as it does not support scaling and displacement. In relation to the segment registers, the 64-bit stack pointer is used in conjunction with the stack segment-selector (SS) register as a default.
Register | Extra Functionality |
---|---|
RAX, EAX, AX | The accumulator . If used as a pointer in Protected Mode uses the DS segment register as a default. DS:[EAX] |
RBX, EBX, BX | Used as a data pointer using the DS segment register as a default. DS:[EBX] |
RCX, ECX, CX | Used as a counter in string (rep) and loop operations. If used as a pointer in Protected Mode uses the DS segment register as a default. DS:[ECX] |
RDX, EDX, DX | Input/output port address. If used as a pointer in Protected Mode uses the DS segment register as a default. DS:[EDX] |
RSI, ESI, SI | Source index using DS segment register as a default. DS:[ESI] |
RDI, EDI, DI | Destination index using ES segment register as a default. ES:[EDI] |
RBP, EBP, BP | Pointer to data on the stack (very similar to ESP); uses the SS segment register as a default. SS:[EBP] |
RSP, ESP, SP | Stack pointer used the SS segment register as a default. SS:[ESP] |
RIP, EIP, IP | Instruction pointer. CS:[EIP] |
Note: The "R" prefix of these registers only became available with the 64-bit versions of the processor. The "E" prefix of these registers became available with the introduction of the 32-bit 386 processor. Prior to that, only 16-bit registers were supported.
Regardless of which mode you were in, you could access either 32-bit or 16-bit registers. But this was with the introduction of a pre-op code. If in 32 bit, you accessed 32-bit registers. In 16 bit, you accessed 16-bit registers. But if you needed to access the alternate type, then a hidden leading prefix was embedded in the binary output:
(66h ) operand- size prefix
(67h ) address-size prefix
So from 32-bit code
mov eax,3 66h mov ax,3
from 16-bit code
66h mov eax,3 mov ax,3
This covers all the 32-bit processors. So now that I have complicated things for you with some history, let us examine the new REX prefix.
The prefix REX is not an instruction, it is an invisible prefix. It is similar to the operand-size and address-size prefix that the assembler and compilers inject into the code when switching before a 16-bit and 32-bit access method. With the new 64-bit instructions it has been extended again.
Note | When the processor is running in 64-bit mode the data is 32 bit. A REX prefix of 40h 48h is embedded when using 64-bit data access. After all, a 64-bit number is a very big number and thus not needed that often. Sign extending a 32-bit number when needed is more code efficient. |
With the introduction of 64-bit processors a new invisible prefix is used: REX ( 40h4Fh ). So if this new processor is running in 64-bit mode the previous rules still apply, but to access the 64-bit data a REX opcode is injected:
66h mov ax,3 mov eax,3 REX mov rax,3
No 64-bit | You cannot use 64-bit data while running in 32-bit mode or inc/dec register instructions in 64-bit mode and here is why: The opcodes 40h4Fh are mapped to register increment and decrement instructions in a 32-bit mode environment! Thus, in 32-bit mode only the 32-bit data and instruction sets can be accessed. REX does not exist. In 64-bit mode, 32-bit and 64-bit data can be accessed, but the inc/dec instructions are no longer available for direct use by a register. |
40h | inc EAX |
41h | inc ECX |
42h | inc EDX |
43h | inc EBX |
44h | inc ESP |
45h | inc EBP |
46h | inc ESI |
47h | inc EDI |
48h | dec EAX |
49h | dec ECX |
4ah | dec EDX |
4bh | dec EBX |
4ch | dec ESP |
4dh | dec EBP |
4eh | dec ESI |
4fh | dec EDI |
7 | 6 | 5 | 4 | 3 | 2 | 1 |
|
---|---|---|---|---|---|---|---|
| 1 |
|
| W | R | X | C |
W | 0 = Default operand size, 1 = 64-bit operand size |
R | Extension of mod r/m register field |
X | Extension of the mod r/m field, |
C | Extension of the mod r/m field, SIB base field, or opcode reg. field |
The instruction format is a grouping of a prefix that is optional, opcode, mod r/m, sib, displacement, and data. This book does not get into the nitty-gritty of how an instruction, registers, and/or memory references map into an actual opcode. But the bit mapping for the mod r/m is as follows :
MOD | R/M | |
---|---|---|
00 | 000 | DS:[EAX] |
00 | 001 | DS:[ECX] |
00 | 010 | DS:[EDX] |
00 | 011 | DS:[EBX] |
00 | 100 | s-i-b |
00 | 101 | DS:d32 |
00 | 110 | DS:[ESI] |
00 | 111 | DS:[EDI] |
MOD | R/M | |
---|---|---|
01 | 000 | DS:[EAX+d8] |
01 | 001 | DS:[ECX+d8] |
01 | 010 | DS:[EDX+d8] |
01 | 011 | DS:[EBX+d8] |
01 | 100 | s-i-b |
01 | 101 | SS:[EBP+d8] |
01 | 110 | DS:[ESI+d8] |
01 | 111 | DS:[EDI+d8] |
MOD | R/M | |
---|---|---|
10 | 000 | DS:[EAX+d32] |
10 | 001 | DS:[ECX+d32] |
10 | 010 | DS:[EDX+d32] |
10 | 011 | DS:[EBX+d32] |
10 | 100 | s-i-b |
10 | 101 | SS:[EBP+d32] |
10 | 110 | DS:[ESI+d32] |
10 | 111 | DS:[EDI+d32] |
MOD | R/M | |
---|---|---|
11 | 000 | AL AX EAX RAX |
11 | 001 | CL CX ECX RCX |
11 | 010 | DL DX EDX RDX |
11 | 011 | BL BX EBX RBX |
11 | 100 | AH SP ESP RSP SPL |
11 | 101 | CH BP EBP RBP BPL |
11 | 110 | DH SI ESI RSI SIL |
11 | 111 | BH DI EDI RDI DIL |
There are other mappings but this is sufficient. The reason this book does not get too deep into details is that you are probably not writing assemblers or compilers. If you were, then you mostly would not need this book except as a reference. It is just one of those interesting tidbits but unnecessary for assembly language programming or debugging. "s-i-b" represents (scale-index-base) byte.
In Protected Mode these registers are referred to as "selectors" and in Real Mode "segment registers." In Real Mode they are used in conjunction with an index register to calculate a memory address. As they are functionally the same, in this section "segment" will mean both. They are sometimes referred to as segment-selectors.
150 | Description |
---|---|
CS | Code segment |
DS | Data segment |
ES | Extra (data) segment |
FS | Data segment |
GS | Data segment |
SS | Stack segment |
Note: The FS and GS were not available prior to the 386 processor.
When modifying any segment-selector register you must first save a copy of its stored value and restore it before exiting your function or your program will go "BOOM!" (That is a technical term !) Well, it will not explode as it will just cause the process to crash, but it will sure seem like it exploded. (Ask any assembly language programmer!)
If you are writing a Win32 type application, then typically all the segment-selectors are used in the execution of your code but are usually not denoted in your code as the defaults will be used. The FS and GS are used in your assembly code typically only in device drivers. This is the case of a flat memory model and the DS and ES are set to the same base address in memory. This section essentially becomes a no-brainer! You can completely ignore the segment registers since the DS, ES, and SS are set to the same segment and the indexing registers have used one or the other segment register as a default.
If you are writing an Extended DOS or other OS-based application, then you will typically use most or all of the segment-selector registers, especially in your low-level operating system drivers.
There are eight 64-bit MMX registers (MM0, MM1, MM2, MM3, MM4, MM5, MM6, MM7). These are 64-bit registers that can deal with a single 64-bit number, or two 32-bit, four 16-bit, or eight 8-bit packed values. In the 3DNow! instruction set they used for both integers and floating-point value pairs. These registers were introduced with the Pentium Pro series processors. There are no flags to set or read but based upon the instruction the individual packed data values are treated individually to effectively replicate a desired instruction.
There are eight 128-bit SSE registers (XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7) for pre 64-bit and eight additional registers (XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15) for 64-bit or larger data processors. These are 128-bit registers that can deal with two single 64-bit, four 32-bit, eight 16-bit, or sixteen 8-bit packed values, whether they be integer or single/double-precision floating-point. These registers were introduced with the PIII series processors. There are no flags to set or read, but based upon the instruction the individual packed data values are treated individually to effectively replicate a desired instruction. The functionality of the 64-bit MMX registers was migrated to the 128-bit SSE registers, thus doubling the size but without the burden of the FPU vs. MMX data type switching. Whenever possible, these should be used instead of MMX.