在一個(gè)程序中的不同地方,常常需要多次非循環(huán)的使用完成特定功能的程序段,,這些程序段除了某些變量的賦值不同外,,具有相同的指令序列,這時(shí),,我們?yōu)榱藴p少重復(fù)編寫程序,,縮短目標(biāo)代碼,節(jié)省內(nèi)存空間,,把視線這一功能的指令序列組成一個(gè)相對獨(dú)立的程序段,。這也就是我們這片文章中所要討論的子程序。
子程序相當(dāng)于高級語言(比如C語言)中的過程和函數(shù),,在匯編語言中子程序也稱為過程,。使用子程序的好處:
a、有利于程序模塊化,、結(jié)構(gòu)化和自頂向下的程序設(shè)計(jì)方法,,簡化了程序設(shè)計(jì)過程。
b,、增加了源程序的可讀性,,便于調(diào)試維護(hù)
c、減少了目標(biāo)代碼鎖占用的空間
d,、子程序一旦編制成功,,在開發(fā)研制各種軟件時(shí)都可使用,,縮短了軟件的開發(fā)周期。
一,、子程序的調(diào)用與返回
1,、子程序的定義
子程序必須定義在一個(gè)邏輯段內(nèi),子程序的定義由過程定義偽指令PROC/ENDP來實(shí)現(xiàn),,它們分別用在程序的子程序的前后,,一般格式如下:
PROC_NAME PROC [NEAR/FAR]
......
PROC_NAME ENDP
其中PROC_NAME為子程序名,也極為CALL的操作數(shù),,自程序具有3個(gè)屬性:段屬性,、偏移量屬性和類型屬性,段屬性表示該子程序所在段的段基值,。偏移量屬性表示該子程序在段中的偏移量,。類型屬性也稱為距離屬性,可以是NEAR或FAR,,屬性為NEAR的子程序只能在本段內(nèi)調(diào)用,,屬性為FAR的子程序則可以在本段以內(nèi)以及其他段中調(diào)用。
2,、調(diào)用指令
當(dāng)主程序?qū)傩允荖EAR的子程序時(shí),,CPU把當(dāng)前指令指針I(yè)P的內(nèi)容壓入堆棧,作為返回地址保存起來,,然后將子程序的偏移量送入IP,,當(dāng)從子程序返回時(shí),將從堆棧彈出2個(gè)字節(jié)的返回地址送入IP,,當(dāng)調(diào)用屬性是FAR的過程時(shí),,CPU把當(dāng)前的段寄存器CS與指令指針I(yè)P的內(nèi)容都壓入堆棧,作為返回地址保存起來,,然后將子程序的段基值與偏移量送入CS與IP,,當(dāng)子程序返回時(shí),將從堆棧彈出4個(gè)字節(jié)的返回地址分別送入IP與CS,。
我們?nèi)菀字?,?dāng)主程序和子程序處于同一邏輯段時(shí),可以把類型屬性定義為NEAR,,也可以把類型屬性定義為FAR,,然后進(jìn)行調(diào)用。而當(dāng)主程序與子程序不在同一邏輯段是,,只可把過程的類型定義為FAR,,然后調(diào)用。
二,、返回指令
返回指令RET是子程序邏輯上的最后一條指令,,也就是最后一條被執(zhí)行的指令,,它使子程序在完成功能后返回到調(diào)用它的CALL指令的后續(xù)指令處,即返回地址處繼續(xù)執(zhí)行,。
三,、子程序設(shè)計(jì)的基本要求
1、子程序必須有一定的通用性
2,、注意寄存器的保存和恢復(fù)
3,、正確使用堆棧
4、選用適當(dāng)?shù)姆椒ㄔ谥鞒绦蚺c子程序間進(jìn)行參數(shù)傳遞
5,、編制子程序說明信息文件
四,、子程序與主程序間的參數(shù)傳遞
在匯編語言中最常用的參數(shù)傳遞方式有3種,分別是:用寄存器傳遞參數(shù),、用堆棧傳遞參數(shù)和用地址表達(dá)式傳遞參數(shù),。
1,、用寄存器傳遞參數(shù)
這種方式是通過通用寄存器來傳遞的參數(shù),,即在主程序調(diào)用子程序前,將入口參數(shù)送到約定的通用寄存器中,,子程序可以直接從這些寄存器中取出參數(shù)進(jìn)行加工處理,,并將結(jié)果放在約定的通用寄存器中,返回主程序,,主程序再從約定的寄存器中取出結(jié)果,,我們一例子來說明問題:
例:將兩個(gè)給定的二進(jìn)制數(shù)(8位和16位)轉(zhuǎn)換為ASCII碼字符串。
分析:主程序提供唄轉(zhuǎn)換的數(shù)據(jù)和轉(zhuǎn)化后的ASCII碼字符串的存儲(chǔ)區(qū)的首地址,。子程序完成二進(jìn)制的轉(zhuǎn)換,。為了提高子程序的代碼轉(zhuǎn)換通用性,它可以完成8位或16位數(shù)的轉(zhuǎn)換,。設(shè)調(diào)用子程序時(shí),,入口參數(shù)為:被轉(zhuǎn)換的數(shù)在DX中,若位數(shù)小于16,,則從高到低存放,,轉(zhuǎn)換后的ASCII碼的存放首地址在DI中。下面給出一種實(shí)現(xiàn)方法:
DATA SEGMENT
BIN1 DB 35H
BIN2 DW 0AB48H
ASCBUF DB 20H DUP (?)
DATA ENDS
STACK1 SEGMENT PARA STACK
DW 20H DUP (0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK1
BEGIN: MOV AX, DATA
MOV DS, AX
XOR DX, DX
LEA DI, ASCBUF ;存放ASCII碼的單元首地址送DI
MOV DH, BIN1 ;待轉(zhuǎn)換的第一個(gè)數(shù)據(jù)送DH
MOV AX, 8 ;待轉(zhuǎn)換的二進(jìn)制數(shù)的位數(shù)送AX
CALL BINASC
MOV DX, BIN2
MOV AX, 16
LEA DI, ASCBUF
ADD DI, 8 ;設(shè)置下一個(gè)數(shù)的存放首地址
CALL BINASC
MOV AH, 4CH
INT 21H
BINASC PROC
MOV CX, AX
LOP: ROL DX, 1 ;最高位移入最低位
MOV AL, DL
AND AL, 1 ;保留最低位,,屏蔽其他位
ADD AL, 30H
MOV [DI], AL ;存結(jié)果
INC DI ;修改地址指針
LOOP LOP
RET
BINASC ENDP
CODE ENDS
END BEGIN
2,、用堆棧傳遞參數(shù)
這種方法是主程序先將入口參數(shù)壓入堆棧,子程序從堆棧中把參數(shù)讀出,,進(jìn)行加工處理,。這里要注意從堆棧中讀取數(shù)據(jù)與從堆棧中彈出數(shù)據(jù)是有區(qū)別的,從堆棧中讀取數(shù)據(jù)并不改變堆棧的棧頂指針SP,,而從堆棧中彈出的數(shù)據(jù),,則需修改SP,,在使用堆棧傳遞參數(shù)時(shí),要保證堆棧狀態(tài)的正確,。
我們還以上面的例子來說明下問題,,這次采用堆棧傳遞參數(shù)
分析:如果使用堆棧,一般用包括:
a,、在主程序中,,將待轉(zhuǎn)換的數(shù)據(jù)、存放ASCII碼的首地址和轉(zhuǎn)換的位數(shù)壓入棧中
b,、在子程序中保存信息
下面我們依然用程序說明問題,,在程序的必要處我已經(jīng)做了注釋
DATA SEGMENT
BIN1 DB 35H
BIN2 DW 0AB48H
ASCBUF DB 20H DUP (?)
DATA ENDS
STACK1 SEGMENT PARA STACK
DW 20H DUP (0)
STACK1 ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, SS:STACK1
BEGIN: MOV AX, DATA
MOV DS, AX
MOV AH, BIN1
PUSH AX ;待轉(zhuǎn)換數(shù)據(jù)壓棧
MOV AX, 8
PUSH AX ;待轉(zhuǎn)換位數(shù)壓棧
LEA DI, ASCBUF
PUSH DI ;存放ASCII碼的首地址壓棧
CALL BINASC ;調(diào)用轉(zhuǎn)換子程序
MOV AX, BIN2
PUSH AX
MOV AX, 10H
PUSH AX
ADD DI, 8
PUSH DI
CALL BINASC
MOV AH, 4CH
INT 21H
BINASC PROC
PUSH AX
PUSH CX
PUSH DX
PUSH DI
MOV BP, SP
MOV DI, [BP+10] ;從堆棧取出入口參數(shù)
MOV CX, [BP+12]
MOV DX, [BP+14]
LOP: ROL DX, 1
MOV AL, DL
AND AL, 1
ADD AL, 30H
MOV [DI], AL
INC DI
LOOP LOP
POP DI
POP DX
POP CX
POP AX
RET 6 ;返回并從堆棧中彈出6個(gè)字節(jié)
BINASC ENDP
CODE ENDS
END BEGIN
3、用地址表傳遞參數(shù)
當(dāng)要傳送的參數(shù)較多時(shí),,可在主程序中建立一個(gè)地址表,,在調(diào)用子程序前,把所有參數(shù)的地址依次存放在該地址表中,,然后把地址表的首地址通過寄存器傳送到子程序中去,,而在子程序中,按照地址表中給出的地址逐個(gè)取出參數(shù),,用地址表傳遞參數(shù)的方法,,在入口參數(shù)比較多時(shí)很方便,當(dāng)返回參數(shù)較多時(shí),,可用同樣的方法傳遞參數(shù),,供主程序使用。