彙編之子程序設計

彙編之子程序設計

1. 子程序的概念

1.1 子程序的引入

  • 在程序設計中,我們會發現一些多次無規律重複的程序段或語句序列。解決此類問題一個行之有效的方法就是將它們設計成可供反覆調用的獨立的子程序結構,以便在需要時調用。

1.2 子程序和主程序

  1. 子程序(過程):是指功能相對獨立的一段程序。
  2. 主程序:調用子程序的程序稱爲主調程序或主程序。
  3. 子程序與主程序的關係:調用與被調用的關係。

1.3 子程序的優點

  • 子程序作爲一個功能性模塊,供一個程序甚至多個程序使用;
  • 可以簡化源程序結構;
  • 提高程序的可讀性與可維護性;
  • 有利於代碼複用;
  • 提高程序的設計效率。

2. 子程序的調用與返回

  • 過程定義後,可在主程序中用CALLCALL指令,反覆調用。過程結束,由返回指令RETRET返回主程序。

2.1 調用指令CALLCALL

2.1.1 段內調用

  1. 段內直接調用
    (1)格式:CALL OPR
    (2)執行操作:先保存斷點:SPSP2SP←SP-2,將CALLCALL的下一條指令的IPIP入棧;在將子程序名OPROPR代表的偏移地址IP\to IP,轉到子程序執行。
    (3)功能:子程序名直接寫在指令中,作段內調用。
  2. 段內間接調用
    (1)格式:CALL WORD PTR OPR
    (2)執行操作:將斷點處的IP入棧保存;如果子程序的偏移地址在16位寄存器中則把寄存器的內容IP\to IP;如果其偏移地址是用存儲器中的一個字指出,則把改存儲器單元的內容IP\to IP
    (3)功能:子程序的偏移地址由寄存器或存儲單元指出,作段內調用。

2.1.2 段間調用

  1. 段間直接遠調用
    (1)格式:CALL FAR PTR OPR
    (2)執行操作:先將CALLCALL的下一條指令的CS和IP分別入棧;再把子程序的偏移地址IP\to IP,子程序所在段的段地址CS\to CS
    (3)功能:子程序名用FAR PTRFAR\ PTR屬性直接寫在指令中,作跨段調用。
  2. 段間間接調用
    (1)格式:CALL DWORD PTR OPR
    (2)執行操作:先將CALL的下一條指令的CS和IP分別入棧;再把存儲單元的(EA)IP(EA)\to IPEA+2CS(EA+2)\to CS
    (3)功能:子程序名保存在雙字單元中,第一個字作偏移地址,第二個字作爲段地址,做跨段調用。

2.2 返回指令RETRET

  1. 格式:RET [n]
  2. 執行操作:
    (1)段內返回(近返回)時,從堆棧段中彈出的斷點僅修改IPIP
    (2)段間返回(遠返回)時,從堆棧段中彈出斷點的偏移地址IP\to IP,再彈出斷點的段地址CS\to CS
    (3)如果是RET n指令,表示彈出斷點後,再將堆棧段指針SP+nSP +n之後再返回。
  3. 功能:用於子程序中,返回到主程序的斷點處繼續執行。執行時,將斷點從堆棧中彈出,修改IP或修改IPIPCSCS

3. 子程序的過程定義

3.1 僞指令PROC

  1. 定義:由子程序定義僞指令PROCPROCENDPENDP來完成。
  2. 格式:
子程序名  PROC [NEAR/FAR]
          ┆    ;過程體
子程序名  ENDP
  1. 說明:
    (1)程序名是子程序入口地址的符號表示。同標號一樣,具有三種屬性,即段屬性、偏移地址屬性以及類型屬性。
    (2)PROCPROC表示子程序定義開始,ENDPENDP表示子程序定義結束。
    (3)類型屬性分爲NEAR進程屬性和FAR遠程屬性。如果不寫屬性,系統默認爲NEAR屬性。

3.2 過程屬性

  • 主程序與子程序在同一個代碼段中則子程序使用NEAR屬性。
  • 主程序與子程序不在同一個代碼段中則子程序使用FAR屬性。
  • CALL指令執行時,系統根據子程序名的屬性決定保存斷點的段地址和偏移地址。

4. 子程序參數傳遞

  • 主程序與子程序的參數傳遞:
    (1)入口參數(也稱入口條件):是指主程序調用子程序前,爲子程序內部數據處理準備所需的預置值;
    (2)出口參數:(也稱出口條件):是子程序返回主程序後,把子程序處理的結果傳遞給主程序的數據。
  • 參數傳遞的基本方法有一下三種:

4.1 寄存器傳參

  • 通過CPU寄存器傳遞參數。傳遞數據方便、快捷,但所能傳遞的數據長度和個數都有限。
  • 舉例:求1+2的和的程序。要求將結果送到內存單元,並顯示。(通過寄存器傳送)
DATA SEGMENT
	SUM DB 0
DATA ENDS
STACK SEGMENT
	DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
	ASSUME DS:DATA,SS:STACK,CS:CODE           
START:
	MOV AX,DATA
	MOV DS,AX
	MOV AL, 1
	MOV BL, 2
	CALL subprog
	mov ah,4cH
	int 21h
Subprog PROC
	ADD AL, BL
	OR AL, 30H
	MOV SUM, AL
	Mov dl,al
	Mov ah,2
	Int 21h
	RET	
subprog ENDP
CODE ENDS
	END START

4.2 存儲單元傳參

  • 通過內存單元(組)傳遞參數。傳遞數據的長度和個數可不受限制,程序設計比較靈活。
  • 舉例:求1+2的和的程序。要求將結果送到內存單元,並顯示。(通過存儲單元傳送)
DATA SEGMENT
	SUM DB 0
    D1 DB ?
    D2 DB ? 
DATA ENDS
STACK SEGMENT
	DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
	ASSUME DS:DATA,SS:STACK,CS:CODE           
START:
	MOV AX,DATA
	MOV DS,AX
	MOV D1, 1
	MOV D2, 2
	CALL SPROG
	mov ah,4cH
	int 21h
SPROG PROC
	MOV AL, D1
	ADD AL, D2
	OR AL, 30H
	MOV SUM, AL
	Mov dl,al
	Mov ah,2
	Int 21h
	RET	
SPROG ENDP
CODE ENDS
	END START

4.3 堆棧傳參

  • 堆棧法:通過堆棧傳遞參數。用堆棧保存所要傳遞的數據或存儲地址,利用堆棧數據存取的特點,是常用的參數傳遞方法。
  • 舉例:求1+2的和的程序。要求將結果送到內存單元,並顯示。(通過堆棧傳送:功能最強/最靈活/最複雜)
DATA SEGMENT
	SUM DB 0
DATA ENDS
STACK SEGMENT
	DB 100 DUP(?)
STACK ENDS
CODE SEGMENT
	ASSUME DS:DATA,SS:STACK,CS:CODE           
START:
	MOV AX,DATA
	MOV DS,AX
	MOV AL, 1
	MOV BL, 2
	MOV AH,0
	MOV BH,0
	PUSH AX
	PUSH BX
	CALL SPR
	POP BX
	POP AX
	mov ah,4cH
	int 21h
Spr	PROC
	PUSH BP
	MOV BP, SP
	MOV AX, [BP+6]
	MOV BX, [BP+4]
	ADD AL, BL
	OR AL, 30H
	MOV DL,AL
	MOV AH,2
	INT 21H 
	MOV SUM, AL
	POP BP
	RET	
Spr ENDP
CODE ENDS
	END START

4.4 現場保護

  • 主程序用到某些寄存器保存數據,轉到子程序後,可能會修改寄存器中的值。因此,在進入子程序時,先要將這些寄存器保護起來,稱爲現場保護。
  • 一般採用PUSH指令入棧保存的方法。

5. 子程序的嵌套與遞歸

5.1 子程序的嵌套

  1. 定義:一個程序中可以有多個子程序,而且一個子程序也可以作爲調用程序去調用另一個子程序,這稱爲子程序的嵌套。
  2. 子程序可以多次嵌套,套結構如下:
主程序
  ┋
CALL SUB1 
  ┋ 
子程序1
SUB1
  ┋
CALL SUB2
  ┋ 	
子程序2
SUB2
  ┋
CALL SUB3
  ┋  
一直嵌套下去 
  1. 說明:
    (1)子程序嵌套的層數原則上沒有限制,只受堆棧容量大小的約束。子程序的調用和返回應正確使用CALL和RET;
    (2)各子程序之間所使用的寄存器合理保護和恢復,以避免各層子程序之間發生因寄存器衝突而出現錯誤的情況。
    (3)如果程序中使用堆棧來傳遞參數,則對堆棧的操作要格外小心,堆棧使用不當,可能造成程序不能正確返回。

5.2 子程序的遞歸

  • 定義:如果一個子程序調用的子程序就是它自身,這就稱爲子程序的遞歸。
  • 【例】 編程實現,計算兩個矩陣中每行元素之和的程序,假設每行元素之和仍然是字數據。
    分析與要求:計算每個矩陣中各行元素之和的方法是相同的,所以可把它獨立出來用子程序實現。主程序和子程序之間的參數傳遞通過堆棧實現,注意主程序與子程序中參數的讀取及返回應當配合好。
DATA     SEGMENT
A           DW  12223344      ;A矩陣有3行,每行4個元素
			DW  55667788
			DW  99101112
B           DW  54321       ;B矩陣有2行,每行5個元素
			DW  109876
AI          DW  3                  ;A矩陣的行數
AJ          DW  4                  ;A矩陣的列數
BI          DW  2                  ;B矩陣的行數
BJ          DW  5                  ;B矩陣的列數
LINESUM  	DW  5   DUP( ? )	   ;A與B共5行,有5個行相加之和
DATA     ENDS
STAK     SEGMENT  ‘STACK’
			DB  100  DUP( ? )
STAK     ENDS
CODE     SEGMENT
	ASSUME   CS : CODE,DS:DATA, SS : STACK
START:
	MOV  AX,DATA
	MOV   DS,AX
	LEA   DI,LINESUM
	LEA   BX,A
	PUSH  BX; A矩陣元素首址進棧
	MOV  AX,AI; 取A陣行數
	PUSH   AX
	MOV  AX,AJ; 取A陣列數
	PUSH  AX
	CALL   SUMLINE
	LEA   BX,B
	PUSH  BX
	MOV  AX,BI; B矩陣行數取回AX中
	PUSH  AX; 進棧
	MOV  AX,BJ; B矩陣列數取回AX中
	PUSH   AX
	CALL  SUMLINE
	MOV  AX, 4C00H
	INT  21H
;----------------------------------------------------
;子程序名:SUMLINE
;功能:計算矩陣每行元素之和
;入口參數:矩陣偏移地址、矩陣行、列數進棧傳遞
;出口參數:矩陣每行之和存入LINESUM數組中
;佔用寄存器:AX,BX,CX,DX,BP,FLAG
;----------------------------------------------------
SUMLINE  PROC  NEAR
	PUSH  AX        ;保護現場
	PUSH  BX
	PUSH  CX
	PUSH  DX
	PUSH  BP
	MOV  BP,SP
	PUSHF
	MOV  BX,[BP + 16]; 取矩陣元素的首地址
	MOV  CX,[BP + 14]; 取矩陣行數
LOP : MOV  DX,[BP + 12]; 取矩陣列數,即每行元素個數
	XOR   AX,AX
	NEXT : ADD  AX,[BX]
	ADD  BX,2
	DEC  DX
	JNZ   NEXT
	MOV[DI],AX; 存矩陣每行之和
	ADD   DI,2
	LOOP  LOP
	POPF                   ;恢復現場
	POP  BP
	POP  DX
	POP  CX
	POP  BX
	POP  AX
	RET  6
SUMLINE ENDP
CODE ENDS
	END START
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章