x86 is a 32-bit CISC-style instruction set architecture, mainly for Intel and AMD CPUs. The 64-bit version, x86-64 (or amd64), extends on x86 by supporting much more virtual and physical memory.

Why do x86 CPUs take so much power? Turns out there’s a RISC emulation layer within the CPU to support pipelining. CISC instructions are decoded into RISC-style instructions.

Features

x86 has a huge amount of architectural features that other languages don’t have, because it’s effectively been in continuous development from an 8-bit architecture to 64-bit since the 70s.

  • SIMD instructions were added in the “Multimedia eXtension” update around ~1997.
    • MMX adds SIMD instructions.
    • SSE (Streaming SIMD Extension) extends SIMD to single-precision floating-point numbers.
    • SSE2 adds support for double-precision floats.
    • AVX (Advanced Vector Extensions) adds 256-bit and 512-bit SIMD registers.
  • Hardware virtualisation was introduced in 2005-2006.
    • This adds support for ring -1 mode, for type-1 hypervisors.

Instructions

Instructions are not fixed-length. They can vary between 1-18 bytes.

Control flow:

  • callf: subroutine call. This places the return address on a stack in memory.

Registers

The x86-64 ABI (called System V) specifies a calling convention and stack alignment. The ABI also specifies a 16-byte stack alignment boundary. Most operating systems (Linux, macOS, Windows) use this ABI. The calling convention is register-based and is given by:

  • The first 6 integer/pointer parameters are stored in: rdi, rsi, rdx, rcx, r8, and r9, respectively. Any more parameters must be put on the stack.
  • Floating-point inputs passed in xmm0 to xmm7.
  • Integer/pointer return values are put in rax and float returns are put in xmm0.
  • Registers rax, rcx, rdx, rsi, rdi, r8 to r11 are caller-saved.
  • Registers rbx, rbp, r12 to r15 are callee-saved.

We can access parts of the register:

  • Last 32 bits
    • For special registers, we prefix with e instead of r, i.e., eax, ebx.
    • For numbered registers, we suffix with d, i.e., r11d.
  • Last 16 bits — for special registers, we remove the first character (i.e., ax, bx). For numbered registers, we suffix with w.
  • Last 8 bits — for special registers we suffix with l, i.e., al, bl, sil, dil. For numbered registers, we suffix with b.