# Instructions

As x86-64 is a CISC architecture, it has a vast range of different instructions ([about \~980](https://stefanheule.com/blog/how-many-x86-64-instructions-are-there-anyway/), not counting different operand types for the same instruction), varying in complexity. Below are some of the most commonly used/most important instructions, grouped by functionality. For those interested in a more extensive set of instructions, the official [Intel Manual](http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html) is a nice (and with \~5,000 pages fairly light) read.

Note that a `.` postfix is a placeholder for a size indicator, so either `b`(byte), `w` (word), `l` (long), or `q` (quadword). Some instructions allow only a subset of these postfixes.

{% tabs %}
{% tab title="Data Transfer" %}
<table><thead><tr><th width="129">Mnemonic</th><th width="109">Operands</th><th>Action</th></tr></thead><tbody><tr><td>mov.</td><td>SRC, DST</td><td>DST = SRC</td></tr><tr><td>push.</td><td>SRC</td><td><code>rsp</code> -= &#x3C;#bytes>; (<code>rsp</code>) = SRC</td></tr><tr><td>pop.</td><td>DST</td><td>DST = (<code>rsp</code>); <code>rsp</code> += &#x3C;#bytes></td></tr><tr><td>xchg.</td><td>A, B</td><td>TMP = A; A = B; B = TMP</td></tr><tr><td>movzb.</td><td>SRC, DST</td><td>DST = SRC (one byte only, higher-order bits set to zero)</td></tr><tr><td>movzw.</td><td>SRC, DST</td><td>DST = SRC (one word only, higher-order bits set to zero)</td></tr><tr><td>lea.</td><td>A, DST</td><td>DST = &#x26;A (address of A)</td></tr></tbody></table>
{% endtab %}

{% tab title="Arithmetic" %}
<table><thead><tr><th width="129">Mnemonic</th><th width="123">Operands</th><th>Action</th></tr></thead><tbody><tr><td>add.</td><td>SRC, DST</td><td>DST = DST + SRC</td></tr><tr><td>sub.</td><td>SRC, DST</td><td>DST = DST - SRC</td></tr><tr><td>inc.</td><td>DST</td><td>DST = DST + 1</td></tr><tr><td>dec.</td><td>DST</td><td>DST = DST - 1</td></tr><tr><td>mul.</td><td>SRC</td><td><code>rdx</code>:<code>rax</code> = <code>rax</code> * SRC (unsigned)</td></tr><tr><td>imul.</td><td>SRC</td><td><code>rdx</code>:<code>rax</code> = <code>rax</code> * SRC</td></tr><tr><td>imul.</td><td>SRC, DST</td><td>DST = SRC * DST</td></tr><tr><td>imul.</td><td>C, SRC, DST</td><td>DST = C * SRC</td></tr><tr><td>(i)div.</td><td>SRC</td><td><code>rax</code> = <code>rdx</code>:<code>rax</code> / SRC;<br><code>rdx</code> = <code>rdx</code>:<code>rax</code> % SRC</td></tr></tbody></table>

{% hint style="info" %}
`rdx:rax` represents a 128-bit value where the most significant 64 bits are in `rdx` and the least significant 64 bits are in `rax`
{% endhint %}
{% endtab %}

{% tab title="Logic and Shift" %}
<table><thead><tr><th width="129">Mnemonic</th><th width="109">Operands</th><th>Action</th></tr></thead><tbody><tr><td>cmp.</td><td>A, B</td><td>B - A (only set flags)</td></tr><tr><td>or.</td><td>SRC, DST</td><td>DST = SRC | DST (bitwise)</td></tr><tr><td>and.</td><td>SRC, DST</td><td>DST = SRC &#x26; DST (bitwise)</td></tr><tr><td>xor.</td><td>SRC, DST</td><td>DST = SRC ^ DST (bitwise)</td></tr><tr><td>neg.</td><td>DST</td><td>DST = !DST (bitwise)</td></tr><tr><td>shl.</td><td>C, DST</td><td>DST = DST &#x3C;&#x3C; C (overflowing bits discarded)</td></tr><tr><td>shr.</td><td>C, DST</td><td>DST = DST >> C (underflowing bits discarded)</td></tr><tr><td>rol.</td><td>C, DST</td><td>DST = DST &#x3C;&#x3C; C (overflowing bits become least sig. bits)</td></tr><tr><td>ror.</td><td>C, DST</td><td>DST = DST >> C (underflowing bits become most sig. bits)</td></tr></tbody></table>
{% endtab %}

{% tab title="Program Flow" %}
<table><thead><tr><th width="129">Mnemonic</th><th width="115">Operands</th><th>Action</th></tr></thead><tbody><tr><td>call</td><td>ADDR</td><td>jump to ADDR and push return address</td></tr><tr><td>ret</td><td></td><td>pop address and jump to it</td></tr><tr><td>cmp.</td><td>A, B</td><td>B - A (only set flags, see below)</td></tr><tr><td>test.</td><td>A, B</td><td>A &#x26; B (only set flags, see below)</td></tr></tbody></table>

All conditional branch instructions (except `jrcxz`, `jecxz`, and `jcxz`) use the state of the processor flags to decide whether or not to perform the jump. The flags are (among others) set through the result of arithmetic instructions (like `cmp` or `test`). x86-64 processors have a large set of flags, below are the ones commonly used for conditional jumps:

* **Carry Flag (CF):** set on high-order bit carry or borrow (cleared otherwise)
* **Parity Flag (PF):** set if low-order 8 bits contain an even number of '1' bits (cleared otherwise)
* **Zero Flag (ZF):** set if the result is zero (cleared otherwise)
* **Sign Flag (SF):** set to equal high-order bit of result
* **Overflow Flag (OF):** set if the result is too large of a positive number or too small of a negative number (excluding sign bit) to fit the destination operand (cleared otherwise)

All following instructions take the location to jump to as their only operand.

<table><thead><tr><th width="146">Mnemonic</th><th>Condition</th><th width="165" align="center">Flags</th></tr></thead><tbody><tr><td>jmp</td><td></td><td align="center"></td></tr><tr><td>jo</td><td>overflow</td><td align="center">OF</td></tr><tr><td>jno</td><td>no overflow</td><td align="center">!OF</td></tr><tr><td>js</td><td>sign bit (negative number)</td><td align="center">SF</td></tr><tr><td>jns</td><td>no sign bit</td><td align="center">!SF</td></tr><tr><td>je / jz</td><td>equal / zero</td><td align="center">ZF</td></tr><tr><td>jne / jnz</td><td>not equal / not zero</td><td align="center">!ZF</td></tr><tr><td>jb / jnae / jc</td><td>below / not above or equal / carry (unsigned)</td><td align="center">CF</td></tr><tr><td>jnb / jae / jnc</td><td>not below / above or equal / not carry (unsigned)</td><td align="center">!CF</td></tr><tr><td>jbe / jna</td><td>below or equal / not above (unsigned)</td><td align="center">CF or ZF</td></tr><tr><td>ja/ jnbe</td><td>above / not below or equal (unsigned)</td><td align="center">!CF and !ZF</td></tr><tr><td>jl / jnge</td><td>less / not greater or equal (signed)</td><td align="center">SF != OF</td></tr><tr><td>jge / jnl</td><td>greater or equal / not less (signed)</td><td align="center">SF = OF</td></tr><tr><td>jle / jng</td><td>less or equal / not greater (signed)</td><td align="center">ZF or (SF != OF)</td></tr><tr><td>jg / jnle</td><td>greater / not less or equal (signed)</td><td align="center">!ZF and (SF = OF)</td></tr><tr><td>jp / jpe</td><td>parity / parity even</td><td align="center">PF</td></tr><tr><td>jnp / jpo</td><td>not parity / parity odd</td><td align="center">!PF</td></tr><tr><td>jrcxz</td><td>rcx register is 0 (loop counter at 0)</td><td align="center"><code>rcx</code> = 0</td></tr><tr><td>jecxz</td><td>ecx register is 0 (loop counter at 0)</td><td align="center"><code>ecx</code> = 0</td></tr><tr><td>jcxz</td><td>cx register is 0 (loop counter at 0)</td><td align="center"><code>cx</code> = 0</td></tr></tbody></table>
{% endtab %}
{% endtabs %}

***

## Addressing Modes

The x86-64 architecture allows for many different (memory) addressing modes. Below are some of the most commonly used:

<table data-full-width="false"><thead><tr><th width="150">Name</th><th width="304">Syntax</th><th width="411">Description</th></tr></thead><tbody><tr><td>Immediate</td><td><pre class="language-nasm"><code class="lang-nasm">movq $1, %rax
</code></pre></td><td>move <strong>the a value</strong> <code>1</code> into the register <code>rax</code></td></tr><tr><td>Register</td><td><pre class="language-nasm"><code class="lang-nasm">movq %rdi, %rax
</code></pre></td><td>move (copy) <strong>the contents</strong> (8 bytes) from the register <code>rdi</code> into the register <code>rax</code></td></tr><tr><td>Indirect</td><td><pre class="language-nasm"><code class="lang-nasm">movq (%rdi), %rax
</code></pre></td><td>move 8 bytes <strong>from memory</strong> starting at the address stored in <code>rdi</code> into the register <code>rax</code></td></tr><tr><td>Base and Displacement</td><td><pre class="language-nasm"><code class="lang-nasm">movq -8(%rdi), %rax
</code></pre></td><td>move 8 bytes <strong>from memory</strong> starting at the address:<br><code>rdi - 8</code> into the register <code>rax</code><br><br>The displacement may be any positive or negative value.</td></tr><tr><td>Base and Index</td><td><pre class="language-nasm"><code class="lang-nasm">movq (%rdi, %rbx), %rax
</code></pre></td><td>move 8 bytes <strong>from memory</strong> starting at the address:<br><code>rdi + rbx</code> into the register <code>rax</code></td></tr><tr><td>Base, Index, and Scale</td><td><pre class="language-nasm"><code class="lang-nasm">movq (%rdi, %rbx, 4), %rax
</code></pre></td><td><p>move 8 bytes <strong>from memory</strong> starting at the address:<br><code>rdi + (rbx * 4)</code> into the register <code>rax</code></p><p><br>The scale factor may be <strong>either 1, 2, 4, or 8.</strong></p></td></tr><tr><td>Base, Index, Scale, and Displacement</td><td><pre class="language-nasm"><code class="lang-nasm"><strong>movq 16(%rdi, %rbx, 4), %rax
</strong></code></pre></td><td><p>move 8 bytes <strong>from memory</strong> starting at the address:<br><code>rdi + (rbx * 4) + 16</code> into the register <code>rax</code><br></p><p>The displacement may be any positive or negative value.</p></td></tr></tbody></table>

### Note on Order of Operands

For all of these modes, except _Immediate_, the order of operands given in the example may also be reversed (to use the addressing for the destination instead of the source operand). However, **at least one of the operands needs to be a register or intermediate value**, so the following would not be a valid instruction:

```nasm
movq    (%rax), (%rdi)
```

as both the source and destination operands are memory locations.
