..:: Register Modifications – GPR’s ::..
As was previously mentioned, one of the biggest additions to the IA-32 architecture for support of EM64T was the addition and modification of the registers. As we now know, Intel has added support for eight additional GPR’s for support of 64-bit operation. Under the IA-32 architecture, general purpose registers aren’t always as simple as their name states. In IA-32, GPR’s handle specialized instructions that might only be able to be executed within a certain register or set of registers. There are certain registers which deal with data like accumulators, and others that focus on memory addressing, such as indexing. With 64-bit GPR’s, progress has been made towards giving these GPR’s the capability to be used in multiple situations rather than for limited, specialized uses.
When operating under legacy or compatibility modes, there are eight general purpose registers available. These registers are broken up into two subsets depending upon the size of the operands in use, either 16 or 32-bits wide. For 32-bit operands, we have the registers EAX, EBX, ECX, EDX, EDI, ESI, EBP, and ESP. In order to utilize these registers with 16-bit operands, they are divided in half so that the lower 16-bits of these 32-bit registers can be used. These registers are known as AX, BX, CX, DX, DI, SI, BP, and SP. Further, for legacy 8-bit operations, these subsets can even be divided again giving 8-bit register capability. In the case of these 8-bit segments, the registers are known as legacy high-byte, and legacy low-byte. The register names follow suit with the above pattern, being AH, BH, or AL, BL.
|../// Sidebar : GPR Background ///..
Let’s take a quick sidebar here so that we can quickly go over the usages for these GPR’s. The *AX register is what is known as an accumulator, a type of register that specializes in arithmetic instructions and logical operations. Operations such as multiplication, division, and BCD correction can only occur in the accumulator register. Other operations range from simple addition, to xor the stored value and so forth. The accumulator is widely used, while the remaining registers typically offer up support for the calculations taking place in the accumulator.
The *BX register, also known as the base register is one of the few registers that does not have an important, dedicated use. This register can hold a memory location that will be used as a base, hence the name base register, that will be combined with a memory offset value for loading or storing data, etc. A simple example would be the instruction MOV AL, [BX+AL], where the value stored in AL would be transferred to the location of BX + AL. If the value stored in AL was $12, and in BX was $23, then location $35 would be stored with the value $12. This usage was more common in the 16-bit world, in the 32-bit+ world, any register can serve as a memory offset.
The *CX register is known as the count register. This register is used specifically for counting related instructions. This register is utilized in applications such as loops, and can also be used to specify when a branch should be taken, or when a jump should be made once the counter reaches zero. This register is also useful in terms of bit shifting operations such as logic or arithmetic shifts. The *CX register in this case would hold the number of shifts to be performed.
The *DX, or data, register is closely tied with the accumulator register we’ve already discussed. In the case of a 32-bit environment, the *DX register can be used to deal with oversized data like multiplication, or division. In the case of such operations, the most significant bits of the data are stored in the data register, while the remaining least significant bits are stored in the accumulator. In this case, the data register and accumulator “combine” to serve as a pseudo 64-bit register. The data register can also be used during input / output operations where it would hold the location of the port to be read, while the accumulator stores or writes the data. The most common uses of the data register rely on the accumulator’s calculations.
The *DI and *SI registers have similar properties, and thus will be covered together. To start off, the *SI register is known as the Source Index, while the *DI register is known as the Destination Index. Let’s take a loop as an example for the use of these two registers. In the case of a loop where data from multiple locations needs to be fed in, the Source Index acts as a moving pointer to the memory locations where data needs to be fetched from. In a similar case, the Destination Index is utilized as a moving pointer for storage of data from the loop. Each of these registers holds a base memory address at the beginning of the loop, and as the loop progresses, will be incremented to move on to successive memory locations. These registers have also been used for other purposes, sometimes as simple as extra storage.
Finally, the last of the eight main GPR’s are the *SP and *BP registers. These two registers are also widely used, and cover another form of memory addressing, much like the *DI and *SI registers. The *SP, or Stack Pointer, register holds the location for the top of the stack, or if the stack is “full”, the location of the last pushed item. When a function is called during a block of code, certain parameters, a return address, and other items are pushed to the stack. Once these parameters have been moved, the *BP, or Base Pointer, takes the value of the Stack Pointer and proceeds to load its own parameters to the stack. From then on, the function will work with the locations based upon the value stored in the Base Pointer. In the background, the Stack Pointer keeps track of the next empty memory location available on the top of the stack.
../// End Sidebar ///..
In 64-bit mode, the default size for the operands is 32-bits, however, these general purpose registers can be put to use by both 32-bit and 64-bit operands. If a 32-bit operand is specified, then the registers with the “E” prefix are available, along with R8D – R15D. Likewise, if a 64-bit operand is specified, the registers with the “R” prefix are available, along with the eight newly added registers R8 – R15. According to Intel, all of these registers can be accessed at the byte, word, dword, and qword level.
Also, when operating under 64-bit mode, there are limitations to some of the registers that can be accessed. Instructions cannot access the legacy high-byte registers (i.e. AH, BH), and one of the new registers at the same time. However, this is not true for the legacy low-byte registers. These registers, AL and BL for example, can indeed be referenced by instructions at the same time as new registers. These limitations are controlled for any instructions utilizing the “REX” prefix.