子程序设计:参数传递、局部变量与调用约定

如何让汇编代码模块化?从 PROC/ENDP 到栈帧管理,从寄存器传参到栈传参,掌握子程序设计的核心模式,写出可复用的汇编函数。

2

为什么需要子程序?

汇编没有"函数"关键字,但我们可以用 CALLRET 实现同样的效果。

子程序的基本结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
MyFunc PROC
    PUSH BP        ; 保存调用者的栈帧
    MOV BP, SP     ; 建立新栈帧
    SUB SP, 4      ; 分配 4 字节局部变量
    
    ; 函数体
    MOV [BP-2], AX  ; 局部变量 1
    MOV [BP-4], BX  ; 局部变量 2
    
    MOV SP, BP     ; 清理局部变量
    POP BP         ; 恢复调用者栈帧
    RET
MyFunc ENDP

参数传递方式

1. 寄存器传参(最快)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
; 调用者
MOV AX, 100
MOV BX, 200
CALL AddFunc

; AddFunc
AddFunc PROC
    ADD AX, BX     ; 结果在 AX 中
    RET
AddFunc ENDP

2. 栈传参(适合多参数)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
; 调用者
PUSH 200
PUSH 100
CALL AddFunc
ADD SP, 4          ; 清理参数

; AddFunc
AddFunc PROC
    PUSH BP
    MOV BP, SP
    
    MOV AX, [BP+4] ; 参数 1
    MOV BX, [BP+6] ; 参数 2
    ADD AX, BX
    
    POP BP
    RET
AddFunc ENDP

局部变量的作用

局部变量存储在栈中,每个函数调用有独立的副本:

  • 不会污染全局数据
  • 递归调用时自动隔离
  • 函数返回后自动释放

调用约定

约定 参数传递 栈清理 寄存器保护
C 调用 栈(右到左) 调用者 EAX/ECX/EDX 不保护
Pascal 栈(左到右) 被调用者 所有寄存器保护
fastcall 寄存器 + 栈 调用者 混合

总结

子程序是汇编走向工程化的关键。掌握栈帧管理,你就能写出结构清晰、可维护的汇编代码。

下一篇:《宏指令与高级汇编技术:代码复用与元编程》

广告
广告位预留中 (728x90)