x86-64 registers & flags
Registers
Sixteen 64 bit general purpose registers. Each one can be used at four widths: rax is the whole register, eax its low 32 bits, ax its low 16 and al its low 8. Writing a 32 bit name clears the top half of the 64 bit register; writing a 16 or 8
bit name leaves the rest alone.
rax eaxaxahal
The accumulator. mul, div and the string instructions use it without being told to, a syscall number goes in it, and a syscall result comes back in it.
rbx ebxbxbhbl
A general register. Called on to survive a function call: a function that writes to it has to put it back before returning.
rcx ecxcxchcl
The counter. loop and the repeated string instructions count down with it, the shift instructions read a variable shift amount from cl, and it carries the fourth argument of a function call. syscall destroys it.
rdx edxdxdhdl
The high half of the product mul writes and of the dividend div reads, and the third argument of a function call or a syscall.
rsi esisisil
The source pointer of the string instructions, and the second argument of a function call or a syscall.
rdi edididil
The destination pointer of the string instructions, and the first argument of a function call or a syscall.
rbp ebpbpbpl
The frame pointer by convention, pointing at the base of the current function's stack frame. Nothing in the hardware requires it, and compilers routinely use it as one more general register.
rsp espspspl
The stack pointer. push, pop, call and ret move it without being told to, and it must point at usable memory whenever any of them runs.
r8 to r15 r8d to r15dr8w to r15wr8b to r15b
The eight registers x86-64 added. r8 and r9 carry the fifth and sixth arguments of a function call; r10 replaces rcx as the fourth argument of a syscall, because syscall destroys rcx. r11 is destroyed too.
rip
The instruction pointer. It cannot be read or written directly, but it can be addressed: [rel label] assembles to an offset from rip, which is how position independent code reaches its own data.
rflags eflagsflags
The flags, listed below. Arithmetic and logic instructions write them, the conditional jumps and setcc read them, and pushfq and popfq move the whole register to and from the stack.
Flags
The flags live in rflags. Arithmetic and logic instructions write them, cmp and test exist to write them without keeping a result, and the conditional instructions
read them.
CF bit 0
Carry. Set when an unsigned addition overflowed or an unsigned subtraction borrowed, and by the shift and rotate instructions, which shift the last bit out through it.
PF bit 2
Parity. Set when the low byte of the result has an even number of set bits.
AF bit 4
Adjust. The carry out of bit 3, which only the decimal adjust instructions read.
ZF bit 6
Zero. Set when the result was zero, which is what je and jne read after a cmp.
SF bit 7
Sign. A copy of the top bit of the result, so it is set when the result is negative read as signed.
DF bit 10
Direction. Clear means the string instructions count upwards, set means downwards. cld and std write it, and it is expected to be clear everywhere else.
OF bit 11
Overflow. Set when a signed operation produced a result too large for its destination, which is a different question from the one the carry flag answers.
SSE registers
Floating point arithmetic in a 64 bit program is SSE arithmetic. The xmm registers are wide enough to hold several numbers at once, and each instruction says how much of a register it means: the scalar forms work on the lowest lane alone, so addsd xmm0, xmm1 adds one pair of doubles and cvtsi2sd xmm0, rax turns an integer into a double and writes it into that same lowest lane, both of them leaving the upper lane of the destination as they found it. The moves are the exception: movsd xmm0, [x] loads one double from memory and clears bits 127 to 64, while movsd xmm0, xmm1 copies the low double and leaves the upper lane alone, so where the value came from decides what the rest of the register holds. The packed forms, addpd and mulps among them, apply the same operation to every lane of the register at once, which is the reason the registers are this wide.
The single precision instructions are spelled with ss and ps where the double precision ones use sd and pd, and the calling convention passes floating point arguments in xmm0 to xmm7 and returns them in xmm0.
xmm0 to xmm15 128 bit
Sixteen 128 bit registers. Read as doubles they are two lanes, read as singles four, and read as raw bits sixteen bytes; the registers panel shows all three, because nothing in the register itself records which one the program meant.
mxcsr 32 bit
The control and status register of the unit. It holds the rounding mode, the masks that decide whether an invalid operation raises an exception or quietly produces a NaN, and the flags that record which of those conditions has happened since the flags were last cleared. ldmxcsr and stmxcsr move it to and from memory.
x87 registers
The x87 unit is the floating point hardware x86 had before SSE, and it is still what the f instructions use. Its eight registers are a stack rather than a numbered file: st0 is always the top, fld and fld1 push a value onto it and rename everything below, and faddp adds the top two and pops, so the same register name means a different value after every push. Programs written today use SSE for arithmetic and reach for x87 mainly for the operations SSE has no instruction for, such as fsin, fcos or fpatan.
This emulator keeps the stack as ordinary 64 bit doubles rather than the 80 bit extended values real hardware computes with, so a long chain of x87 arithmetic can differ from a physical processor in the last bits of the result.
A slot the stack has not filled, or has popped, keeps whatever bits it last held. The panel shows those rows blank rather than the stale value, the way info float prints Empty in gdb, and the bits are still a hover away; ftag is the register that says which slots are live.
st0 to st7 64 bit
The stack registers, listed top first: what the panel calls st0 is whatever the last push left on top, and one more push moves that value to st1. An instruction that pops past the bottom of the stack, or pushes onto a full one, raises the stack fault the status word reports.
fctrl 16 bit
The control word: the rounding mode, the precision the unit rounds results to, and the masks that say which exceptions the program wants to be told about. fldcw writes it, which is how code that needs truncation rather than the default round to nearest gets it. The precision field has nothing to decide here, because the stack already holds doubles.
fstat 16 bit
The status word: the exception flags, the condition codes a comparison such as fcom writes, and the three bits that say which register is currently the top of the stack. fstsw ax copies it into ax, which is how an x87 comparison used to reach a conditional jump.
ftag 16 bit
Two bits per register saying whether it holds a number, a zero, a special value such as an infinity, or nothing at all. It is what makes an empty stack slot distinguishable from one holding zero, and what the panel reads to decide which rows to leave blank.
Condition codes
The same sixteen conditions end jcc, setcc and cmovcc: jne jumps, setne writes 1 or 0 to a byte, and cmovne copies a register, all on the same test. The unsigned conditions read the carry flag and the signed
ones read the sign and overflow flags, which is why comparing two numbers the wrong way round
silently gives the wrong answer.
| Condition | Also written | Meaning | Test |
|---|---|---|---|
| e | z | equal, zero | ZF = 1 |
| ne | nz | not equal, not zero | ZF = 0 |
| a | nbe | above (unsigned) | CF = 0 and ZF = 0 |
| ae | nb, nc | above or equal (unsigned) | CF = 0 |
| b | nae, c | below (unsigned) | CF = 1 |
| be | na | below or equal (unsigned) | CF = 1 or ZF = 1 |
| g | nle | greater (signed) | ZF = 0 and SF = OF |
| ge | nl | greater or equal (signed) | SF = OF |
| l | nge | less (signed) | SF is not OF |
| le | ng | less or equal (signed) | ZF = 1 or SF is not OF |
| s | sign set, negative | SF = 1 | |
| ns | sign clear, not negative | SF = 0 | |
| o | overflow | OF = 1 | |
| no | no overflow | OF = 0 | |
| p | pe | parity even | PF = 1 |
| np | po | parity odd | PF = 0 |