1. 數據傳輸指令
1). 操作數類型
[label:] mnemonic [operands][; comment]
指令可以有零個,一個,兩個或者三個操作數。此處忽略label和comment, 如下:
mnemonic
mnemonic [destination]
mnemonic [destination],[source]
mnemonic [destination],[source-1],[source-2]
操作輸的基本類型:
- 立即數: 使用數字文本表達式
- 寄存器: CPU中的寄存器
- 內存: 直接引用內存地址
2). 直接內存操作數
| 操作數 | 描述 |
|---|---|
| reg8 | 8位普通用途的寄存器:AH, AL, BH, BL, CH, CL, DH, DL |
| reg16 | 16位普通用途的寄存器:AX, BX, CX, DX, SI, DI, SP, BP |
| reg32 | 32位普通用途的寄存器:EAX, EBX, ECX, EDX, ESI, EDI, ESP, EBP |
| reg | 任何普通用途的寄存器 |
| sreg | 16位段寄存器:CS, DS, SS, ES, FS, GS |
| imm | 8,16,32位立即數 |
| imm8 | 8位字節(jié)立即數 |
| imm16 | 16位字立即數 |
| imm32 | 32位雙字立即數 |
| reg/mem8 | 8位操作數,可以是8位普通寄存器或內存字節(jié) |
| reg/mem16 | 16位操作數,可以是16位普通寄存器或內存字節(jié) |
| reg/mem32 | 32位操作數,可以是32位普通寄存器或內存字節(jié) |
| mem | 8,16,32內存操作數 |
3). MOV 指令
- 功能:MOV指令從源操作數賦值數據到目標操作數中。
- 格式:
MOV destination,source
-
操作數規(guī)則
- 兩個操作數必須是相同的大小
- 兩個操作數不能是內存操作數
- 指令指針寄存器(IP, EIP, RIP)不能作為目標操作數
MOV reg,reg
MOV mem,reg
MOV reg,mem
MOV mem,imm
MOV reg,imm
- 覆蓋值
.data
oneByte BYTE 78h ; 定義一個8bit變量
oneWord WORD 1234h ; 定義一個16bit變量
oneDword DWORD 12345678h ; 定義一個32bit變量
.code
main PROC ; 定義主函數開始位置
mov eax, 0 ; 為eax寄存器賦值 -- EAX = 0000 0000h
mov al, oneByte ; 為al賦值 -- EAX = 0000 0078h
mov ax, oneWord ; 為ax賦值 -- EAX = 0000 1234h
mov eax, oneDword ; 為eax賦值 -- EAX = 1234 5678h
mov ax, 0 ; 為ax賦值 -- EAX = 1234 0000h
4). 整數0和符號的擴展
- 問題
主要原因:占用字節(jié)空間大的寄存器低字節(jié)賦值時,高字節(jié)為做更改
解決方法:第一種用MOVZX指令代替,第二種用MOVSX代替
COMMENT &
第一種情況是將小位數的數賦值給大位數的寄存器時,未賦值的高字節(jié)未置空
第二種情況是將小位數的負數賦值給大位數的寄存器時,為賦值的高字節(jié)未置F
&
.data
count WORD 10 ; 定義變量
signedVar SWORD -16 ; 定義負數
.code
main PROC ; 定義主函數開始位置
mov ecx, 100000 ; 為ecx寄存器賦值,此時ECX = 000186A0
mov cx, count ; 為ecx寄存器賦值,此時ECX = 0001000A
mov cx, signedVar ; 為ecx寄存器賦值,此時ECX = 0001FFF0,解決方法之一:可在此之前將ecx設置為FFFF FFFFh
- MOVZX 指令
功能:賦值源操作數的內容到目標操作數,為16位或32位的值進行0的擴展。這個指令僅被使用在無符號整型中, 作用域:
MOVZX reg32,reg/mem8
MOVZX reg32,reg/mem16
MOVZX reg16,reg/mem8
示例:
COMMENT &
MOVZX 解決0擴展問題
&
.data
byte1 BYTE 9Bh ; 定義字節(jié)變量
word1 WORD 0A69Bh ; 定義字變量
.code
main PROC ; 定義主函數開始位置
; 寄存器->寄存器
mov bx, 0A69Bh ; 為bx賦值 ebx = 7EFD A69Bh
movzx eax, bx ; 將bx的值賦值給eax, eax = 76AB 342Bh -> eax = 0000 A69Bh
movzx edx, bl ; 將bl的值賦值給edx, edx = 00F9 1005h -> edx = 0000 009Bh
movzx cx, bl ; 將bl的值賦值給cx, ecx = 0000 0000h -> ecx = 0000 009Bh

圖1.png
- MOVSX 指令
功能:賦值源操作數的內容到目標操作數,為16位或32位的值進行符號的擴展。這個指令僅被使用在有符號整型中, 作用域:
MOVSX reg32,reg/mem8
MOVSX reg32,reg/mem16
MOVSX reg16,reg/mem8
示例:
COMMENT &
MOVZX 解決符號擴展問題
&
.data
byteVal BYTE 10001111b ; 定義字節(jié)變量
.code
main PROC ; 定義主函數開始位置
; 內存 -> 寄存器
movsx ax, byteVal ; 將byteVal的值賦值給ax寄存器,ax = 342Bh -> ax = FF8Fh
; 寄存器->寄存器
mov bx, 0A69Bh ; 為bx賦值,bx = E000h -> bx = A69Bh
movsx eax, bx ; 將bx的值賦值給eax, eax = 76AB FF8Fh -> eax = FFFF A69Bh
movsx edx, bl ; 將bl的值賦值給edx, edx = 0035 1005h -> edx = FFFF FF9Bh
movsx cx, bl ; 將bl的值賦值給cx, cx = 0000h -> cx = FF9Bh

圖2.png
5). LAHF和SAHF--EFlags狀態(tài)
COMMENT &
LANF加載EFLAGS值到AH,SANF保存AH值
&
.data
saveflags BYTE ? ; 定義保存flag的變量
newflags BYTE ? ; 定義新的flag的值
.code
main PROC ; 定義主函數開始位置
lahf ; 加載flag到ah eax = 76AB462Bh
mov saveflags, ah ; 將ah的數值保存到flag中 saveflags = 70
mov saveflags, 100 ; 賦值 saveflags = 100
mov ah, saveflags ; 賦值 eax = 76AB642Bh
sahf ; 保存
6). XCHG指令
功能:交換兩個操作數的內容。形式:
XCHG reg,reg
XCHG reg,mem
XCHG mem,reg
注:XCHG不接立即數操作數。
COMMENT &
XCHG,交換數值
&
.data
val1 WORD 10 ; 定義變量1
val2 WORD 20 ; 定義變量2
.code
main PROC ; 定義主函數開始位置
; 交換val1 和 val2的數值
mov ax, val1 ; 將val1的值存入ax中
xchg ax, val2 ; 交換ax與val2的值
mov val1, ax ; 將ax的值放入val1中
7). 直接偏移操作數
功能: 為數組變量名添加一個移位。
COMMENT &
直接偏移操作數,訪問數組元素
&
.data
arrayB BYTE 10h, 20h, 30h, 40h, 50h ; 定義字節(jié)數組元素
arrayW WORD 100h, 200h, 300h ; 定義字數組元素
arrayD DWORD 10000h, 20000h ; 定義雙字數組元素
.code
main PROC ; 定義主函數開始位置, eax = 76AB342Bh
mov al, [arrayB + 3] ; 訪問BYTE數組第4個元素, eax = 76AB3440h
mov ax, [arrayW + 2 * 2] ; 訪問WORD數組第3個元素, eax = 76AB0300h
mov eax, [arrayD + 4 * 1] ; 訪問DWORD數組第2個元素, eax = 00020000h
8). 綜合示例
.486 ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall ; 選擇程序的內存模式為平坦模式,stdcall調用習慣
.stack 4096 ; 設置運行的堆棧大小為4096字節(jié)
ExitProcess PROTO, dwExitCode: DWORD
COMMENT &
直接偏移操作數,訪問數組元素
&
.data
val1 WORD 1000h
val2 WORD 2000h
arrayB BYTE 10h, 20h, 30h, 40h, 50h ; 定義字節(jié)數組元素
arrayW WORD 100h, 200h, 300h ; 定義字數組元素
arrayD DWORD 10000h, 20000h ; 定義雙字數組元素
.code
main PROC ; 定義主函數開始位置
; MOVZX 指令示范
mov bx, 0A69Bh
movzx eax, bx ; eax = 0000 A69Bh
movzx edx, bl ; edx = 0000 009Bh
movzx cx, bl ; cx = 009Bh
; MOVSZ 指令示范
mov bx, 0A69Bh
movsx eax, bx ; eax = FFFF A69Bh
movsx edx, bl ; edx = FFFF FF9Bh
mov bl, 7Bh
movsx cx, bl ; cx = 007Bh
; 內存 -> 內存 數值交換
mov ax, val1 ; ax = 1000h
xchg ax, val2 ; ax = 2000h, val2 = 1000h
mov val1, ax ; val1 = 2000h
; 直接偏移地址(BYTE數組)
mov al, arrayB ; al = 10h
mov al, [arrayB + 1] ; al = 20h
mov al, [arrayB + 2] ; al = 30h
; 直接偏移地址(WORD數組)
mov ax, arrayW ; ax = 100h
mov ax, [arrayW + 2] ; ax = 200h
; 直接偏移地址(DWORD數組)
mov eax, arrayD ; eax = 0001 0000h
mov eax, [arrayD + 4] ; eax = 0002 0000h
INVOKE ExitProcess, 0 ; 退出程序
main ENDP ; 函數結束位置, ENDP 之前的內容,要與PROC
END main ; 設置了函數的入口與出口
2. 加與減
1). INC與DEC指令
- 作用域:
INC reg/mem
DEC reg/mem
- 示例代碼:
COMMENT &
加減運算
&
.data
myWord WORD 1000h
.code
main PROC ; 定義主函數開始位置
inc myWord ; myWord變量自加 myWord = 1001h
mov bx, myWord ; 將bx值設置為myWord bx = 1001h
dec bx ; bx值進行自減 bx = 1000h
2). ADD 指令
- 使用方法:
ADD dest,source
COMMENT &
加減運算
&
.data
var1 DWORD 10000h
var2 DWORD 20000h
.code
main PROC ; 定義主函數開始位置
mov eax, var1 ; 將var1的值賦值給eax, eax = 10000h
add eax, var2 ; 將var2的值與eax的值相加, eax = 30000h
3). SUB 指令
- 使用方法:
SUB dest,source
COMMENT &
加減運算
&
.data
var1 DWORD 10000h
var3 DWORD 30000h
.code
main PROC ; 定義主函數開始位置
mov eax, var3 ; 將var3的值賦值給eax, eax = 30000h
sub eax, var1 ; 將eax的值減去1000h, eax = 20000h
4). NEG 指令
- 使用方法:
NEG reg/mem
COMMENT &
加減運算
&
.data
var1 DWORD 10000h
var3 DWORD 30000h
.code
main PROC ; 定義主函數開始位置
mov eax, var3 ; 將var3的值賦值給eax, eax = 30000h
sub eax, var1 ; 將eax的值減去1000h, eax = 20000h
neg eax ; eax由20000h取反+1為FFFE0000
5). 實現算術表達式
- 示例代碼:
COMMENT &
加減運算
&
.data
Rval DWORD ?
Xval DWORD 26
Yval DWORD 30
Zval DWORD 40
.code
main PROC ; 定義主函數開始位置
; Rval = -Xval + (Yval - Zval)
; 第一步: -Xval
mov eax, Xval
neg eax ; eax = -26
; 第二步:(Yval - Zval)
mov ebx, Yval
sub ebx, Zval ; ebx = -10
; 第三步:計算Rval
add eax, ebx
mov Rval, eax ; Rval = -36
6). 標志位測試
.code
main PROC ; 定義主函數開始位置
; ZF 零標志位示例
mov cx, 1
sub cx, 1 ; ZF = 1
mov ax, 0FFFFh
inc ax ; ZF = 1
; SF 符號標志位示例
mov cx, 0
sub cx, 1 ; SF = 1
mov ax, 7FFFh
add ax, 2 ; SF = 1
; CF 進位標志位示例
mov al, 0FFh
add al, 1 ; CF = 1, al = 00h
; OF 溢出標志位示例
mov al, +127
add al, 1 ; OF = 1
mov al, -128
sub al, 1 ; OF = 1
3. 數據相關的運算符和指令
1). OFFSET 操作數
功能:獲取偏移地址
COMMENT &
數據相關的運算符和指令運算
&
.data
bVal BYTE ?
wVal WORD ?
dVal DWORD ?
dVal2 DWORD ?
myArray WORD 1, 2, 3, 4, 5
.code
main PROC ; 定義主函數開始位置
; OFFSET 偏移
mov esi, OFFSET bVal ; ESI = 00904000h
mov esi, OFFSET wVal ; ESI = 00904001h
mov esi, OFFSET dVal ; ESI = 00904003h
mov esi, OFFSET dVal2 ; ESI = 00904007h
mov esi, OFFSET myArray + 4 ; ESI = 0090400Fh
2). ALIGN 指令
功能:對齊字節(jié)大小,將小字節(jié)內存向大字節(jié)內存靠攏
.data
; ALIGN 對齊
bVal1 BYTE ? ; 00404000h
ALIGN 2
wVal1 WORD ? ; 00404002h
bVal2 BYTE ? ; 00404004h
3). PTR 操作數
功能:將大字節(jié)的變量轉換為小字節(jié)的變量,將小字節(jié)的數組拼接為打字節(jié)的變量
.data
myDouble DWORD 12345678h
wordList WORD 5678h, 1234h
.code
main PROC ; 定義主函數開始位置
; PTR 指針
mov ax, WORD PTR myDouble ; ax = 5678h
mov ax, WORD PTR [myDouble + 2] ; ax = 1234h
mov eax, DWORD PTR wordList ; eax = 12345678h
4). TYPE 操作數
功能:返回變量的所占用的字節(jié)大小
.data
bVal BYTE ?
wVal WORD ?
dVal DWORD ?
.code
main PROC ; 定義主函數開始位置
; TYPE 獲取變量所占內存大小
mov eax, TYPE bVal ; eax = 0000 0001h
mov eax, TYPE wVal ; eax = 0000 0002h
mov eax, TYPE dVal ; eax = 0000 0004h
5). LENGTHOF 操作數
功能:獲取數組長度
.data
byte1 BYTE 10, 20, 30
array1 WORD 30 DUP(?), 0, 0
array2 WORD 5 DUP(3 DUP(?))
array3 DWORD 1, 2, 3, 4
digitStr BYTE "12345678", 0
.code
main PROC ; 定義主函數開始位置
; LENGTHOF 計算數組長度
mov eax, LENGTHOF byte1 ; eax = 0000 0003h
mov eax, LENGTHOF array1 ; eax = 0000 0020h
mov eax, LENGTHOF array2 ; eax = 0000 000Fh
mov eax, LENGTHOF array3 ; eax = 0000 0004h
mov eax, LENGTHOF digitStr ; eax = 0000 0009h
6). SIZEOF 操作數
功能:計算變量所占用的位數
.data
intArray WORD 32 DUP(0)
.code
main PROC ; 定義主函數開始位置
; SIZEOF 計算所占用的字節(jié)位數
mov eax, SIZEOF intArray ; eax = 0000 0040h
7). LABEL 指令
**功能:設置別名,使用內存地址訪問之后定義的變量 **
.data
val16 LABEL WORD
val32 DWORD 12345678h
LongValue LABEL DWORD
val1 WORD 5678h
val2 WORD 1234h
.code
main PROC ; 定義主函數開始位置
; LABEL 地址訪問
mov ax, val16 ; ax = 1234h
mov dx, [val16 + 2] ; dx = 5678h
mov eax, LongValue ; eax = 1234 5678h
4. 間接尋址
1). 間接操作數
功能:使用地址訪問對應的地址的數值
- 保護模式
.data
byteVal BYTE 10h
.code
main PROC ; 定義主函數開始位置
; 間接操作
mov esi, OFFSET byteVal
mov al, [esi]
- 使用PTR間接操作
inc BYTE PTR [esi]
2). 數組
.data
arrayW WORD 1000h, 2000h, 3000h
.code
main PROC ; 定義主函數開始位置
; 數組
mov esi, OFFSET arrayW
mov ax, [esi] ; ax = 1000h
add esi, 2
mov ax, [esi] ; ax = 2000h
add esi, 2
mov ax, [esi] ; ax = 3000h
3). 索引操作數
- 表現形式
constant[reg]
[constant + reg]
示例:
.data
arrayB BYTE 10h, 20h, 30h
.code
main PROC ; 定義主函數開始位置
; 索引操作數
mov esi, 0
mov al, arrayB[esi] ; al = 10h
- 添加位移
.data
arrayW WORD 1000h, 2000h, 3000h
.code
main PROC ; 定義主函數開始位置
; 添加位移
mov esi, OFFSET arrayW
mov ax, [esi] ; ax = 1000h
mov ax, [esi + 2] ; ax = 2000h
mov ax, [esi + 4] ; ax = 3000h
- 使用16位寄存器
mov al,arrayB[si]
mov ax,arrayW[di]
mov eax,arrayD[bx]
- 索引操作數中的比例因子
.data
arrayD DWORD 100h, 200h, 300h, 400h
.code
main PROC ; 定義主函數開始位置
; 索引操作數中的比例因子
mov esi, 3 * TYPE arrayD
mov eax, arrayD[esi] ; eax = 0000 0400h
4). 指針
概念:一個變量存儲另一個變量的地址
.data
arrayB BYTE 10h,20h,30h,40h
ptrB DWORD arrayB
- TYPEDEF 操作數
功能:用戶可自定義類型名
PBYTE TYPEDEF PTR BYTE
5. JMP 和 LOOP 指令
1). JMP 指令
-
功能
一種非傳統的傳遞,類似于C語言中的goto語句
語法
JMP destination
- 創(chuàng)建循環(huán)
top:
.
.
jmp top
2). LOOP 指令
- 功能
一種非傳統的傳遞,類似于C語言中的循環(huán)語句
- 語法
LOOP destination
- 循環(huán)
mov ax,0
mov ecx,5
L1:
inc ax
loop L1
每次循環(huán)為ax自加1,ecx進行自減,循環(huán)結束時,ax=5,ecx=0
- 循環(huán)內部修改ECX的值
.data
count DWORD ?
.code
mov ecx,100 ; 設置循環(huán)計數
top:
mov count,ecx ; 保存循環(huán)計數
.
mov ecx,20 ; 修改ECX
.
mov ecx,count ; 恢復循環(huán)計數
loop top
- 嵌套循環(huán)
.data
count DWORD ?
.code
mov ecx,100 ; 設置外層循環(huán)計數
L1:
mov count,ecx ; 保存外層循環(huán)計數
mov ecx,20 ; 設置內層循環(huán)計數
L2:
.
.
loop L2 ; 重復內層循環(huán)
mov ecx,count ; 恢復外層循環(huán)計數
loop L1 ; 重復外層循環(huán)
3). 數組和
.486 ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall ; 選擇程序的內存模式為平坦模式,stdcall調用習慣
.stack 4096 ; 設置運行的堆棧大小為4096字節(jié)
ExitProcess PROTO, dwExitCode: DWORD
COMMENT &
數組求和
&
.data
intArray DWORD 10000h, 20000h, 30000h, 40000h
.code
main PROC ; 定義主函數開始位置
mov edi, OFFSET intArray ; 獲取數組偏移地址
mov ecx, LENGTHOF intArray ; 設置循環(huán)計數
mov eax, 0 ; 存儲數組元素之和
L1:
add eax, [edi] ; 將數組元素值加入eax
add edi, TYPE intArray ; 獲取下一個數組元素地址
LOOP L1 ; 循環(huán)
INVOKE ExitProcess, 0 ; 退出程序2
main ENDP ; 函數結束位置, ENDP 之前的內容,要與PROC
END main ; 設置了函數的入口與出口
4). 字符串復制
.486 ; 定義32位程序可以接受32位的寄存器和地址
.model flat, stdcall ; 選擇程序的內存模式為平坦模式,stdcall調用習慣
.stack 4096 ; 設置運行的堆棧大小為4096字節(jié)
ExitProcess PROTO, dwExitCode: DWORD
COMMENT &
數組求和
&
.data
source BYTE "This is the source string", 0
target BYTE SIZEOF source DUP(0)
.code
main PROC ; 定義主函數開始位置
mov esi, 0 ; 索引寄存器
mov ecx, SIZEOF source ; 循環(huán)計數
L1:
mov al, source[esi] ; 從源字符串獲取一個字符, mov指令不能夠有兩個內存操作數
mov target[esi], al ; 存儲到目標字符串對應位置
inc esi ; 移動到下一個字符串
LOOP L1 ; 循環(huán)
INVOKE ExitProcess, 0 ; 退出程序
main ENDP ; 函數結束位置, ENDP 之前的內容,要與PROC
END main ; 設置了函數的入口與出口
5). 數組求和——64位
; 數組求和
ExitProcess PROTO
.data
intArray QWORD 1000000000000h, 2000000000000h, 3000000000000h, 4000000000000h
.code
main PROC
mov rdi, OFFSET intArray ; 設置偏移地址
mov rcx, LENGTHOF intArray ; 初始化循環(huán)計數
mov rax, 0 ; 數組之和
L1:
add rax, [rdi] ; 加入當前位置的數組值
add rdi, TYPE intArray ; 移動得到下一個數組元素
LOOP L1 ; 重復執(zhí)行,直到rcx=0
mov ecx, 0 ; 退出程序并返回
call ExitProcess ; 退出程序
main ENDP
END