x86-64

registers, the calling convention, and the instructions i actually type. intel/nasm order throughout: op dst, src.

jump to: registers · calling convention · instructions · addressing · conditions

registers

64     32     16    8      role (sysv)
rax    eax    ax    al     return value
rdi    edi    di    dil    arg 1
rsi    esi    si    sil    arg 2
rdx    edx    dx    dl     arg 3  (also 2nd return)
rcx    ecx    cx    cl     arg 4
r8     r8d    r8w   r8b    arg 5
r9     r9d    r9w   r9b    arg 6
r10    r10d   r10w  r10b   scratch
r11    r11d   r11w  r11b   scratch
rbx    ebx    bx    bl     callee-saved
rbp    ebp    bp    bpl    frame pointer (callee-saved)
rsp    esp    sp    spl    stack pointer
r12    r12d   r12w  r12b   callee-saved
r13    r13d   r13w  r13b   callee-saved
r14    r14d   r14w  r14b   callee-saved
r15    r15d   r15w  r15b   callee-saved
  • rip --; instruction pointer; rflags --; status flags (ZF, SF, CF, OF, ...)
  • xmm0–xmm15 --; 128-bit sse registers for floats/vectors
  • legacy ah, bh, ch, dh alias the high byte of the first four

calling convention (sysv amd64)

linux and macos. windows x64 differs (rcx, rdx, r8, r9).

  • integer/pointer args, in order: rdi, rsi, rdx, rcx, r8, r9 --; the rest go on the stack, pushed right-to-left
  • float args: xmm0–xmm7
  • return value: rax (rdx:rax for 128-bit); floats in xmm0
  • callee-saved (you must restore): rbx, rbp, rsp, r12, r13, r14, r15
  • caller-saved (scratch): rax, rcx, rdx, rsi, rdi, r8, r9, r10, r11
  • stack must be 16-byte aligned at the call; leaf functions get a 128-byte red zone below rsp
  • note: syscalls differ --; number in rax, args in rdi, rsi, rdx, r10, r8, r9 (see interrupts)

common instructions

  • data: mov copy, movzx/movsx zero/sign-extend, lea address math, xchg swap
  • stack: push, pop, call, ret, leave
  • arithmetic: add, sub, inc, dec, neg, imul/idiv (signed), mul/div (unsigned)
  • bits: and, or, xor, not, shl/sal, shr, sar, rol/ror
  • compare: cmp a, b sets flags for a − b; test a, b sets flags for a & b
  • control: jmp, conditional jcc (below), call/ret, syscall, nop
; int add(int a, int b) { return a + b; }   (sysv)
add:
    lea eax, [rdi + rsi]    ; a in edi, b in esi -> eax
    ret

addressing modes

  • immediate --; mov rax, 5
  • register --; mov rax, rbx
  • memory --; mov rax, [rbx]
  • base + displacement --; [rbx + 8]
  • base + index*scale + disp --; [rbx + rcx*4 + 8], scale ∈ {1, 2, 4, 8}
  • rip-relative --; [rel label] (nasm) or [rip + label]

conditions (jcc after cmp)

  • equal: je/jz; not equal: jne/jnz
  • signed: jg (>), jge (≥), jl (<), jle (≤)
  • unsigned: ja (>), jae (≥), jb (<), jbe (≤)
  • flags: js/jns (sign), jo/jno (overflow), jc/jnc (carry)