# x86_64
keywords: x86_64, x86, abi
- 64bit synonyms: `x86_64`, `x64`, `amd64`, `intel 64`
- 32bit synonyms: `x86`, `ia32`, `i386`
- ISA type: `CISC`
- Endianness: `little`
## Registers
### General purpose register
```markdown
bytes
[7:0] [3:0] [1:0] [1] [0] desc
----------------------------------------------------------
rax eax ax ah al accumulator
rbx ebx bx bh bl base register
rcx ecx cx ch cl counter
rdx edx dx dh dl data register
rsi esi si - sil source index
rdi edi di - dil destination index
rbp ebp bp - bpl base pointer
rsp esp sp - spl stack pointer
r8-15 rNd rNw - rNb
```
### Special register
```markdown
bytes
[7:0] [3:0] [1:0] desc
---------------------------------------------------
rflags eflags flags flags register
rip eip ip instruction pointer
```
### FLAGS register
```markdown
rflags
bits desc instr comment
--------------------------------------------------------------------------------------------------------------
[21] ID identification ability to set/clear -> indicates support for CPUID instr
[18] AC alignment check alignment exception for PL 3 (user), requires CR0.AM
[13:12] IOPL io privilege level
[11] OF overflow flag
[10] DF direction flag cld/std increment (0) or decrement (1) registers in string operations
[9] IF interrupt enable cli/sti
[7] SF sign flag
[6] ZF zero flag
[4] AF auxiliary carry flag
[2] PF parity flag
[0] CF carry flag
```
Change flag bits with `pushf` / `popf` instructions:
```x86asm
pushfd // push flags (4bytes) onto stack
or dword ptr [esp], (1 << 18) // enable AC flag
popfd // pop flags (4byte) from stack
```
> There is also `pushfq` / `popfq` to push and pop all 8 bytes of `rflags`.
### Model Specific Register (MSR)
```x86asm
rdmsr // Read MSR register, effectively does EDX:EAX <- MSR[ECX]
wrmsr // Write MSR register, effectively does MSR[ECX] <- EDX:EAX
```
## Size directives
Explicitly specify size of the operation.
```x86asm
mov byte ptr [rax], 0xff // save 1 byte(s) at [rax]
mov word ptr [rax], 0xff // save 2 byte(s) at [rax]
mov dword ptr [rax], 0xff // save 4 byte(s) at [rax]
mov qword ptr [rax], 0xff // save 8 byte(s) at [rax]
```
## Addressing
```x86asm
mov qword ptr [rax], rbx // save val in rbx at [rax]
mov qword ptr [imm], rbx // save val in rbx at [imm]
mov rax, qword ptr [rbx+4*rcx] // load val at [rbx+4*rcx] into rax
```
`rip` relative addressing:
```x86asm
lea rax, [rip+.my_str] // load addr of .my_str into rax
...
.my_str:
.asciz "Foo"
```
Load effective address:
```x86asm
mov rax, 2
lea r11, [rax + 3] // r11 <- 5
```
## String instructions
The operand size of a string instruction is defined by the instruction suffix
`b | w | d | q`.
Source and destination registers are modified according to the `direction flag
(DF)` in the `flags` register
- `DF=0` increment src/dest registers
- `DF=1` decrement src/dest registers
Following explanation assumes `byte` operands with `DF=0`:
```x86asm
movsb // move data from string to string
// ES:[DI] <- DS:[SI]
// DI <- DI + 1
// SI <- SI + 1
lodsb // load string
// AL <- DS:[SI]
// SI <- SI + 1
stosb // store string
// ES:[DI] <- AL
// DI <- DI + 1
cmpsb // compare string operands
// DS:[SI] - ES:[DI] ; set status flag (eg ZF)
// SI <- SI + 1
// DI <- DI + 1
scasb // scan string
// AL - ES:[DI] ; set status flag (eg ZF)
// DI <- DI + 1
```
String operations can be repeated:
```x86asm
rep // repeat until rcx = 0
repz // repeat until rcx = 0 or while ZF = 0
repnz // repeat until rcx = 0 or while ZF = 1
```
### Example: Simple `memset`
```x86asm
// memset (dest, 0xaa /* char */, 0x10 /* len */)
lea di, [dest]
mov al, 0xaa
mov cx, 0x10
rep stosb
```
## [SysV x86_64 ABI][sysvabi]
### Passing arguments to functions
- Integer/Pointer arguments
```markdown
reg arg
-----------
rdi 1
rsi 2
rdx 3
rcx 4
r8 5
r9 6
```
- Floating point arguments
```markdown
reg arg
-----------
xmm0 1
.. ..
xmm7 8
```
- Additional arguments are passed on the stack. Arguments are pushed
right-to-left (RTL), meaning next arguments are closer to current `rsp`.
### Return values from functions
- Integer/Pointer return values
```markdown
reg size
-----------------
rax 64 bit
rax+rdx 128 bit
```
- Floating point return values
```markdown
reg size
-------------------
xmm0 64 bit
xmm0+xmm1 128 bit
```
### Caller saved registers
Caller must save these registers if they should be preserved across function
calls.
- `rax`
- `rcx`
- `rdx`
- `rsi`
- `rdi`
- `rsp`
- `r8` - `r11`
### Callee saved registers
Caller can expect these registers to be preserved across function calls. Callee
must must save these registers in case they are used.
- `rbx`
- `rbp`
- `r12` – `r15`
### Stack
- grows downwards
- frames aligned on 16 byte boundary
```text
Hi ADDR
| +------------+
| | prev frame |
| +------------+ <--- 16 byte aligned (X & ~0xf)
| [rbp+8] | saved RIP |
| [rbp] | saved RBP |
| [rbp-8] | func stack |
| | ... |
v +------------+
Lo ADDR
```
### Function prologue & epilogue
- prologue
```x86asm
push rbp // save caller base pointer
mov rbp, rsp // save caller stack pointer
```
- epilogue
```x86asm
mov rsp, rbp // restore caller stack pointer
pop rbp // restore caller base pointer
```
> Equivalent to `leave` instruction.
## [Windows x64 ABI][winabi]
### Passing arguments to functions ([ref][winabi-args])
> A single argument is never spread across multiple registers.
- Integer/Pointer arguments
```markdown
reg arg
-----------
rcx 1
rdx 2
r8 3
r9 4
```
- Floating point arguments
```markdown
reg arg
-----------
xmm0 1
.. ..
xmm3 4
```
- Additional arguments are passed on the stack. Arguments are pushed
right-to-left (RTL), meaning next arguments are closer to current `rsp`.
[See example](https://godbolt.org/z/oT5Tjdf7Y).
### Return values from functions
- Integer/Pointer return values
```markdown
reg size
-----------------
rax 64 bit
```
- Floating point return values
```markdown
reg size
-------------------
xmm0 64 bit
```
### Caller saved registers
Caller must save these registers if they should be preserved across function
calls.
- `rax`
- `rcx`
- `rdx`
- `r8` - `r11`
- `xmm0` - `xmm5`
### Callee saved registers
Caller can expect these registers to be preserved across function calls. Callee
must must save these registers in case they are used.
- `rbx`
- `rbp`
- `rdi`
- `rsi`
- `rsp`
- `r12` - `r15`
- `xmm6` - `xmm15`
## ASM skeleton
Small assembler skeleton, ready to use with following properties:
- use raw Linux syscalls (`man 2 syscall` for ABI)
- no `C runtime (crt)`
- gnu assembler [`gas`][gas_doc]
- intel syntax
```x86asm
# file: greet.s
.intel_syntax noprefix
.section .text, "ax", @progbits
.global _start
_start:
mov rdi, 1 # fd
lea rsi, [rip + greeting] # buf
mov rdx, [rip + greeting_len] # count
mov rax, 1 # write(2) syscall nr
syscall
mov rdi, 0 # exit code
mov rax, 60 # exit(2) syscall nr
syscall
.section .rdonly, "a", @progbits
greeting:
.asciz "Hi ASM-World!\n"
greeting_len:
.int .-greeting
```
> Syscall numbers are defined in `/usr/include/asm/unistd.h`.
To compile and run:
```bash
> gcc -o greet greet.s -nostartfiles -nostdlib && ./greet
Hi ASM-World!
```
## References
- [SystemV AMD64 ABI][sysvabi]
- [AMD64 Vol1: Application Programming][amd64_vol1]
- [AMD64 Vol2: System Programming][amd64_vol2]
- [AMD64 Vol3: General-Purpose & System Instructions][amd64_vol3]
- [X86_64 Cheat-Sheet][x86_64_cheatsheet]
- [Intel 64 Vol1: Basic Architecture][intel64_vol1]
- [Intel 64 Vol2: Instruction Set Reference][intel64_vol2]
- [Intel 64 Vol3: System Programming Guide][intel64_vol3]
- [GNU Assembler][gas_doc]
- [GNU Assembler Directives][gas_directives]
- [GNU Assembler `x86_64` dependent features][gas_x86_64]
- [`juicebox-asm` an `x86_64` jit assembler playground][juicebox]
[sysvabi]: https://gitlab.com/x86-psABIs/x86-64-ABI
[winabi]: https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions
[winabi-args]: https://learn.microsoft.com/en-us/cpp/build/x64-calling-convention
[amd64_vol1]: https://www.amd.com/system/files/TechDocs/24592.pdf
[amd64_vol2]: https://www.amd.com/system/files/TechDocs/24593.pdf
[amd64_vol3]: https://www.amd.com/system/files/TechDocs/24594.pdf
[x86_64_cheatsheet]: https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf
[intel64_vol1]: https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-software-developers-manual-volume-1-basic-architecture.html
[intel64_vol2]: https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-2a-2b-2c-and-2d-instruction-set-reference-a-z.html
[intel64_vol3]: https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-3a-3b-3c-and-3d-system-programming-guide.html
[gas_doc]: https://sourceware.org/binutils/docs/as
[gas_directives]: https://sourceware.org/binutils/docs/as/Pseudo-Ops.html#Pseudo-Ops
[gas_x86_64]: https://sourceware.org/binutils/docs/as/i386_002dDependent.html
[juicebox]: https://github.com/johannst/juicebox-asm