在MASM 5(Microsoft Micro Assembler)的汇编体系中,子程序(Procedures)的定义和调用是非常重要的,就像C、pascal等的函数和方法一样;且对深入理解高级语言里函数的底层原理极其重要,如函数的参数传递、栈、变长参数等。但在网络上许多教程及代码都极其不规范且语焉不详;有的代码虽然可以运行,但都存在潜在Bug。我仔细阅读了Microsoft的相关手册后,像子程序的严格定义及调用分享如下:
一、子程序(Procedure)的定义和调用
方式1
定义:
label Proc [Far | Near]
...(语句)
Ret[n]
label Endp
调用:
Call label
方式2
定义:
label:
...(语句)
Retn[n]
调用:
Call Near Ptr label
方式3
label:
...(语句)
Retf[n]
调用:
Call Far Ptr label
注意事项:
1、方式1是官方推荐的,Call时不用关心near(段内调用)和far(跨段调用),编译器会根据定义自动生成near call或far call。
2、方式2和方式3定义中Retn和Retf一定要与Call Near Ptr和Call Far Ptr对应,否则栈数据会被破坏
3、从MASM 6后还可通过Proc的定义中声明参数(相当于C语言中函数的定义)。
4、ret、retn、retf后面的n(整数)表示调用返回后sp还需要加n(即还需要弹出n个字节),主要用于传递参数。
二、Call的语法补充
语法:Call oprd(操作数),可分为直接调用或间接调用
1、直接调用
oprd为子程序的地址,则可通过call [near或far]调用。
2、间接调用
oprd为保存子程序的地址的寄存器或内存地址:
段内调用(near call)则可通过call bx或call word ptr [bx+si+20];
跨段调用(far call)则可通过call dword ptr [bx+si+20];