過程定義由PROC與ENDP僞指令實現,形式如下:
過程名 PROC [NEAR|FAR]
<過程體>
過程名 ENDP
過程名在整個程序中必須是唯一的。
過程名本質上與標號一樣,也具有3種屬性:段地址、偏移地址和類型(NEAR或FAR)。
PROC後用關鍵字NEAR、FAR或空,以表示過程的類型(缺省爲NEAR)。
過程名 PROC [NEAR|FAR]
<過程體>
過程名 ENDP
過程名在整個程序中必須是唯一的。
過程名本質上與標號一樣,也具有3種屬性:段地址、偏移地址和類型(NEAR或FAR)。
PROC後用關鍵字NEAR、FAR或空,以表示過程的類型(缺省爲NEAR)。
1.過程調用和返回指令
(1)CALL:過程調用
與JMP指令類似,CALL指令包括下列4種調用方式:
段內直接調用(Intrasegment/Direct Call)
段間直接調用(Intersegment/Direct Call)
段內間接調用(Intrasegment/Indirect Call)
段間間接調用(Intersegment/Indirect Call)
段內調用在同一代碼段內進行,又稱近(Near)調用;
段間調用可以在不同代碼段之間進行,又稱遠(Far)調用。
語法格式:
CALL ProcName ; 若ProcName與該指令在同一代碼段,則爲段內直接調用:
; IP進棧,IP = label的偏移地址;
; 若ProcName與該指令不在同一代碼段,則爲段間直接調用:
; CS:IP 進棧,CS:IP = label的分段地址
CALL reg16/mem16 ; 段內間接調用:IP進棧,IP = reg16 / [mem16]
CALL mem32 ; 段間間接調用:
; CS:IP 進棧,CS = mem32高字,IP = mem32低字
功能描述:
(1)返回地址進棧。
遠調用:CS與IP(下一條指令的地址)依次進棧。
近調用:IP(下一條指令的16位偏移地址)進棧。
(2)轉移到過程的第1條指令去執行。
遠調用:根據操作數,將32位分段地址送CS:IP。
近調用:根據操作數,將16位偏移地址送IP。
對標誌位的影響:無。
(2)RET指令RET(Return):過程返回
過程返回分爲近(段內)返回和遠(段間)返回。
語法格式:
RET ; 近返回或遠返回
RET imm16 ; 近返回或遠返回,並調整堆棧:SP = SP + imm16
功能描述:
RET:返回地址出棧,從而實現轉移到返回地址處。其中,
遠返回:POP 1個雙字到CS:IP。
近返回:POP 1個字到IP。
RET imm16:在返回地址出棧後,CPU立即將imm16加到堆棧指針SP。這種機制用來在返回前將參數從棧中移出。
對標誌位的影響:無。
說明:RET由彙編器根據其所在過程的類型(NEAR或FAR)決定是近返回還是遠返回。缺省爲近返回。
(1)CALL:過程調用
與JMP指令類似,CALL指令包括下列4種調用方式:
段內直接調用(Intrasegment/Direct Call)
段間直接調用(Intersegment/Direct Call)
段內間接調用(Intrasegment/Indirect Call)
段間間接調用(Intersegment/Indirect Call)
段內調用在同一代碼段內進行,又稱近(Near)調用;
段間調用可以在不同代碼段之間進行,又稱遠(Far)調用。
語法格式:
CALL ProcName ; 若ProcName與該指令在同一代碼段,則爲段內直接調用:
; IP進棧,IP = label的偏移地址;
; 若ProcName與該指令不在同一代碼段,則爲段間直接調用:
; CS:IP 進棧,CS:IP = label的分段地址
CALL reg16/mem16 ; 段內間接調用:IP進棧,IP = reg16 / [mem16]
CALL mem32 ; 段間間接調用:
; CS:IP 進棧,CS = mem32高字,IP = mem32低字
功能描述:
(1)返回地址進棧。
遠調用:CS與IP(下一條指令的地址)依次進棧。
近調用:IP(下一條指令的16位偏移地址)進棧。
(2)轉移到過程的第1條指令去執行。
遠調用:根據操作數,將32位分段地址送CS:IP。
近調用:根據操作數,將16位偏移地址送IP。
對標誌位的影響:無。
(2)RET指令RET(Return):過程返回
過程返回分爲近(段內)返回和遠(段間)返回。
語法格式:
RET ; 近返回或遠返回
RET imm16 ; 近返回或遠返回,並調整堆棧:SP = SP + imm16
功能描述:
RET:返回地址出棧,從而實現轉移到返回地址處。其中,
遠返回:POP 1個雙字到CS:IP。
近返回:POP 1個字到IP。
RET imm16:在返回地址出棧後,CPU立即將imm16加到堆棧指針SP。這種機制用來在返回前將參數從棧中移出。
對標誌位的影響:無。
說明:RET由彙編器根據其所在過程的類型(NEAR或FAR)決定是近返回還是遠返回。缺省爲近返回。
*使用過程應注意的問題
在過程體內必須有一條RET指令被執行到。如果在過程內沒有執行到RET或其它轉移指令,程序將繼續執行ENDP後的指令。
正確選擇過程的類型。通常基於下列原則:
若過程只在同一代碼段中被調用,則定義爲NEAR。
若過程可以在不同代碼段中被調用,則定義爲FAR。
CALL與RET的類型要一致。
通常要保證RET指令執行前,棧頂內容正好是返回地址。
注意保護相關寄存器的值。通常,除了作爲返回參數的寄存器外,過程不應改變其它寄存器的值。
可以將過程定義放在單獨的代碼段中。若過程定義與主程序處於同一代碼段,則要保證其只有被調用時,纔會執行。
對於大多數過程,需要與調用者之間傳遞一定數量的數據,即參數。根據傳遞的方向,將參數分爲兩類:
入口參數:由調用者向過程傳遞的數據,作爲過程的輸入參數。
出口參數:由過程向調用者返回的數據,作爲過程的輸出參數。
根據問題的需要,過程可以只有入口參數或只有出口參數,也可以二者兼有。
對於過程與調用者之間的參數傳遞,可根據傳遞的數據量,選擇採用寄存器、變量或堆棧等方式。由於過程是相對獨立的功能塊, 因此,在定義過程時,通常要加上適當的註釋,主要包括功能、入口參數與出口參數等。
在過程體內必須有一條RET指令被執行到。如果在過程內沒有執行到RET或其它轉移指令,程序將繼續執行ENDP後的指令。
正確選擇過程的類型。通常基於下列原則:
若過程只在同一代碼段中被調用,則定義爲NEAR。
若過程可以在不同代碼段中被調用,則定義爲FAR。
CALL與RET的類型要一致。
通常要保證RET指令執行前,棧頂內容正好是返回地址。
注意保護相關寄存器的值。通常,除了作爲返回參數的寄存器外,過程不應改變其它寄存器的值。
可以將過程定義放在單獨的代碼段中。若過程定義與主程序處於同一代碼段,則要保證其只有被調用時,纔會執行。
對於大多數過程,需要與調用者之間傳遞一定數量的數據,即參數。根據傳遞的方向,將參數分爲兩類:
入口參數:由調用者向過程傳遞的數據,作爲過程的輸入參數。
出口參數:由過程向調用者返回的數據,作爲過程的輸出參數。
根據問題的需要,過程可以只有入口參數或只有出口參數,也可以二者兼有。
對於過程與調用者之間的參數傳遞,可根據傳遞的數據量,選擇採用寄存器、變量或堆棧等方式。由於過程是相對獨立的功能塊, 因此,在定義過程時,通常要加上適當的註釋,主要包括功能、入口參數與出口參數等。
1 用變量傳遞參數
在程序中定義全局變量,如放在數據段,過程直接按名訪問該變量。
過程直接以變量作爲參數,雖然方便,但通用性較差。
2 用寄存器傳遞參數
通過寄存器傳遞數據或數據地址。
通常選擇AL、AX、DX:AX(或EAX)傳遞字節、字或雙字。
傳遞16位偏移地址最好選擇SI、DI或BX,
傳遞32位分段地址可以用DS:BX、DS:SI、DS:DI、ES:BX、ES:SI或ES:DI等。
當然,要根據需要來選擇,以方便爲主,但很少使用BP來傳遞參數。
通過寄存器傳遞數據或數據地址。
通常選擇AL、AX、DX:AX(或EAX)傳遞字節、字或雙字。
傳遞16位偏移地址最好選擇SI、DI或BX,
傳遞32位分段地址可以用DS:BX、DS:SI、DS:DI、ES:BX、ES:SI或ES:DI等。
當然,要根據需要來選擇,以方便爲主,但很少使用BP來傳遞參數。
3 用地址表傳遞參數
建立一個地址表,存放所有參數的地址,傳遞地址表的首地址給過程。
這種方法特別適合於參數較多的情況。
建立一個地址表,存放所有參數的地址,傳遞地址表的首地址給過程。
這種方法特別適合於參數較多的情況。
4 用堆棧傳遞參數
調用者通過調整堆棧指針爲返回參數預留空間,然後將過程所需的入口參數進棧;
過程從堆棧得到入口參數,返回前將出口參數寫入堆棧;
調用者通過出棧得到返回參數。
過程從堆棧存取參數時,通常使用BP,因爲其隱含的段地址在SS中。
採用堆棧傳遞參數時,典型的過程結構如下:
StdProc proc near
push bp
mov bp, sp ; BP指向當前棧頂,用於取入口參數
...
pop bp
ret ParmSize ; 返回前從堆棧移出入口參數
StdProc endp
其中,ParmSize是過程被調用前進棧的入口參數的字節數。
調用者通過調整堆棧指針爲返回參數預留空間,然後將過程所需的入口參數進棧;
過程從堆棧得到入口參數,返回前將出口參數寫入堆棧;
調用者通過出棧得到返回參數。
過程從堆棧存取參數時,通常使用BP,因爲其隱含的段地址在SS中。
採用堆棧傳遞參數時,典型的過程結構如下:
StdProc proc near
push bp
mov bp, sp ; BP指向當前棧頂,用於取入口參數
...
pop bp
ret ParmSize ; 返回前從堆棧移出入口參數
StdProc endp
其中,ParmSize是過程被調用前進棧的入口參數的字節數。
5 用代碼流傳遞參數
由位於CALL指令之後的代碼流(Code Stream)傳遞參數。
由位於CALL指令之後的代碼流(Code Stream)傳遞參數。
遞歸過程
1.遞歸過程的主要思想
將一個問題分解爲幾個子問題,而其中的有些子問題與原問題相同,只是規模要小。
隨着問題的不斷分解,一定存在一個與原問題相同的最小問題,可以直接解決,這便是遞歸出口。
2.遞歸過程設計的關鍵
保證除了出口參數外,每次調用都不破壞以前調用時所用到的參數和中間結果。
遞歸過程的參數傳遞常使用堆棧,也可使用寄存器,但通常不用變量。
保證除了出口參數外,每次調用都不破壞以前調用時所用到的參數和中間結果。
遞歸過程的參數傳遞常使用堆棧,也可使用寄存器,但通常不用變量。