學習內容:彙編指令/語法:
-
拷貝源運算元到目標運算元:
mov 目標運算元,源運算元
-
源運算元可以是任意單元(r/m/sr/imm) (sr:Segment Register)
-
目標運算元可以是除了立即數之外的任意單元(r/m/sr)
-
運算元的寬度必須前後一致
-
源運算元和目標運算元不能同時為記憶體單元
-
-
加/減/與/或/異或:
? add/sub/and/or/xor 目標運算元,源運算元
-
源運算元可以是r/m/imm
-
目標運算元可以是r/m
-
運算元的寬度除了源運算元是立即數的情況之外(即:立即數可以是任意位)必須前後一致
? 非:
- not r/m8 not r/m16 not r/m32
-
-
從指定記憶體中寫入/讀取資料:
mov dword ptr ds:[m],imm //寫
mov r,dword ptr ds:[r] //讀
ptr: Point 代表後面是一個指標 (指標即裡面存的不是普通的值,而是個地址) 在8086中設定4個16位的段暫存器,用於管理4種段: ①資料段---ds(Data Segment):資料段暫存器 ②程式碼段---cs(Code Segment):程式碼段暫存器 ③堆疊段---ss(Stack Segment):堆疊段暫存器 ④附加段---es(Extra Segment):附加段暫存器 BYTE 位元組 = 8(BIT) WORD 字 = 16(BIT) DWORD 雙字 = 32(BIT) 1KB = 1024 BYTE
-
定址公式
(LEA與MOV的區別在於MOV是取地址中的值,而LEA是取地址)
①[imm]形式
讀取記憶體的值 向記憶體中寫資料 讀取記憶體編號 mov r,dword ptr ds:[m] mov dword ptr ds:[m],r/imm lea r,dword ptr ds:[m] ②[r]形式
讀取記憶體的值 向記憶體中寫資料 讀取記憶體編號 mov r',imm
mov r'',dword ptr ds:[r']mov r,imm
mov dword ptr ds:[r],immlea r',dword ptr ds:[r'']
mov r',dword ptr ds:[r'']③[r+imm]形式
讀取記憶體的值 向記憶體中寫資料 讀取記憶體編號 mov r',imm
mov r'',dword ptr ds:[r'+imm]mov r,imm
mov dword ptr ds:[r+imm],immlea r,dword ptr ds:[r+imm]
mov r,dword ptr ds:[r+imm]④[r+r*(1/2/4/8)]形式
讀取記憶體的值 向記憶體中寫資料 讀取記憶體編號 mov r',imm
mov r'',imm
mov r''',dword ptr ds:[r'+r''*4]mov r',imm
mov r'',imm
mov dword ptr ds:[r'+r''*4],immlea r',dword ptr ds:[r'+r''*4] ⑤[r+r*(1/2/4/8)+imm]
讀取記憶體的值 向記憶體中寫資料 讀取記憶體編號 mov r',imm
mov r'',imm
mov r''',dword ptr ds:[r'+r''*4+8]mov r',imm
mov r'',imm
mov dword ptr ds:[r'+r''*4+8],immlea r',dword ptr ds:[r'+r''*4+8] -
壓棧與出棧
PUSH與POP的語法:PUSH:
- PUSH r16/32
- PUSH m16/32
- PUSH imm8/16/32
POP:
- POP r16/32
- POP m16/32
? 注意:
PUSH/POP加減2/4是看它PUSH/POP的是16/32位的單元? 附:
PUSHAD可將八個通用暫存器中的資料寫入記憶體中,然後即可對八個通用暫存器中的資料進行隨意更改
而更改完之後需要恢復現場,就可以用POPAD再將剛剛PUSHAD出去的八個通用暫存器中的值原封不動的還原回去 -
帶進/借位加/減法
ADC/SBB:帶 進位/借位 加/減法格式:
ADC/SBB r/m , r/m/imm 兩邊不能同時為記憶體,寬度要一樣
計算過程:
當使用ADC/SBB指令後,在執行加/減法時會先看C位暫存器的值:
①C位暫存器值為1----執行加/減法時自動多加/減1
②C位暫存器值位0----正常執行加/減法e.g.
①C位暫存器值為1MOV EAX,3
MOV ECX,1將C位暫存器值置為1
ADC EAX,ECX
將C位暫存器值置為1
SBB EAX,ECX
②C位暫存器值為0
MOV EAX,3
MOV ECX,1將C位暫存器值置為0
ADC EAX,ECX
將C位暫存器值置為0
SBB EAX,ECX
-
交換資料:
XCHG:
格式:
XCHG r/m , r/m 兩邊都必須為容器且不能同時為記憶體,寬度要一樣e.g.
XCHG AL,CL
XCHG DWORD PTR DS:[12FFC4],EAX
XCHG BYTE PTR DS:[12FFC4],AL -
移動資料:
MOVS:
即:把一塊記憶體中的資料移動到另一塊記憶體中
記憶體--記憶體(注意寬度) (唯一可以兩邊同時為記憶體單元的指令)
此指令預設操作[EDI]和[ESI]暫存器
格式:
MOVSB == MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI]
MOVSW == MOVS WORD PTR ES:[EDI],WORD PTR DS:[ESI]
MOVSD == MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
// 注意:[EDI]搭配的是PTR ES,而不是PTR DS
計算過程:
①將[ESI]中儲存的地址 對應的 記憶體中的值 賦給[EDI] 指定的記憶體
②[ESI]和[EDI]中儲存的地址同時 加/減 1/2/4
注意:
[ESI]和[EDI]中儲存地址 加/減 取決於D位暫存器的值為 0/1 -
串儲存指令
STOS(Store inTO String):
功能:
將[EAX/AX/AL]中的值存入[EDI]指定的記憶體單元(注意:不是存入[EDI]) 中 (存入的值的位數由BYTE/WORD/DWORD決定,存入後[EDI]的值加/減 由 D位暫存器的值是0/1 決定)
格式:
STOSB == STOS BYTE PTR ES:[EDI]
STOSW == STOS WORD PTR ES:[EDI]
STOSD == STOS DWORD PTR ES:[EDI] -
重複指令
REP:
功能:
按計數暫存器(ECX)中指定的次數重複執行字串指令
每執行一次,就根據D位暫存器中的值(0/1)把記憶體地址加/減1/2/4MOV ECX,10 //注意,ECX,10 中的10為十六進位制,即十進位制的16 REP MOVSD REP STOSD
-
修改[EIP]暫存器
補充[關於[EIP]]:
[EIP]中儲存的是一個地址,這個地址就是CPU下一步要去的地方,即決定了CPU即將要執行的程式碼是什麼
想要修改CPU的行為就要修改[EIP]的值
? JMP:
功能:
只修改[EIP]的值,相當於專用於[EIP]的MOV指令
格式:
JMP r/imm
注: JMP隻影響[EIP]。
完整操作簡述為:
MOV EIP,r/imm
? CALL:
功能:
修改[EIP]的值,和JMP一樣,但是CALL會修改[ESP]的值,會把下一行指令的地址壓棧,而下一行指令的地址的計算是根據CALL這一行儲存的位元組數相加得到的,然後[ESP]中的值移動到[ESP-4]的記憶體地址中,相當於把CALL的下一個地址進行一個PUSH。
格式:
CALL r/addr
注:函式的返回地址就是此處CALL壓入棧中的地址值
完整操作簡述為:
PUSH [CALL的地址+CALL行儲存的位元組數]
MOV EIP,m/addr
? RET:
功能:
回到剛剛CALL的位置,出棧,相當於一個POP,然後把CALL的下一個地址寫入[EIP]。
格式:
RET
完整操作簡述為:- LEA ESP,[ESP+4]
- MOV EIP,[ESP-4]
(=POP EIP)
-
比較指令:
? CMP:
功能:
該指令是比較兩個運算元,實際上,它相當於SUB指令,但是相減的結構並不儲存到第一個運算元中。即:在不改變任何資料的情況下,比較兩個運算元的大小,比較結果可以通過Z位、S位暫存器得到。- Z = 0 : 運算元1 ≠ 運算元2
- Z = 1 : 運算元1 = 運算元2
- S = 0 : 運算元1 > 運算元2
- S = 1 : 運算元1 < 運算元2
0001 0000 0010 0000 -0010 0000 -0001 0000 =1111 0000 =0001 0000 S=1 S=0
格式:
CMP r/m,r/m/imm
? TEST:
功能:
兩個數值進行與操作,該指令在一定程式上和CMP指令類似,結果不儲存,但是會改變相應標誌位。
格式:
TEST r/m,r/m/imm
常見用法:
用TEST指令判斷某個單元是否為0,通過Z位暫存器即可得到結果。
TEST EAX,EAX- Z = 1 : 空
- Z = 0 :非空
e.g.
標準用法MOV EAX,3
TEST EAX,3
常見用法
MOV EAX,3
TEST EAX,EAX
MOV EAX,0
TEST EAX,EAX