程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編基礎:子程序設計

匯編基礎:子程序設計

編輯:匯編語言

在我的上一篇博文中,我簡單的向大家介紹了匯編語言程序設計的三種基本方式。在一個程序中的不同地方,常常需要多次非循環的使用完成特定功能的程序段,這些程序段除了某些變量的賦值不同外,具有相同的指令序列,這時,我們為了減少重復編寫程序,縮短目標代碼,節省內存空間,把視線這一功能的指令序列組成一個相對獨立的程序段。這也就是我們這片文章中所要討論的子程序。

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

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

b、增加了源程序的可讀性,便於調試維護

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

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

一、子程序的調用與返回

1、子程序的定義

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

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

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

2、調用指令

當主程序屬性是NEAR的子程序時,CPU把當前指令指針IP的內容壓入堆棧,作為返回地址保存起來,然後將子程序的偏移量送入IP,當從子程序返回時,將從堆棧彈出2個字節的返回地址送入IP,當調用屬性是FAR的過程時,CPU把當前的段寄存器CS與指令指針IP的內容都壓入堆棧,作為返回地址保存起來,然後將子程序的段基值與偏移量送入CS與IP,當子程序返回時,將從堆棧彈出4個字節的返回地址分別送入IP與CS。

我們容易知道,當主程序和子程序處於同一邏輯段時,可以把類型屬性定義為NEAR,也可以把類型屬性定義為FAR,然後進行調用。而當主程序與子程序不在同一邏輯段是,只可把過程的類型定義為FAR,然後調用。

二、返回指令

返回指令RET是子程序邏輯上的最後一條指令,也就是最後一條被執行的指令,它使子程序在完成功能後返回到調用它的CALL指令的後續指令處,即返回地址處繼續執行。

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

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

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

3、正確使用堆棧

4、選用適當的方法在主程序與子程序間進行參數傳遞

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

四、子程序與主程序間的參數傳遞

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

1、用寄存器傳遞參數

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

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

分析:主程序提供呗轉換的數據和轉化後的ASCII碼字符串的存儲區的首地址。子程序完成二進制的轉換。為了提高子程序的代碼轉換通用性,它可以完成8位或16位數的轉換。設調用子程序時,入口參數為:被轉換的數在DX中,若位數小於16,則從高到低存放,轉換後的ASCII碼的存放首地址在DI中。下面給出一種實現方法:

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            ;待轉換的第一個數據送DH    
    MOV AX, 8           ;待轉換的二進制數的位數送AX    
    CALL    BINASC      
    MOV DX, BIN2    
    MOV AX, 16    
    LEA DI, ASCBUF    
    ADD DI, 8           ;設置下一個數的存放首地址    
    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            ;存結果    
    INC DI          ;修改地址指針    
    LOOP    LOP    
    RET    
BINASC  ENDP    
CODE    ENDS    
    END BEGIN

2、用堆棧傳遞參數

這種方法是主程序先將入口參數壓入堆棧,子程序從堆棧中把參數讀出,進行加工處理。這裡要注意從堆棧中讀取數據與從堆棧中彈出數據是有區別的,從堆棧中讀取數據並不改變堆棧的棧頂指針SP,而從堆棧中彈出的數據,則需修改SP,在使用堆棧傳遞參數時,要保證堆棧狀態的正確。

我們還以上面的例子來說明下問題,這次采用堆棧傳遞參數

分析:如果使用堆棧,一般用包括:

a、在主程序中,將待轉換的數據、存放ASCII碼的首地址和轉換的位數壓入棧中

b、在子程序中保存信息

下面我們依然用程序說明問題,在程序的必要處我已經做了注釋

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              ;待轉換數據壓棧    
    MOV AX, 8    
    PUSH    AX              ;待轉換位數壓棧    
    LEA DI, ASCBUF    
    PUSH    DI          ;存放ASCII碼的首地址壓棧    
    CALL    BINASC              ;調用轉換子程序    
    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]         ;從堆棧取出入口參數    
    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個字節    
BINASC  ENDP    
CODE    ENDS    
    END BEGIN

3、用地址表傳遞參數

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

本文出自 “驿落黃昏” 博客,請務必保留此出處http://yiluohuanghun.blog.51cto.com/3407300/940566

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved