// $Id: arch-x86.txt 2217 2009-07-24 17:47:49Z peter $
[[arch-x86]]
== x86 Architecture

indexterm:[amd64]
The ((x86)) architecture is the generic name for a multi-vendor
16-bit, 32-bit, and most recently 64-bit architecture.  It was
originally developed by Intel in the 8086 series of CPU, extended to
32-bit by Intel in the 80386 CPU, and extended by AMD to 64 bits in
the Opteron and Athlon 64 CPU lines.  While as of 2007, Intel and AMD
are the highest volume manufacturers of x86 CPUs, many other vendors
have also manufactured x86 CPUs.  Generally the manufacturers have
cross-licensed (or copied) major improvements to the architecture, but
there are some unique features present in many of the implementations.

[[arch-x86-instructions]]
=== Instructions

The x86 architecture has a variable instruction size that allows for
moderate code compression while also allowing for very complex operand
combinations as well as a very large instruction set size with many
extensions.  Instructions generally vary from zero to three operands
with only a single memory operand allowed.

[[arch-x86-nop]]
==== NOP Padding

indexterm:[alignment,code]
indexterm:[`ALIGN`,code]

Different processors have different recommendations for the ((NOP))
(no operation) instructions used for ((padding)) in code.  Padding is
commonly performed to align loop boundaries to maximize performance,
and it is key that the padding itself add minimal overhead.  While the
one-byte NOP `90h` is standard across all x86 implementations, more
recent generations of processors recommend different variations for
longer padding sequences for optimal performance.  Most processors
that claim a 686 (e.g. Pentium Pro) generation or newer featureset
support the ""long"" NOP opcode `0Fh 1Fh`, although this opcode was
undocumented until recently.  Older processors that do not support
these dedicated long NOP opcodes generally recommended alternative
longer NOP sequences; while these sequences work as NOPs, they can
cause decoding inefficiencies on newer processors.

Because of the various NOP recommendations, the code generated by the
Yasm `ALIGN` directive depends on both the execution mode (`BITS`)
setting and the processor selected by the `CPU` directive (see
<<arch-x86-cpu>>).  <<x86-nop-modes>> lists the various combinations
of generated NOPs.

[[x86-nop-modes]]
.x86 NOP Padding Modes
[cols="3*<",options="header"]
|========
|`BITS`| `CPU`                          | Padding
| `16` | Any                            | 16-bit short NOPs
| `32` | None given, or less than `686` | 32-bit short NOPs (no long NOPs)
| `32` | `686` or newer Intel processor | Intel guidelines, using long NOPs
| `32` | `K6` or newer AMD processor    | AMD K10 guidelines, using long NOPs
| `64` | None                           | Intel guidelines, using long NOPs
| `64` | `686` or newer Intel processor | Intel guidelines, using long NOPs
| `64` | `K6` or newer AMD processor    | AMD K10 guidelines, using long NOPs
|========

In addition, the above defaults may be overridden by passing one of
the options in <<x86-nop-cpu>> to the `CPU` directive.

[[x86-nop-cpu]]
.x86 NOP `CPU` Directive Options
[cols="2*<",options="header"]
|========
| Name           | Description
| ((`basicnop`)) | Long NOPs not used
| ((`intelnop`)) | Intel guidelines, using long NOPs
| ((`amdnop`))   | AMD K10 guidelines, using long NOPs
|========

[[arch-x86-modes]]
=== Execution Modes and Extensions

The x86 has been extended in many ways throughout its history,
remaining mostly backwards compatible while adding execution modes and
large extensions to the instruction set.  A modern x86 processor can
operate in one of four major modes: 16-bit real mode, 16-bit protected
mode, 32-bit protected mode, and 64-bit long mode.  The primary
difference between real and protected mode is in the handling of
segments: in real mode the segments directly address memory as 16-byte
pages, whereas in protected mode the segments are instead indexes into
a descriptor table that contains the physical base and size of the
segment.  32-bit protected mode allows paging and virtual memory as
well as a 32-bit rather than a 16-bit offset.

The 16-bit and 32-bit operating modes both allow for use of both
16-bit and 32-bit registers via instruction prefixes that set the
operation and address size to either 16-bit or 32-bit, with the active
operating mode setting the default operation size and the ""other""
size being flagged with a prefix.  These operation and address sizes
also affect the size of immediate operands: for example, an
instruction with a 32-bit operation size with an immediate operand
will have a 32-bit value in the encoded instruction, excepting
optimizations such as sign-extended 8-bit values.

Unlike the 16-bit and 32-bit modes, 64-bit long mode is more of a
break from the ""legacy"" modes.  Long mode obsoletes several
instructions.  It is also the only mode in which 64-bit registers are
available; 64-bit registers cannot be accessed from either 16-bit or
32-bit mode.  Also, unlike the other modes, most encoded values in
long mode are limited to 32 bits in size.  A small subset of the `MOV`
instructions allow 64 bit encoded values, but values greater than 32
bits in other instructions must come from a register.  Partly due to
this limitation, but also due to the wide use of relocatable shared
libraries, long mode also adds a new addressing mode: `RIP`-relative.

[[arch-x86-cpu]]
==== CPU Options

The NASM parser allows setting what subsets of instructions and
operands are accepted by Yasm via use of the `CPU` directive (see
<<nasm-directive-cpu>>).  As the x86 architecture has a very large
number of extensions, both specific feature flags such as ""SSE3"" and
CPU names such as ""P4"" can be specified.  The feature flags have
both normal and ""no""-prefixed versions to turn on and off a single
feature, while the CPU names turn on only the features listed, turning
off all other features.  <<x86-cpu-features>> lists the feature flags,
and <<x86-cpus>> lists the CPU names Yasm supports.  Having both
feature flags and CPU names allows for combinations such as `CPU P3
nofpu`.  Both feature flags and CPU names are case insensitive.

[[x86-cpu-features]]
.x86 CPU Feature Flags
[cols="2*<",options="header"]
|========
|Name     |Description
|`FPU`    |Floating Point Unit (FPU) instructions
|`MMX`    |MMX SIMD instructions
|`SSE`    |Streaming SIMD Extensions (SSE) instructions
|`SSE2`   |Streaming SIMD Extensions 2 instructions
|`SSE3`   |Streaming SIMD Extensions 3 instructions
|`SSSE3`  |Supplemental Streaming SIMD Extensions 3 instructions
|`SSE4.1` |Streaming SIMD Extensions 4, Penryn subset (47 instructions)
|`SSE4.2` |Streaming SIMD Extensions 4, Nehalem subset (7 instructions)
|`SSE4`   |All Streaming SIMD Extensions 4 instructions (both SSE4.1 and SSE4.2)
|`SSE4a`  |Streaming SIMD Extensions 4a (AMD)
|`SSE5`   |Streaming SIMD Extensions 5
|`XSAVE`  |XSAVE instructions
|`AVX`    |Advanced Vector Extensions instructions
|`FMA`    |Fused Multiply-Add instructions
|`AES`    |Advanced Encryption Standard instructions
|`CLMUL`, `PCLMULQDQ`    |PCLMULQDQ instruction
|`3DNow`  |3DNow! instructions
|`Cyrix`  |Cyrix-specific instructions
|`AMD`    |AMD-specific instructions (older than K6)
|`SMM`    |System Management Mode instructions
|`Prot`, `Protected`     |Protected mode only instructions
|`Undoc`, `Undocumented` |Undocumented instructions
|`Obs`, `Obsolete`       |Obsolete instructions
|`Priv`, `Privileged`    |Privileged instructions
|`SVM`    |Secure Virtual Machine instructions
|`PadLock`|VIA PadLock instructions
|`EM64T`  |Intel EM64T or better instructions (not necessarily 64-bit only)
|========

[[x86-cpus]]
.x86 CPU Names
[cols="3*<",options="header"]
|========
|Name
|Feature Flags
|Description

|`8086`
|`Priv`
|Intel 8086

|`186`, `80186`, `i186`
|`Priv`
|Intel 80186

|`286`, `80286`, `i286`
|`Priv`
|Intel 80286

|`386`, `80386`, `i386`
|`SMM`, `Prot`, `Priv`
|Intel 80386

|`486`, `80486`, `i486`
|`FPU`, `SMM`, `Prot`, `Priv`
|Intel 80486

|`586`, `i586`, `Pentium`, `P5`
|`FPU`, `SMM`, `Prot`, `Priv`
|Intel Pentium

|`686`, `i686`, `P6`, `PPro`, `PentiumPro`
|`FPU`, `SMM`, `Prot`, `Priv`
|Intel Pentium Pro

|`P2`, `Pentium2`, `Pentium-2`, `PentiumII`, `Pentium-II`
|`MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel Pentium II

|`P3`, `Pentium3`, `Pentium-3`, `PentiumIII`, `Pentium-III`, `Katmai`
|`SSE`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel Pentium III

|`P4`, `Pentium4`, `Pentium-4`, `PentiumIV`, `Pentium-IV`,
`Williamette`
|`SSE2`, `SSE`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel Pentium 4

|`IA64`, `IA-64`, `Itanium`
|`SSE2`, `SSE`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel Itanium (x86)

|`K6`
|`3DNow`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|AMD K6

|`Athlon`, `K7`
|`SSE`, `3DNow`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|AMD Athlon

|`Hammer`, `Clawhammer`, `Opteron`, `Athlon64`, `Athlon-64`
|`SSE2`, `SSE`, `3DNow`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|AMD Athlon64 and Opteron

|`Prescott`
|`SSE3`, `SSE2`, `SSE` `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel codename Prescott

|`Conroe`, `Core2`
|`SSSE3`, `SSE3`, `SSE2`, `SSE`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel codename Conroe

|`Penryn`
|`SSE4.1`, `SSSE3`, `SSE3`, `SSE2`, `SSE`, `MMX`, `FPU`, `SMM`,
`Prot`, `Priv`
|Intel codename Penryn

|`Nehalem`, `Corei7`
|`XSAVE`, `SSE4.2`, `SSE4.1`, `SSSE3`, `SSE3`, `SSE2`, `SSE`, `MMX`,
`FPU`, `SMM`, `Prot`, `Priv`
|Intel codename Nehalem

|`Westmere`
|`CLMUL`, `AES`, `XSAVE`, `SSE4.2`, `SSE4.1`, `SSSE3`, `SSE3`, `SSE2`,
`SSE`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel codename Westmere

|`Sandybridge`
|`AVX`, `CLMUL`, `AES`, `XSAVE`, `SSE4.2`, `SSE4.1`, `SSSE3`, `SSE3`,
`SSE2`, `SSE`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|Intel codename Sandy Bridge

|`Venice`
|`SSE3`, `SSE2`, `SSE`, `3DNow`, `MMX`, `FPU`, `SMM`, `Prot`, `Priv`
|AMD codename Venice

|`K10`, `Phenom`, `Family10h`
|`SSE4a`, `SSE3`, `SSE2`, `SSE`, `3DNow`, `MMX`, `FPU`, `SMM`, `Prot`,
`Priv`
|AMD codename K10

|`Bulldozer`
|`SSE5`, `SSE4a`, `SSE3`, `SSE2`, `SSE`, `3DNow`, `MMX`, `FPU`, `SMM`,
`Prot`, `Priv`
|AMD codename Bulldozer

|========

In order to have access to 64-bit instructions, _both_ a 64-bit
capable CPU must be selected, and 64-bit assembly mode must be set (in
NASM syntax) by either using `BITS 64` (see
<<nasm-directive-bits-top>>) or targetting a 64-bit object format such
as `elf64`.

The default CPU setting is for the latest processor and all feature
flags to be enabled; e.g. all x86 instructions for any processor,
including all instruction set extensions and 64-bit instructions.

[[arch-x86-registers]]
=== Registers

The 64-bit x86 register set consists of 16 general purpose registers,
only 8 of which are available in 16-bit and 32-bit mode.  The core
eight 16-bit registers are `AX`, `BX`, `CX`, `DX`, `SI`, `DI`, `BP`,
and `SP`.  The least significant 8 bits of the first four of these
registers are accessible via the `AL`, `BL`, `CL`, and `DL` in all
execution modes.  In 64-bit mode, the least significant 8 bits of the
other four of these registers are also accessible; these are named
`SIL`, `DIL`, `SPL`, and `BPL`.  The most significant 8 bits of the
first four 16-bit registers are also available, although there are
some restrictions on when they can be used in 64-bit mode; these are
named `AH`, `BH`, `CH`, and `DH`.

The 80386 extended these registers to 32 bits while retaining all of
the 16-bit and 8-bit names that were available in 16-bit mode.  The
new extended registers are denoted by adding a _E_ prefix; thus the
core eight 32-bit registers are named `EAX`, `EBX`, `ECX`, `EDX`,
`ESI`, `EDI`, `EBP`, and `ESP`.  The original 8-bit and 16-bit
register names map into the least significant portion of the 32-bit
registers.

64-bit long mode further extended these registers to 64 bits in size
by adding a _R_ prefix to the 16-bit name; thus the base eight 64-bit
registers are named `RAX`, `RBX`, etc.  Long mode also added eight
extra registers named numerically `r8` through `r15`.  The least
significant 32 bits of these registers are available via a _d_ suffix
(`r8d` through `r15d`), the least significant 16 bits via a _w_ suffix
(`r8w` through `r15w`), and the least significant 8 bits via a _b_
suffix (`r8b` through `r15b`).

<<x86-registers>> summarizes the full 64-bit x86 general purpose
register set.

[[x86-registers]]
.x86 General Purpose Registers
image::arch-x86/x86-registers[formats="eps,png"]

[[arch-x86-segmentation]]
=== Segmentation

indexterm:[segmentation,x86]

// vim: set syntax=asciidoc sw=2 tw=70:
