汇编-子程序参数传递的三种方式:
寄存器法,堆栈法,参数赋值法
子程序结构如下:
名称 PROC FAR|NEAR
;DO SOMETHING
RET [N];返回断点地址,N可忽略,加了必须对SP进行 平栈 操作
名称 ENDP
结合此结构,我们来看,
1.寄存器法
这个方法最简单易用,但是要注意对寄存器的选择,一般选ABCD[X]通用寄存器就可以了。
步骤如下:
1.通过MOV指令将参数存到寄存器
2.再在子程序中调用寄存器即可【注意保护寄存器】
样例就不给了。
2.堆栈法
过程是:
1.先将参数入栈
2.然后在子程序中使用SP,BP,SI这三个寄存器,对栈值(参数)进行取出利用
样例如下:
参数压栈:
MOV CX,01H
; 压入初始奇数1参数
PUSH CX
; 压入结束参数50
MOV CX,50
PUSH CX
子程序参数利用:
; 利用栈指针SP取栈值
MOV BP,SP
; 取结束参数50,字
; 栈底是高地址段
MOV AX,[BP+2]
; 取初始参数1
MOV BX,[BP+4]
注意:
在利用寄存器取值时要注意参数存储的物理结构,本例参数都是字变量,所以以2为单位进行取值
栈的地段的地址段会越来越高
既是:例如取栈顶时:
应当取SP+2,当然写成[SP+2]是错的,
需要:[BP+2]
如上例。
3.参数赋值法
这一个最是麻烦,但是用会了也就没什么了。
原理如下:
代码段CS定义变量进行参数存储,然后供各个程序模块【子程序,同一源文件】使用【特殊的存取】。
将参数存放到CALL指令后的一串单元中,子程序通过返回地址【断点地址】存取参数并修改返回地址。
步骤是:
在CALL指令调用后,在CS定义自己的数据参数
然后利用SP,BP获取CALL指令执行后的断点地址
此时断点地址后就是对应的参数区
可通过SI取得对应参数
最后在RET前修改栈顶的值为参数区后的地址值【不强制规定,但一般都是】,
做PUSH(一定要先将原断点POP)
就能越过参数区做下一步操作
样例如下:
对参数的定义,
; call求和子程序
CALL sumsub
; 参数定义
NUM DW 50;结束参数
DW 1;初始奇数
; 输出
NEXT: CALL pf
子程序调用参数:
; 获取断点地址做SI
MOV BP,SP
MOV SI,[BP]
; 取代码段中变量
;结束50
MOV AX,CS:[SI+0]
; 开始1
MOV BX,CS:[SI+2]
;
;
;参数利用
;
;
;修改当前断点【修改栈顶的地址断点】
;清除默认断点地址
POP CX
;取自己要执行的断点位置地址
MOV CX,OFFSET NEXT
;修改
PUSH CX
RET
注意:
NEXT是程序返回后要执行的位置【在参数定义后】
CX不做固定,根据自己需要可以更换寄存器,只是不能使得入栈的变量是一个立即数罢了。
在子程序取得了当前执行断点后,开始取定义在CS中的参数,
需要修改默认段基址DS为CS
完。
可能写的不好,但还是求赞!
努力!