Introduction to x86 Assembly Instruction

2 minute read

這篇介紹一些基本的 intel x86 的組合語言指令,做個小筆記。

Arithmetic

  • mov: 搬移 ``` mov (destination, source)

mov eax, 0 # 把 eax 歸零 mov eax, ecx # 把 ecx 寫入 eax 中,ecx 不變

<!--more-->

- add/sun: 加/減法運算

add/sub (destination, source)

add eax, 3 # eax = eax + 3 sub eax, ecx # eax = eax - ecx

\*eax 會被寫入新的值!

- inc/dec: 遞增/遞減
- neg: 取負數

inc/dec/neg (destination)

inc eax # eax++ dec ecx # ecx– neg eax # eax = -eax


- mul/imul: 無號(unsigned)乘法/有號(signed)乘法

mul/imul (source) 它會自動把結果寫入 eax,所以沒有 destination

mul ebx # eax = eax * ebx

imul 還有其他接受 destination, source 的格式,這裡就不一一列舉

- div/idiv: 無號(unsigned)除法/有號(signed)除法

div/idiv (source) 它會把商寫入 EAX, 餘數寫入 EDX 注意他的被除數是 EDX:EAX div ebx # eax = eax / ebx


如果是 dword 的運算,被除數是 EDX:EAX,商會在 EAX, 餘數在 EDX
如果是 word 的運算,被除數是 DX:AX,商會在 AX, 餘數在 DX
如果是 byte 的運算,被除數是 AX,商會在 AL, 餘數在 AH

## Compare and Conditional Jumps

這其實就是 if-else 敘述的 assembly code,主要的概念是,先透過 cmp 進行比較,設定 EFLAGS 上的一些位元,再透過 jump 系列指令依據不同的條件跳到不同的位址(更改EIP)

- cmp: 比較並設定旗標

cmp (op1, op2)

它會嘗試 op1 - op2,但結果不會寫入任何地方,也不會影響 op1 或 op2,唯一改變的是 EFLAGS 的旗標 (如 CF, ZF...等等),通常 cmp 會搭配 conditional jump 指令使用

- jmp: 直接跳轉到某個位址,類似 goto

jmp label


- Conditional jump 系列:
其他 jump 系列的如 jle (less or equal), jng (not greater) 等等,都是藉由 EFLAGS 的旗標決定是否跳轉 

## Example

```c
for (int i = 0; i < 10; i++)
  printf("%d", i); 

編譯之後的 assembly:

0x804841c <main+17>     mov    DWORD PTR [ebp-0xc],0x0
0x8048423 <main+24>     jmp    0x804843c <main+49>
0x8048425 <main+26>     sub    esp,0x8                
0x8048428 <main+29>     push   DWORD PTR [ebp-0xc]    
0x804842b <main+32>     push   0x80484d0              
0x8048430 <main+37>     call   0x80482e0 <printf@plt> 
0x8048435 <main+42>     add    esp,0x10               
0x8048438 <main+45>     add    DWORD PTR [ebp-0xc],0x1
0x804843c <main+49>     cmp    DWORD PTR [ebp-0xc],0x9
0x8048440 <main+53>     jle    0x8048425 <main+26>
# int i = 0
0x804841c <main+17>     mov    DWORD PTR [ebp-0xc],0x0
# 先跳到 main + 49 去 compare ,因為 for loop 會先比一次
0x8048423 <main+24>     jmp    0x804843c <main+49>

# function call 的準備工作
0x8048425 <main+26>     sub    esp,0x8                
0x8048428 <main+29>     push   DWORD PTR [ebp-0xc]    
0x804842b <main+32>     push   0x80484d0              

# call printf 以及放掉 stack memory
0x8048430 <main+37>     call   0x80482e0 <printf@plt> 
0x8048435 <main+42>     add    esp,0x10               

# i++
0x8048438 <main+45>     add    DWORD PTR [ebp-0xc],0x1

# 如果 i <= 9 的話就跳到 main + 26 繼續迴圈,否則往下跑結束迴圈
0x804843c <main+49>     cmp    DWORD PTR [ebp-0xc],0x9
0x8048440 <main+53>     jle    0x8048425 <main+26>