基礎知識
CPU簡介
CPU是計算機的核心,負責:
- 執行機器指令:解碼并執行二進制指令
mov eax, 5 ; 將值5移動到EAX寄存器
- 暫存少量數據:通過內部寄存器快速存取
- 訪問存儲器:讀寫內存數據
mov [0x1000], eax ; 將EAX值存入內存地址0x1000
匯編語言概念
機器指令
二進制代碼,如B8 05 00 00 00
對應mov eax, 5
匯編格式指令
add eax, ebx ; 操作碼 + 操作數
匯編語言的優缺點
優點 | 缺點 |
---|---|
直接硬件控制 | 學習曲線陡峭 |
極致性能優化 | 可移植性差 |
小內存占用 | 開發效率低 |
實時性強 | 調試困難 |
數據的表示和儲存
數據表示
- 二進制:
01011010
- 十六進制:
0x5A
- ASCII:
'A' = 65
基本數據類型
類型 | 大小 | 范圍 | 聲明示例 |
---|---|---|---|
字節 | 8位 | 0-255 | db 0x55 |
字 | 16位 | 0-65535 | dw 0x1234 |
雙字 | 32位 | 0-4,294,967,295 | dd 0x12345678 |
字符串 | 可變 | ASCII序列 | db 'Hello', 0 |
數據存儲
- 小端序:低字節在低地址
dd 0x12345678 ; 內存: 78 56 34 12
IA-32處理器基本功能
通用寄存器及其使用
寄存器 | 主要用途 | 子寄存器 | 示例 |
---|---|---|---|
EAX | 累加器 | AX, AH, AL | mov eax, 10 |
EBX | 基址寄存器 | BX, BH, BL | mov ebx, [mem] |
ECX | 計數器 | CX, CH, CL | mov ecx, 100 |
EDX | 數據寄存器 | DX, DH, DL | mul edx |
ESI | 源索引 | SI | lodsb |
EDI | 目的索引 | DI | stosb |
EBP | 基址指針 | BP | mov ebp, esp |
ESP | 棧指針 | SP | push eax |
標志寄存器(EFLAGS)
標志 | 含義 | 檢查指令 | 設置條件 |
---|---|---|---|
CF | 進位標志 | JC, JNC | 無符號溢出 |
ZF | 零標志 | JZ, JNZ | 結果為零 |
SF | 符號標志 | JS, JNS | 結果為負 |
OF | 溢出標志 | JO, JNO | 有符號溢出 |
PF | 奇偶標志 | JP, JNP | 低8位1的個數為偶 |
AF | 輔助進位 | - | BCD運算 |
cmp eax, ebx
jg greater ; 有符號大于跳轉
尋址方式
- 立即尋址:
mov eax, 5
- 寄存器尋址:
mov ebx, eax
- 直接尋址:
mov eax, [0x4000]
- 寄存器間接:
mov eax, [ebx]
- 基址變址:
mov eax, [ebx+esi*4]
- 相對尋址:
mov eax, [array+4]
常用條件跳轉指令
指令 | 含義 | 檢查條件 |
---|---|---|
JE/JZ | 等于/零 | ZF=1 |
JNE/JNZ | 不等于/非零 | ZF=0 |
JC | 進位 | CF=1 |
JNC | 無進位 | CF=0 |
JA | 高于(無符號) | CF=0 & ZF=0 |
JB | 低于(無符號) | CF=1 |
JG | 大于(有符號) | ZF=0 & SF=OF |
JL | 小于(有符號) | SF≠OF |
cmp eax, 100
jae above_equal ; 無符號大于等于
堆棧和堆棧操作
push eax ; ESP -= 4, [ESP] = EAX
pop ebx ; EBX = [ESP], ESP += 4
程序設計初步
堆棧作用
過程調用和返回指令
call my_function ; 壓入返回地址
; ...
my_function:ret ; 彈出返回地址
參數傳遞
push 10 ; 參數2
push 20 ; 參數1
call addxy
add esp, 8 ; 清理棧
局部變量
my_func:push ebpmov ebp, espsub esp, 8 ; 分配8字節局部變量mov [ebp-4], eax ; 使用局部變量; ...mov esp, ebp ; 清理局部變量pop ebpret
乘法運算全解析
1. 8位乘法(MUL/IMUL)
無符號乘法(MUL):
mov al, 50 ; 被乘數 (8位)
mov bl, 10 ; 乘數 (8位)
mul bl ; AX = AL * BL
; 結果:AX = 0x01F4 (500)
有符號乘法(IMUL):
mov al, -5 ; 被乘數 (8位有符號)
mov bl, 10 ; 乘數 (8位有符號)
imul bl ; AX = AL * BL
; 結果:AX = 0xFFCE (-50)
特性對比:
特性 | MUL | IMUL |
---|---|---|
操作數位數 | 8/16/32 | 8/16/32 |
結果存儲 | AX/DX:AX/EDX:EAX | 同MUL |
符號處理 | 無符號 | 有符號 |
指令周期 | 11-18 | 10-21 |
2. 16位乘法
無符號乘法:
mov ax, 5000 ; 被乘數
mov bx, 100 ; 乘數
mul bx ; DX:AX = AX * BX
; 結果:DX:AX = 0x0007:0xA120 (500000)
有符號乘法(單操作數):
mov ax, -2000
mov bx, 300
imul bx ; DX:AX = AX * BX
; 結果:DX:AX = 0xFFF9:0xE700 (-600000)
有符號乘法(雙操作數):
mov ax, 200
imul ax, 30 ; AX = 200 * 30
; 結果:AX = 6000
3. 32位乘法
標準形式:
mov eax, 500000
mov ebx, 1000
mul ebx ; EDX:EAX = EAX * EBX
; 結果:EDX:EAX = 0x0001DCD6:0x50000000 (500000000)
高效形式(IMUL三操作數):
mov ebx, 1234
imul eax, ebx, 56 ; EAX = 1234 * 56
; 比等效的 mov+imul 快30%
除法運算深度剖析
1. 8位除法(DIV/IDIV)
無符號除法(DIV):
mov ax, 100 ; 被除數 (16位)
mov bl, 3 ; 除數 (8位)
div bl ; AL=商, AH=余數
; 結果:AL=33(0x21), AH=1
有符號除法(IDIV):
mov ax, -100 ; 被除數
mov bl, 3 ; 除數
idiv bl ; AL=-33, AH=-1
2. 16位除法
標準形式:
mov dx, 0 ; 清零高位
mov ax, 10000 ; 被除數低16位
mov bx, 300 ; 除數
div bx ; AX=商, DX=余數
; 結果:AX=33(0x21), DX=100
有符號擴展(CDQ前身):
mov ax, -10000
cwd ; 將AX符號擴展到DX
mov bx, 300
idiv bx ; AX=-33, DX=-100
3. 32位除法
無符號除法:
mov edx, 0 ; 清零高位
mov eax, 100000 ; 被除數低32位
mov ebx, 3000 ; 除數
div ebx ; EAX=商, EDX=余數
; 結果:EAX=33, EDX=1000
有符號擴展(CDQ):
mov eax, -100000
cdq ; 將EAX符號擴展到EDX
mov ebx, 3000
idiv ebx ; EAX=-33, EDX=-1000
分支程序設計
cmp eax, ebx
je equal
jl less
jg greaterequal:; 相等處理jmp endless:; 小于處理jmp endgreater:; 大于處理end:; 繼續執行
循環程序設計
mov ecx, 10 ; 循環計數器
loop_start:; 循環體dec ecxjnz loop_start; 或使用LOOP指令
mov ecx, 10
loop_label:; 循環體loop loop_label
子程序設計
; 計算兩數之和
addxy PROC x:DWORD, y:DWORDmov eax, xadd eax, yret
addxy ENDP; 調用
push 20
push 10
call addxy
add esp, 8
字符串操作
基本字符串指令
指令 | 功能 | 操作 |
---|---|---|
MOVSB | 移動字節 | [ESI] → [EDI], ESI±1, EDI±1 |
STOSB | 存儲字節 | AL → [EDI], EDI±1 |
LODSB | 加載字節 | [ESI] → AL, ESI±1 |
CMPSB | 比較字節 | [ESI] - [EDI], 設置標志 |
SCASB | 掃描字節 | AL - [EDI], 設置標志 |
方向標志控制
cld ; 清除方向標志 (向前)
std ; 設置方向標志 (向后)
字符串復制示例
mov esi, source_str
mov edi, dest_str
mov ecx, len
cld ; 正向移動
rep movsb ; 重復復制直到ECX=0
字符串比較示例
mov esi, str1
mov edi, str2
mov ecx, len
cld
repe cmpsb ; 相等時繼續比較
jne different
字符串搜索示例
mov edi, buffer
mov ecx, buflen
mov al, 'A' ; 搜索字符'A'
cld
repne scasb ; 不相等時繼續
je found
高級字符串操作
; 計算字符串長度
strlen PROC str_ptr:DWORDmov edi, str_ptrxor eax, eaxmov ecx, -1repne scasb ; 搜索0字節not ecxdec ecx ; ECX = 長度mov eax, ecxret
strlen ENDP; 字符串轉換大寫
toupper PROC str_ptr:DWORDmov esi, str_ptr
upper_loop:lodsbcmp al, 0je donecmp al, 'a'jb skipcmp al, 'z'ja skipsub al, 32 ; 轉大寫mov [esi-1], al
skip:jmp upper_loop
done:ret
toupper ENDP
性能優化技巧
1. 循環展開
mov ecx, 100/4 ; 每次迭代處理4個元素
loop_start:; 處理元素1; 處理元素2; 處理元素3; 處理元素4loop loop_start
2. 避免內存訪問瓶頸
; 不好:多次內存訪問
add [var1], eax
add [var2], ebx; 更好:使用寄存器
mov ecx, [var1]
add ecx, eax
mov [var1], ecxmov edx, [var2]
add edx, ebx
mov [var2], edx
3. 使用條件移動避免分支
; 傳統分支
cmp eax, ebx
jg greater
mov ecx, eax
jmp end
greater:mov ecx, ebx
end:; 使用條件移動
cmp eax, ebx
cmovg ecx, eax ; 若大于則ECX=EAX
cmovle ecx, ebx ; 否則ECX=EBX
調試技巧
1. 使用調試器
int 3 ; 設置斷點
2. 寄存器檢查
; 在關鍵點插入空操作
nop
3. 內存查看
; 標記關鍵內存區域
important_data db 'DEBUG', 0
結語
匯編語言作為最接近硬件的編程語言,提供了無與倫比的控制能力和性能優勢。通過掌握:
- CPU工作原理和寄存器使用
- 尋址方式和指令集
- 過程調用和堆棧管理
- 分支和循環結構
- 字符串操作優化
開發者能夠編寫出高效、緊湊的底層代碼。雖然現代高級語言在開發效率上更有優勢,但在性能關鍵領域(如操作系統內核、嵌入式系統、高性能計算等),匯編語言仍然不可替代。