aboutsummaryrefslogblamecommitdiffhomepage
path: root/src/arch/x86_64.md
blob: d752b09b168983616b7bb88c528f4fb559f3b646 (plain) (tree)
1
2
3
4
5
6
7
8
        





                                                      
 














                                                          
                                    














                                                   





                                                                                                              
                                                                                                                  




























                                                                           


             



                                                                    


                          
         





                                                             





                                







                                                                              
 
                                                          
         





































                                                         

   
                             


















                                  
             
     

                                                                          








                                
                              




























                                                                               
         







                                                                  
         

     












                                                 

























































                                                                               




















                                                                 
                                                        















                                                             
             
                              


                                                                 



                                                          

                                            
                                                         
                                                                 


                                                       

                                                                                 



                                                                                      


                                                                                                                                                                                      
                                                  
                                                                                    
                                                                             
                                                    
# 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://www.uclibc.org/docs/psABI-x86_64.pdf
[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