# x86 Assembly ## Register ![](https://i.imgur.com/NO6rQgU.png) ### General puspose - rax (accumulator) - rbx (base) - rcx (count) - rdx (data) - rsi (source index) - rdi (destination index) - rbp (base pointer) - rsp (stack pointer) - rip (instruction pointer) > rip could not be dest. 用於記錄下一個要執行的instruction ### r[a-d]x register layout ``` +----------+ | | | | +----------+ 0 63 ``` - r[a-d]x (64 bits) - e[a-d]x (32 bits) - [a-d]x (16 bits) - [a-d]h (8 bits) - [a-d]l (8 bits) ### Stack ![](https://i.imgur.com/3crJlom.png) 由兩個 register (rsp 與 rbp) 指向的記憶體空間,用來記錄: - return address - local variable 一開始 rbp 與 rsp 的位址相同 ```assembly= push rbp mov rbp, rsp ``` 這時如果 push 一組資料進來, rsp 會往 low address 前進 (rsp 存放的位址會越來越小)。 ### push and pop - push: 將資料放進 stack ```assembly= push rax ``` 將 rax 的 value 放進 stack 。 - pop: 將最上層資料捨棄 ```assembly= pop rcx ``` 將上層資料存到 rcx 並捨棄上層資料。 ```assembly= pop word [rbx] ``` 將上層資料存到 rbx 存放的地址(也就是 *rbx) 並捨棄上層資料。 ### function call 假設 `main()` 函式呼叫了 `funcA()` , Stack 與相關暫存器的變化如下: 1. 將 return address (回到 `main()`) 推入 stack: ![](https://i.imgur.com/X6Z27td.png) 2. 接著我們會將 `main()` 的 rbp 推入 stack : ```assembly= push rbp ``` ![](https://i.imgur.com/p358u2C.png) 3. 將 rbp 移動到 rsp 的位址: ```assembly= mov rbp, rsp ``` ![](https://i.imgur.com/CQAG5CE.png) 4. 分配空間給 `funcA()` (也就是將 rsp 向下移動): ```assembly= sub rsp, 0x10 ``` ![](https://i.imgur.com/4meL6L3.png) 5. 等到 `funcA()` return 時,會呼叫 leave : ```assembly= mov rsp, rbp pop rbp ``` ![](https://i.imgur.com/Dz6e9Sm.png) ![](https://i.imgur.com/IASVhQL.png) 6. 這時 rsp 已經指向 main 的 return address 了,接著呼叫 ret 時,rip 就會指向 return address,並且將 stack frame 的狀態回復到 main 的 stack frame 。 ### instruction syntax - syntax ```assembly= mov dest, source ``` - example - `mov rax, rbx` 等於 `rax = rbx` - `mov rax, [rbx-4]` 等於 `rax = *(rbp-4)` - `mov [rax], rbx` 等於 `*rax = rbx` - `lea eax,[ebx+8]` 等於 `eax = (ebx+8)` ### [運算指令](https://zh.m.wikibooks.org/zh-tw/X86_%E6%B1%87%E7%BC%96/%E7%AE%97%E6%9C%AF) - add - sub - imul 有號乘法 - idiv 有號除法 - and - or - xor - neg (x = -x) - not - inc (x = x + 1) - dec ### 型態 - byte: 1 byts - word: 2 bytes - dword: 4 bytes - qword: 8 bytes 舉例: ```assembly= mov byte [rcx], 0x61 mul word [rax], 0x87 inc dword [rbp] not qword [rsp] ``` > **注意!**: > dest 與 source 的型態需要相同 ### Compare 與 Flag ```assembly= cmp val1, val2 ``` 會比較 val1 與 val2 是否相等,並將結果存到 flag register 當中。 > 一般來說會搭配 [jump 指令](https://www.felixcloutier.com/x86/jcc)。 ### [system call](https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/) ### conditional statement 1. if/else ```c= if(rax < 5){ // ... } else if (rax >= 5 && rax < 10){ // ... } else{ // ... } ``` 轉換成 x86 組合語言: ```assembly= cmp rax, 5 jae Lelseif ; do something jmp Lend Lelseif: cmp rax, 10 jae Lelse ; do something jmp Lend Lelse: ; do something Lend: ``` 2. loop ```c= for (int i = 0; i < 10; i++){ } ``` 轉換成 x86 組合語言: ```assembly= mov rcx, 0 loop: cmp rcx, 10 jae lend ; do something... inc rcx jump loop lend: ``` ### funtion parameter (x86_64) function 的參數會依序傳給: - rdi, rsi, rdx, rcx, r8, r9 - 如果超過 6 個參數,通通丟到 Stack 內 ## Reference - [BambooFox 社課](https://www.youtube.com/watch?v=h_OoO_YhtAE) - [你所不知道的 C 語言: 函式呼叫篇](https://hackmd.io/@dange/rk9xmgHKX?type=view)