首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 組合語言

組合語言的藝術——基本認識(三):代碼結構優化、迴圈與分支技巧

     編輯:組合語言

前言:細節決定成敗,習慣成就大師

組合語言效率建立在指令運用上。本章收錄實戰中常見的低效寫法與優化對照,涵蓋條件判斷、流程安排、錯誤處理、迴圈指令選擇、暫存器運用、常數vs暫存器、分支預測與 JMP SHORT 優化。

一、程式要條理通順:判斷與流程優化

1. 連續比較 → 區間判斷


; 差:逐一比較
CMP AL,0; JE ABCD0
CMP AL,1; JE ABCD1
CMP AL,2; JE ABCD2

; 優:先比中間值
CMP AL,1
JNE ABCD0
ABCD1: ...
; ABCD0 內再 JA ABCD2

最常見路徑 (ABCD1) 無分支,最快。

2. 指令重排消除冗餘


; 差
ADD AX,4
ABCD: STOSW; ADD AX,4; ADD DI,2; LOOP ABCD

; 優:將不變操作移出迴圈或合併
ABCD: ADD AX,4; STOSW; INC DI; INC DI; LOOP ABCD

3. 錯誤邏輯修正


; 差:MOV BX,SI / MOV BX,[BX] / OR BX,BX / JZ / MOV SI,BX / JMP
; 優:LODSW / OR AX,AX / JZ / MOV SI,BX / JMP

直接用 LODSW 載入並檢查,省去間接定址開銷。

4. 分支重構


; 差:TEST/JNZ 跳轉 CALL / JMP SHORT
; 優:TEST/JZ 直線執行 / INC BX*2 / CALL 統一入口

5. 堆疊操作極小化


; 差:PUSH DI / MOV CX,BX / REP STOSB / POP DI
; 優:MOV CX,BX / REP STOSB / SUB DI,BX

; 差:PUSH CX / REP MOVSB / POP CX / SUB DX,CX
; 優:SUB DX,CX / REP MOVSB   (CX 不變)

6. 位元測試表格驅動


; 差:8 段 TEST/JZ/MOV 重複代碼
; 優:緩衝區按序排列 / MOV DI,OFFSET BUF1 / MOV AL,BL / MOV CX,4
X1: SHR AH,1; JZ X2; STOSB
X2: SHR AH,1; JZ X3; MOV [DI],DX; INC DI; INC DI
X3: LOOP X1

7. 除法迴圈 → 減法迴圈


; 差:SUB AH,AH / CMP/JB / SUB/INC/JMP
; 優:MOV AH,-1 / INC AH / SUB AL,BL / JA 迴圈 / ADD AL,BL 還原

8. 字母大小寫轉換:AND 取代多重比較


; 差:CMP 60h/JA / SUB 40h / JMP / SUB 60h
; 優:AND AL,1Fh   ; 直接取字母序數 (A=1..Z=26, a=1..z=26)

9. 防禦性程式設計:檢查輸入合法性

測試時假設正確輸入,實際用戶會輸入錯誤。所有有「正確/錯誤」之分的輸入、運算,**必須預先檢查排除錯誤資料**。正確性優先於精簡。

二、指令應用要靈活:大小寫轉換案例演進

需求:DS:SI 資料長度 CX,BL=0 大轉小,BL=1 小轉大。

版本 1:極差 (子程式調用開銷巨大)


LOOP1: CALL CHANGE; JC LOOP11; ADD AL,20h; JMP LOOP12
LOOP11: SUB AL,20h
LOOP12: MOV [SI-1],AL; LOOP LOOP1
CHANGE: LODSB; OR BL,BL; JZ CHANGS; CMP AL,61h; JB CHARET; CMP AL,7Ah; JA CHARET; STC; CHARET: RET
CHANGS: CMP AL,41h; JB CHARET; CMP AL,5Ah; JA CHARET; CLC; RET

每筆資料調用子程式:23+20=43T 開銷,迴圈內再浪費數十 T。

版本 2:內聯但仍用常數比較


CHANGE: LODSB; OR BL,BL; JZ CHANGS; CMP AL,61h; JB CHANG1; CMP AL,7Ah; JA CHANG1; SUB AL,20h; CHANG0: MOV [SI-1],AL; CHANG1: LOOP CHANGE
CHANGS: CMP AL,41h; JB CHANG1; CMP AL,5Ah; JA CHANG1; ADD AL,20h; JMP CHANG1

版本 3:常數預載暫存器 (DH/DL)


MOV AH,20h; MOV DX,7A61h; OR BL,BL; JZ CHANGE; MOV DX,5A41h
CHANGE: LODSB; CMP AL,DL; JB CHANG1; CMP AL,DH; JA CHANG1; XOR AL,AH; MOV [SI-1],AL; CHANG1: LOOP CHANGE; RET

暫存器比較極快,平均 <40T/筆,10MHz 下 10 萬筆約 0.5 秒。

版本 4:預設法 (緩衝區統一參數)


MOV AH,20h; MOV DX,BWCOM; CHANGE: LODSB; CMP AL,DL; JB CHANG1; CMP AL,DH; JA CHANG1; XOR AL,AH; MOV [SI-1],AL; CHANG1: LOOP CHANGE; RET

彈性最大,統一應用介面即可共用。

三、迴圈中的指令:時脈成本核算

  • 核心原則:速度第一,記熟指令時脈,選擇最高效等效指令
  • 忌諱:緩衝區 (慢、佔空間、不靈活)、常數 (盡量用暫存器)、PUSH/POP/DIV/MUL/CALL (高時脈)

案例:位元組 vs 字處理


; 位元組版:50,000 次 × 55T = 275M T ≈ 0.25 秒 (10MHz)
LOOP1: LODSB; XOR AL,[DI]; STOSB; LOOP LOOP1

; 字版:25,000 次 × 66T = 165M T ≈ 0.16 秒,快 36%
LOOP1: LODSW; XOR AX,[DI]; STOSW; LOOP LOOP1

巢狀迴圈與 CALL 開銷

  • LOOP 17T,巢狀極貴
  • CALL/RET 43T,迴圈中絕對避免
  • 四指令子程式 LODSW/XOR/STOSW/RET 若用 CALL 調用:3B 調用換 4B 本體,得不償失

雙重迴圈扁平化


; 差:外層 LOOP2 內層 LOOP3,PUSH/POP CX 保存外層計數
; 優:單層迴圈 + DEC DX / JNZ 外層標號
; 省 46T → 35T/外層迭代

四、分支處理技巧

資料分類驅動分支

  1. 位元分類:以資料位元為索引,間接定址/分支 (如倉頡碼繪圖)
  2. 字元分類:≤128 類用雙數編碼間接定址;連續分類值乘二
  3. 間隔分類:提取可分類資料建字串緩衝區,REPNZ SCASW 比對,間接 CALL

程式結構:間接定址集中於模組首部

便於擴充、表現層次、合併共用代碼。子程式標號按功能集中性排序。

真/假分支時脈非對稱:真 16T、假 4T

高速路徑設為直線 (假),低概率設為分支 (真)。


CDEF: CMP AL,'?'; JZ ABCD; LOOP CDEF  ; '?' 最少,NZ 只需 4T
ABCD: ...

JMP vs JMP SHORT

  • JMP 3B/15T,JMP SHORT 2B/15T (距離 ≤ 128B)
  • 向上跳轉編譯器自動優化;向下需手動改 JMP SHORT,否則多 1B NOP + 2T
  • 除錯完成後全盤檢查 JMP,常有斬獲

總結

從判斷邏輯重構到迴圈指令換裝,從暫存器預載到分支預測利用,每一個微優化在迴圈累積下都是數量級的效能差距。養成「小事不做,小善不為」的反面習慣——即時優化每一條指令——是邁向組合語言大師的必經之路。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved