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.

ConditionAlso writtenMeaningTest
ezequal, zeroZF = 1
nenznot equal, not zeroZF = 0
anbeabove (unsigned)CF = 0 and ZF = 0
aenb, ncabove or equal (unsigned)CF = 0
bnae, cbelow (unsigned)CF = 1
benabelow or equal (unsigned)CF = 1 or ZF = 1
gnlegreater (signed)ZF = 0 and SF = OF
genlgreater or equal (signed)SF = OF
lngeless (signed)SF is not OF
lengless or equal (signed)ZF = 1 or SF is not OF
ssign set, negativeSF = 1
nssign clear, not negativeSF = 0
ooverflowOF = 1
nono overflowOF = 0
ppeparity evenPF = 1
nppoparity oddPF = 0