The 64 bit versions of the 32 bit extended registers are prefixed with r instead of e;
- eax becomes rax
- edx becomes rdx
- exc becomes rcx
- ebx becomes rbx
- esi becomes rsi
- edi becomes rdi
- esp becomes rsp
These ‘new’ registers work like the old e versions except for implicit usage with shift counters or string operation type instructions. The new 64 bit architecture has 8 new int registers encoded with a REX prefix;
- rXb ;8 bit
- rXw ;16 bit
- rXd ;32 bit
- rX ;64 bit
Where X is an integer in the range of 8-16. Most instructions remain 32 bit and their 64 bit counterparts are invoked by the fourth bit in the REX prefix, so every 32 bit instruction has a natural 64 bit equivalent, to utilise the 64 bit version use the q (quad) postfix.
movl $1, %eax
becomes
movq $1, %rax
There are exceptions, in the case of stack manipulation instructions, where the 32 bit instructions have been depreciated (pop, push, call, enter, leave and ret) but the 16 bit versions remain;
pushq %rax
is fine, but
pushl %eax
isn't.
The result of any 32 bit operation is now zero extended to a 64 bit value, obviously 8 and 16 bit operations don''t affect the upper part of registers so they’re fine and if you’re really crafty you can use the 8-16 bit registers for optimisation.
Immediate values within an instruction remain 32 bits, their values are sign extended to 64 bits pre calculation, as a result:
subq $1, %rax
Is fine, but:
subq $0xffffffff, %rax
isn't.
There is an exception to this when the moves of constant to registers that have 64 bit form:
movq 0xffffffff, %rax
Is a 10 byte instruction that is equivalent to:
movl 0xffffffff, %eax
Which is 5 bytes. You can write symbolic expressions as operands to 62 and 32 bit operations, 32 bit operations result in zero extending relocations whilst 64 bit operations result in sign extensions:
movl $symb, %eax
Is a 5 byte instruction, whilst
movq $symb, %rax
Is a 7 bytes instruction.
To load a symb as 64 bit use the movabs instruction (which is a synonym for mov)
movandq %symb, %rax
The new 64 bit architecture has a system of relative addressing which makes it easier to write position independent code, the original displacement type addressing is now encoded by one of the redundant SIB form and as such relative instruction pointer (RIP) addressing is more efficient than displacement:
movl $0x1, 0x01(%rip)
Will store the value 0x1, 10 bytes past the end of the instruction, symbolic location is implicitly RIP relative so:
movl $0x1, symb(%rip)
Will place 0x1 at the address of $symb, its advised to use RIP to increase speed and efficiency.
This article was originally written by pigsbig78 |