Recently I was struggling with intel x86 assembly. I draw some figures to understand well what are the purpose of each register and I’d like to share them here. This is a bit off-topic because this blog is about Smalltalk, however my job is to work on Smalltalk to assembly translation, so it is kind of related.
In the general purpose registers, you have:
- Registers A, B, C D since the 16 bits version
- The indexed registers source index and destination index since 32 bits version
- The stack pointer and frame pointer
- In 64 bits only, additional registers (register 8 to 15)
In addition, 32 bits and more recent architectures provides the x87 stack, that one should not use because it is deprecated, for 80 bits floating pointers calculs. The x87 stack works with this floating pointer format (Extended precision format):
Then, eight 128 bits length registers are provided for SSE (Integer, single and double precision float fast arithmetics) in 32 bits, and sixteen 128 bits length registers are provided in 64 bits.
The instruction pointer has always been here to access the cpu state. However, its value can be directly accessed only since the 64 bits processors. Before, one used to access EIP with this trick:
get_eip: mov eax, [esp]
Then calling this method would put EIP value in EAX:
Segment registers are provided for backward compatibility with old systems, where memory segmentation was used by OS instead of paging. Most of them are not used any more. However, the segment register is used for the GDT (Global Descriptor Table) and several OS uses the GS register (windows 64 bits for the thread local storage and Linux for accessing cpu specific memory).
Lastly, there’s multiple flags in the cpu stored in the flag register.
This is very useful to have this sum-up figures in my opinion. Other useful figures when you work in x86 are equivalence between jumps (for example jump Carry is the same as jump if below). You can find a nice summary of x86 jumps here.