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

組合語言基礎:子程序設計完整指南與參數傳遞三大模式

     編輯:組合語言

子程序核心價值

在組合語言中,子程序(或稱過程)相當於高階語言的函式/程序。將重複使用的指令序列封裝為獨立模組,帶來四大效益:

  • 模組化/結構化:支援自頂向下設計,簡化主程式邏輯。
  • 可讀性/維護性:功能集中,易於除錯與修改。
  • 程式碼體積縮減:避免重複指令,節省記憶體。
  • 復用性:一次開發,多專案調用,縮短開發週期。

子程序定義與屬性

定義語法

PROC_NAME PROC [NEAR | FAR]
    ; 子程序本體指令
PROC_NAME ENDP

三大屬性

NEAR vs FAR 調用機制差異

屬性說明
段屬性子程序所在邏輯段的段基址(CS)
偏移屬性子程序在段內的起始位移(IP)
類型/距離屬性NEAR(段內調用,僅壓 IP)或 FAR(跨段調用,壓 CS:IP)
類型調用指令返回指令堆疊變化適用場景
NEARCALL PROC_NAMERET壓入 IP (2 bytes),彈出 IP主程式與子程序在同一邏輯段
FARCALL PROC_NAMERET壓入 CS:IP (4 bytes),彈出 CS:IP跨段調用,或同段但聲明 FAR

子程序設計五大基本要求

  1. 通用性:參數化設計,避免硬編碼固定資料/位址。
  2. 暫存器保護:子程序使用的暫存器需在入口保存、出口恢復(PUSH/POP)。
  3. 堆疊正確使用:平衡 PUSH/POP,確保 SP 指針正確,避免堆疊溢位/下溢。
  4. 參數傳遞協定:明確定義輸入/輸出參數位置(暫存器/堆疊/記憶體),文件化介面。
  5. 文件化:註解說明功能、輸入/輸出參數、副作用、破壞暫存器、範例調用。

參數傳遞三大經典模式

模式一:暫存器傳遞

特點:速度最快、無堆疊開銷、參數數量受限於可用暫存器(AX、BX、CX、DX、SI、DI、BP)。

範例:二進制轉 ASCII 字串(8/16 位元)

; 入口參數:
;   DX = 待轉換數值(高位在前)
;   AX = 位元數(8 或 16)
;   DI = ASCII 輸出緩衝區首址
; 出口:緩衝區填入 ASCII 字元

BINASC PROC
    MOV CX, AX          ; 迴圈計數器 = 位元數
LOP:
    ROL DX, 1           ; 最高位循環移至最低位
    MOV AL, DL
    AND AL, 1           ; 只保留最低位
    ADD AL, '0'         ; 轉為 '0' 或 '1'
    MOV [DI], AL        ; 存入緩衝區
    INC DI              ; 指標前移
    LOOP LOP
    RET
BINASC ENDP

; 主程式調用
MOV DH, BIN1            ; 8-bit 數值
MOV AX, 8
LEA DI, ASCBUF
CALL BINASC

MOV DX, BIN2            ; 16-bit 數值
MOV AX, 16
LEA DI, ASCBUF+8
CALL BINASC

模式二:堆疊傳遞

特點:參數數量無暫存器限制、支援遞迴、符合高階語言呼叫慣例(CDECL/STDCALL)。

關鍵技巧:使用 BP(基址指針)建立堆疊幀,固定偏移存取參數,不受 PUSH/POP 影響。

範例:同功能改用堆疊傳遞

; 主程式:壓入參數(右至左順序,符合 CDECL)
PUSH AX          ; 位元數
PUSH DX          ; 待轉數值
LEA DI, ASCBUF
PUSH DI          ; 輸出緩衝區首址
CALL BINASC_STACK
ADD SP, 6        ; 清理堆疊 (CDECL: 呼叫端清理)

BINASC_STACK PROC
    PUSH BP
    MOV BP, SP           ; 建立堆疊幀
    PUSH AX              ; 保存暫存器
    PUSH CX
    PUSH DX
    PUSH DI

    MOV DI, [BP+10]      ; 取參數:緩衝區首址 (BP+2+2+2+4=10)
    MOV CX, [BP+12]      ; 位元數
    MOV DX, [BP+14]      ; 待轉數值

LOP:
    ROL DX, 1
    MOV AL, DL
    AND AL, 1
    ADD AL, '0'
    MOV [DI], AL
    INC DI
    LOOP LOP

    POP DI               ; 恢復暫存器
    POP DX
    POP CX
    POP AX
    POP BP
    RET 6                ; 返回並彈出 6 bytes 參數 (STDCALL 慣例)
BINASC_STACK ENDP

堆疊幀佈局圖解

高位址
+------------------+
| 返回地址 (IP)    |  ← BP+2 (NEAR) 或 BP+2/BP+4 (FAR)
+------------------+
| 參數3: DI (緩衝區) |  ← BP+10
+------------------+
| 參數2: CX (位元數) |  ← BP+12
+------------------+
| 參數1: DX (數值)   |  ← BP+14
+------------------+
| 舊 BP            |  ← BP (PUSH BP 後 SP 位置)
+------------------+
| 暫存器保存區     |
|  ...             |
低位址

模式三:位址表傳遞

特點:參數極多時優雅、主程式建立參數位址陣列,子程序透過基址間接存取。

流程

  1. 主程式在資料段建立 PARA_TABLE DW PARAM1, PARAM2, PARAM3, ...
  2. 將表首址放入暫存器(如 SI 或 BX)傳遞給子程序。
  3. 子程序用 MOV AX, [SI]、MOV BX, [SI+2] 等間接定址取得參數位址,再存取資料。

適用場景

  • 系統呼叫、中斷服務、參數超過 10 個以上的複雜子程序。
  • 需雙向傳遞大量參數(輸入+輸出)。

實戰範例:完整程式架構

DATA SEGMENT
    BIN1 DB 35H
    BIN2 DW 0AB48H
    ASCBUF DB 20H DUP(?)
    PARA_TABLE DW 3 DUP(?)  ; 位址表範例
DATA ENDS

STACK SEGMENT PARA STACK
    DW 100 DUP(0)
STACK ENDS

CODE SEGMENT
    ASSUME CS:CODE, DS:DATA, SS:STACK
START:
    MOV AX, DATA
    MOV DS, AX
    ; ... 初始化 ...
    ; 調用子程序
    MOV AX, 4C00H
    INT 21H

; 子程序定義區
BINASC PROC
    ; ...
BINASC ENDP

BINASC_STACK PROC
    ; ...
BINASC_STACK ENDP
CODE ENDS
END START

常見錯誤與除錯技巧

錯誤現象解決
忘記保存/恢復暫存器返回主程式後暫存器值錯亂,邏輯失效入口 PUSH 所有將使用的暫存器,出口逆序 POP
堆疊不平衡RET 後 SP 錯誤,程式崩潰檢查 PUSH/POP 次數、RET n 參數、呼叫端 ADD SP
NEAR/FAR 不匹配跨段調用 NEAR 導致 CS 錯誤跨段必須 FAR,同段可 NEAR/FAR 皆可
參數順序錯誤子程序取到錯誤值統一協定(右至左壓棧),文件化介面
修改呼叫端不該改的資料副作用難追蹤明確標註輸入/輸出/輸入輸出參數,遵守 const 慣例

總結

組合語言子程序設計的核心在於:明確介面協定(參數位置/暫存器約定)、嚴格暫存器保護、堆疊平衡、文件化。掌握暫存器、堆疊、位址表三大傳參模式,並能根據參數數量、效能需求、遞迴要求選擇最適模式,是編寫高品質組合語言模組的關鍵。

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