《電子技術應用》
您所在的位置:首頁 > 嵌入式技術 > 解決方案 > 匯編基礎:子程序設計

匯編基礎:子程序設計

2017-06-10
關鍵詞: 匯編

在一個程序中的不同地方,常常需要多次非循環(huán)的使用完成特定功能的程序段,這些程序段除了某些變量的賦值不同外,具有相同的指令序列,這時,我們?yōu)榱藴p少重復編寫程序,縮短目標代碼,節(jié)省內(nèi)存空間,把視線這一功能的指令序列組成一個相對獨立的程序段。這也就是我們這片文章中所要討論的子程序。

子程序相當于高級語言(比如C語言)中的過程和函數(shù),在匯編語言中子程序也稱為過程。使用子程序的好處:

a、有利于程序模塊化、結(jié)構化和自頂向下的程序設計方法,簡化了程序設計過程。

b、增加了源程序的可讀性,便于調(diào)試維護

c、減少了目標代碼鎖占用的空間

d、子程序一旦編制成功,在開發(fā)研制各種軟件時都可使用,縮短了軟件的開發(fā)周期。

一、子程序的調(diào)用與返回

1、子程序的定義

子程序必須定義在一個邏輯段內(nèi),子程序的定義由過程定義偽指令PROC/ENDP來實現(xiàn),它們分別用在程序的子程序的前后,一般格式如下:

PROC_NAME   PROC    [NEAR/FAR]    
......    
PROC_NAME   ENDP

其中PROC_NAME為子程序名,也極為CALL的操作數(shù),自程序具有3個屬性:段屬性、偏移量屬性和類型屬性,段屬性表示該子程序所在段的段基值。偏移量屬性表示該子程序在段中的偏移量。類型屬性也稱為距離屬性,可以是NEAR或FAR,屬性為NEAR的子程序只能在本段內(nèi)調(diào)用,屬性為FAR的子程序則可以在本段以內(nèi)以及其他段中調(diào)用。

2、調(diào)用指令

當主程序?qū)傩允荖EAR的子程序時,CPU把當前指令指針I(yè)P的內(nèi)容壓入堆棧,作為返回地址保存起來,然后將子程序的偏移量送入IP,當從子程序返回時,將從堆棧彈出2個字節(jié)的返回地址送入IP,當調(diào)用屬性是FAR的過程時,CPU把當前的段寄存器CS與指令指針I(yè)P的內(nèi)容都壓入堆棧,作為返回地址保存起來,然后將子程序的段基值與偏移量送入CS與IP,當子程序返回時,將從堆棧彈出4個字節(jié)的返回地址分別送入IP與CS。

我們?nèi)菀字溃斨鞒绦蚝妥映绦蛱幱谕贿壿嫸螘r,可以把類型屬性定義為NEAR,也可以把類型屬性定義為FAR,然后進行調(diào)用。而當主程序與子程序不在同一邏輯段是,只可把過程的類型定義為FAR,然后調(diào)用。

二、返回指令

返回指令RET是子程序邏輯上的最后一條指令,也就是最后一條被執(zhí)行的指令,它使子程序在完成功能后返回到調(diào)用它的CALL指令的后續(xù)指令處,即返回地址處繼續(xù)執(zhí)行。

三、子程序設計的基本要求

1、子程序必須有一定的通用性

2、注意寄存器的保存和恢復

3、正確使用堆棧

4、選用適當?shù)姆椒ㄔ谥鞒绦蚺c子程序間進行參數(shù)傳遞

5、編制子程序說明信息文件

四、子程序與主程序間的參數(shù)傳遞

在匯編語言中最常用的參數(shù)傳遞方式有3種,分別是:用寄存器傳遞參數(shù)、用堆棧傳遞參數(shù)和用地址表達式傳遞參數(shù)。

1、用寄存器傳遞參數(shù)

這種方式是通過通用寄存器來傳遞的參數(shù),即在主程序調(diào)用子程序前,將入口參數(shù)送到約定的通用寄存器中,子程序可以直接從這些寄存器中取出參數(shù)進行加工處理,并將結(jié)果放在約定的通用寄存器中,返回主程序,主程序再從約定的寄存器中取出結(jié)果,我們一例子來說明問題:

例:將兩個給定的二進制數(shù)(8位和16位)轉(zhuǎn)換為ASCII碼字符串。

分析:主程序提供唄轉(zhuǎn)換的數(shù)據(jù)和轉(zhuǎn)化后的ASCII碼字符串的存儲區(qū)的首地址。子程序完成二進制的轉(zhuǎn)換。為了提高子程序的代碼轉(zhuǎn)換通用性,它可以完成8位或16位數(shù)的轉(zhuǎn)換。設調(diào)用子程序時,入口參數(shù)為:被轉(zhuǎn)換的數(shù)在DX中,若位數(shù)小于16,則從高到低存放,轉(zhuǎn)換后的ASCII碼的存放首地址在DI中。下面給出一種實現(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)換的第一個數(shù)據(jù)送DH    
   MOV AX, 8           ;待轉(zhuǎn)換的二進制數(shù)的位數(shù)送AX    
   CALL    BINASC      
   MOV DX, BIN2    
   MOV AX, 16    
   LEA DI, ASCBUF    
   ADD DI, 8           ;設置下一個數(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ù)讀出,進行加工處理。這里要注意從堆棧中讀取數(shù)據(jù)與從堆棧中彈出數(shù)據(jù)是有區(qū)別的,從堆棧中讀取數(shù)據(jù)并不改變堆棧的棧頂指針SP,而從堆棧中彈出的數(shù)據(jù),則需修改SP,在使用堆棧傳遞參數(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個字節(jié)    
BINASC  ENDP    
CODE    ENDS    
   END BEGIN

3、用地址表傳遞參數(shù)

當要傳送的參數(shù)較多時,可在主程序中建立一個地址表,在調(diào)用子程序前,把所有參數(shù)的地址依次存放在該地址表中,然后把地址表的首地址通過寄存器傳送到子程序中去,而在子程序中,按照地址表中給出的地址逐個取出參數(shù),用地址表傳遞參數(shù)的方法,在入口參數(shù)比較多時很方便,當返回參數(shù)較多時,可用同樣的方法傳遞參數(shù),供主程序使用。


本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點。轉(zhuǎn)載的所有的文章、圖片、音/視頻文件等資料的版權歸版權所有權人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無法一一聯(lián)系確認版權者。如涉及作品內(nèi)容、版權和其它問題,請及時通過電子郵件或電話通知我們,以便迅速采取適當措施,避免給雙方造成不必要的經(jīng)濟損失。聯(lián)系電話:010-82306118;郵箱:aet@chinaaet.com。