1、6.3.3 带参数的子程序,【例6.5】编写一个子程序,对一个无符号的字型数组的各元素求和。在调用子程序之前,已把数组的段地址放在DS中,起始偏移地址放在寄存器SI中,数组元素个数(0)放在CX中。要求子程序把计算结果以双字的形式存放,高位放在DX中,低位放在AX中。,【解】sum PROC NEARPUSH BX ;保护用到的寄存器BXXOR AX,AXMOV DX,AX ;求和前先把存放结果的DX,AX清0,MOV BX,AXs1: ADD AX,BX+SI ;把一个元素加到AX中ADC DX,0 ;若有进位,DX加1INC BXINC BX ;BX加2,指向数组的下一元素LOOP s1P
2、OP BX ;恢复寄存器BX的值RET sum ENDP,子程序说明应该包含如下4个部分: (1)子程序的功能。用来指明该子程序完成什么样的操作。 (2)入口参数。说明调用子程序前应该把什么样的数据放在什么地方。 (3)出口参数。说明调用后从什么地方取得处理结果。 (4)破坏的寄存器。指出子程序中哪些寄存器没有被保护。,6.3.4 参数传递的方法 1通用寄存器传值 2通用寄存器传地址 3标志寄存器传递逻辑型数据【例6.6】编写一个子程序,以放在AX中的公元年份为入口参数,判断该年是否为闰年。另有一个应用程序,它已定义了一个字节型数组t,依次存放着12个月的每月天数,其中2月份的天数是28。应用
3、程序已经在DX中存放了年份值,利用前面编写的子程序,编写程序段调整数组t中2月份的天数。,【解】子程序清单如下:;功能:判断一个年份是否为闰年;入口:AX 公元年份;出口:CF,1表示是闰年,0表示非闰年;破坏寄存器:AXjud PROC NEARPUSH BXPUSH CXPUSH DXMOV CX,AX ;临时保存年份值MOV DX,0MOV BX,4,DIV BX ;除以4,为预防溢出,用双字除以字CMP DX,0JNZ lab1 ;不能整除4则不是闰年,转MOV AX,CX ;取回年份值MOV BX,100DIV BX ;除以100CMP DX,0JNZ lab2 ;不能整除100则是
4、闰年,转MOV AX,CXMOV BX,400DIV BX ;除以400CMP DX,0JZ lab2,lab1:CLC ;把CF清0表示非闰年,设置出口参数JMP lab3lab2:STC ;把CF置1表示是闰年,设置出口参数lab3:POP DXPOP CXPOP BXRETjud ENDP对于DX中存放的年份值,需要先放到AX中,才能调用子程序jud,然后以调用返回后的CF值决定是否把t数组中表示2月份天数的t+1加1。程序段如下:MOV AX,DXCALL judADC BYTE PTR t+1,0 ;原值0CF,4用数据段中已定义的变量存放参数用数据段中定义的变量作为参数传递的载体也
5、是一种常用方法。这种方法要求子程序与调用者之间约定好以哪个变量或哪几个变量进行参数传递。具体做法是:对于用作入口参数的变量,调用者在调用子程序的CALL指令之前,先把变量赋以一定的值,然后以CALL指令转到子程序执行,子程序则取出该变量中的数据进行处理;对用作出口参数的变量,也有赋值与取值两个阶段,子程序进行数据处理后,把处理结果放到约定好的变量中,然后以RET指令返回调用者,调用者可以从变量中取出处理结果使用。,【例6.7】用变量传递参数,编写例6.6要求的子程序。【解】;功能:根据一个年份是否为闰年,设置该年2月份的天数;入口:DS段中的字型变量year 公元年份;出口:DS段中的字节型变
6、量day 该年2月份天数;破坏寄存器:无jud1 PROC NEARPUSH AXPUSH BXPUSH CXPUSH DXMOV BYTE PTR day,28MOV AX,year,MOV DX,0MOV BX,4DIV BX ;除以4CMP DX,0JNZ lab1 ;不能整除4则不是闰年,转MOV AX,year ;取回年份值MOV BX,100DIV BX ;除以100CMP DX,0JNZ lab2 ;不能整除100则是闰年,转MOV AX,yearMOV BX,400DIV BX ;除以400,DIV BX ;除以400CMP DX,0JZ lab2lab2:INC BYTE P
7、TR day ;是闰年,把天数加1,设置出口参数lab1 : POP DXPOP CXPOP BXPOP AXRETJud1: ENDP,5用堆栈传递 参数传递不仅要在传递者之间约定数据的类型,还要约定参数存放地。如果约定用通用寄存器放参数,有可能会出现寄存器不够使用的情况。而约定用变量存放参数又要求在子程序和调用程序之外再写出变量定义,灵活性较差。用堆栈传递参数就可以克服这些缺点。对于调用者来说,传递给子程序的数据可以按字型(如果不是字型,先要转换成字型)用PUSH指令压入堆栈中;对于子程序来说,如何准确地取到栈中数据就是关键性问题。下面的例6.8用一个实际例子说明在子程序中取得参数值的具体方法。,【例6.8】用堆栈传递入口参数,编写子程序,把接收的两个带符号整数中大的一个作为结果,出口参数放在AX中。【解】;功能:求两个带符号整数中大的一个;入口参数:调用前把两个带符号整数入栈;出口参数:AX;破坏寄存器:无,_max PROC NEARPUSH BP ;暂时保存寄存器BP的值MOV BP,SPMOV AX,WORD PTR BP+6 ;取第1个参数到AXCMP AX,WORD PTR BP+4 ;与第2个参数比较JGE labMOV AX,WORD PTR BP+4 ;取第2个参数到AXlab: POP BP ;恢复寄存器BP的原值RET_max ENDP,