匯編語言第六章子程序結(jié)構(gòu).ppt
在程序設(shè)計中,可以發(fā)現(xiàn)一些多次無規(guī)律重復(fù)的程序段或語句序列。解決此類問題一個行之有效的方法就是將它們設(shè)計成可供反復(fù)調(diào)用的獨立的子程序結(jié)構(gòu),以便在需要時調(diào)用。在匯編語言中,子程序又稱過程。 調(diào)用子程序的程序稱為主調(diào)程序或主程序。,第6章 子程序結(jié)構(gòu),子程序的基本結(jié)構(gòu)包括以下幾個部分: (1)子程序定義 (2)保護現(xiàn)場和恢復(fù)現(xiàn)場 (3)子程序體 (4)子程序返回,子程序的結(jié)構(gòu),子程序的定義是由過程定義偽指令PROC和ENDP來完成的。其格式如下: 過程名 PROC NEAR/FAR 過程名 ENDP 其中PROC表示過程定義開始,ENDP表示過程定義結(jié)束。過程名是過程入口地址的符號表示。 一般過程名同標號一樣,具有三種屬性,即段屬性、偏移地址屬性以及類型屬性(NEAR 和 FAR)。,6.1.1 子程序的定義,6.1 子程序的設(shè)計方法,1.如果調(diào)用程序和過程在同一代碼段中,則使用NEAR屬性;,MAIN PROC FAR CALL SUBR1 RET MAIN ENDP ; SUBR1 PROC NEAR RET SUBR1 ENDP,MAIN PROC FAR CALL SUBR1 RET SUBR1 PROC NEAR RET SUBR1 ENDP MAIN ENDP,例6.1,過程嵌套定義,2. 如果調(diào)用程序和過程不在同一代碼段中,則使用FAR屬性;,SEGX SEGMENT SUBT PROC FAR RET SUBT ENDP CALL SUBT SEGX ENDS ; SEGY SEGMENT CALL SUBT SEGY ENDS,例6.2,6.1.2 子程序的調(diào)用和返回,調(diào)用: CALL far/near ptr 過程名,返回: RET n,6.1.3 保護現(xiàn)場和恢復(fù)現(xiàn)場,例如:若子程序PROG中改變了寄存器AX,BX,CX,DX的值,則 可采用如下方法保護和恢復(fù)現(xiàn)場。 PROGPROC PUSHAX PUSH BX PUSHCX;保護現(xiàn)場 PUSHDX POPDX POPCX POPBX;恢復(fù)現(xiàn)場 POPAX RET;返回斷點處 PROCENDP,6.1.4 主程序與子程序參數(shù)傳遞方式,1 通過寄存器傳送參數(shù) 這是最常用的一種方式,使用方便,但參數(shù)很多時不能使用這種方法。 例6.3 十進制到十六進制轉(zhuǎn)換的程序。程序要求從鍵盤取得一個十進制數(shù),然后把該數(shù)以十六進制的形式在屏幕上顯示出來。,開始,調(diào)用DECIBIN,調(diào)用CRLF,調(diào)用BINIHEX,調(diào)用CRLF,結(jié)束,從鍵盤取得十進制 數(shù),保存到BX中,顯示回車和換行,用十六進制形式 顯示BX中的數(shù),Decihex segment assume cs:Decihex Main proc far Repeat: push ds xor ax, ax push ax call decibin call crlf call binihex call crlf ret Main endp,Decibin proc near mov bx, 0 Newchar: mov ah, 1 int 21h sub al, 30h jl exit cmp al, 9 jg exit cbw xchg ax, bx mov cx, 10 mul cx xchg ax, bx ;每次乘的 add bx, ax ;結(jié)果在BX中 jmp newchar Exit : ret Decibin endp,Binihex proc near mov ch, 4 Rotate: mov cl, 4 rol bx, cl mov dl, bl and dl, 0fh add dl, 30h cmp dl, 3ah jl print add dl, 7h Print: mov ah, 2 int 21h dec ch jnz rotate ret Binihex endp,Crlf proc near mov ah, 2 mov dl, odh int 21h mov dl, oah int 21h ret Crlf endp Decihex ends end repeat,如果過程和調(diào)用過程在同一源文件(同一模塊)中,則過程可直接訪問模塊中的變量。 例 6.4_1 主程序MAIN和過程PROADD在同一源文件中,要求用過程PROADD累加數(shù)組的所有元素,并把和(不考慮溢出的可能性)送到指定的存儲單元中去,DATA SEGMENT ARY DW 100 DUP (?) COUNT DW 100 SUM DW ? DATA ENDS CODE SEGMENT MAIN PROC FAR ASSUME CS:CODE , DS:DATA START: PUSH DS SUB AX ,AX PUSH AX MOV AX , DATA CALL NEAR PTR PROADD RET MAIN ENDP,PROADD PROC NEAR PUSH AX PUSH CX PUSH SI PUSH DI LEA SI ,ARY MOV CX ,COUNT XOR AX , AX NEXT: ADD AX , SI ADD SI , 2 LOOP NEXT MOV SUM , AX POP DI POP SI POP CX POP AX RET PROADD ENDP CODE ENDS END START,CODE SEGMENT ARY DW 100 DUP(?) COUNT DW 100 SUM DW ? NUM DW 100 DUP (?) N DW 100 TOTAL DW ? MOV TABLE , OFFSET ARY MOV TABLE+2, OFFSET COUNT MOV TABLE+4 , OFFSET SUN MOV BX , OFFSET TABLE CALL PROADD ;計算SUM ,PROADD PROC NEAR PUSH AX PUSH CX PUSH SI PUSH DI PUSH SI,BX MOV DI , BX+2 MOV CX , DI MOV DI , BX+4 XOR AX , AX NEXT: ADD AX , SI ADD SI , 2 LOOP NEXT MOV 【DI, AX POP DI POP SI POP CX POP AX RET PROADD ENDP CODE ENDS END START,3 通過地址表傳遞參數(shù),例6.4_2,4 通過堆棧傳遞地址或參數(shù),Data segment Ary dw 100 dup(?) Count db 100 Sum dw ? Data ends Stack segment para stack stack dw 100 dup(?) tos label word Stack ends Code1 segment assume cs:code1, ds:data, ss;stack Main proc far Start: push ds xor ax, ax push ax mov ax, data mov ds, ax,mov ax,stack mov ss, ax mov sp,offset tos Mov bx, offset ary Push bx Mov bx, offset count Push bx Mov bx, offset sum Push bx Call far ptr proadd mov al, sum mov dl, al mov ah, 2 int 21h ret Main endp Code1 ends,例6.4_3,Sum地址 Count地址 Ary地址,sp,di si cx ax bp,(Sp)bp,IP CS,Code2 segment assume cs:code2 Proadd proc far push bp mov bp, sp push ax push cx push si push di mov si, bp+0ah mov di, bp+08h mov cl, di mov di, bp+06h xor al, al Again: add al, si inc si dec cl jnz again mov di, al pop di pop si pop cx,pop ax pop bp ret 6 Proadd endp Code2 ends end start,bp+0ah,bp+08h,bp+06h,Sp,Sp,Sp,Sp,Sp,(1) PUBLIC偽指令 格式:PUBLIC 符號 ,符號 功能:說明其后的符號是全局符號。全局符號能被其他模塊引用。(局部符號) (2) EXTRN偽指令 格式:EXTRN 符號:類型 ,符號:類型 功能:說明在本模塊中需要引用的、由其他模塊定義的符號,即外部符號。,5 多個模塊之間的參數(shù)傳送問題,; source module 1 extrn var2:word,lab2:far public var1,lab1 Data1 segment var1 db ? var3 dw ? var4 dw ? Data1 ends code1 segment assume cs:code1,ds:data1 Main proc far start: mov ax , data1 mov ds,ax lab1: mov ah,4ch int 21h Main endp Code1 ends End start,; source module 2 extern var1:byte,var4:word public var2 Data2 segment var2 dw ? var3 dw ? Data2 ends code2 segment assume cs:code2,ds:data2 Main proc far start: mov ax , data2 mov ds,ax mov ah,4ch int 21h Main endp Code2 ends End start,注意:應(yīng)先有public 定義,然后才有extrn說明,; source module 3 extern lab2: far public lab2,lab3 Data2 segment var2 dw ? var3 dw ? Data2 ends code3 segment assume cs:code3 Lab2: . Lab3: . Code3 ends End,例6.5 多個模塊間的參數(shù)共享,;Source model 1 EXTERN proadd: far DATA SEGMENT common ARY DW 100 DUP (?) COUNT DW 100 SUM DW ? DATA ENDS CODE1 SEGMENT MAIN PROC FAR ASSUME CS:CODE1 , DS:DATA START: PUSH DS SUB AX ,AX PUSH AX MOV AX , DATA CALL far ptr PROADD RET MAIN ENDP CODE1 ENDS END START,主程序和子過程不在同一個模塊的時參數(shù)傳遞方法一,LOOP NEXT: MOV SUM , AX POP DI POP SI POP CX POP AX RET PROADD ENDP CODE2 ends END,;Source model 2 PUBLIC PROADD DATA SEGMENT common ARY DW 100 DUP (?) COUNT DW 100 SUM DW ? DATA ENDS CODE2 SEGMENT PROADD PROC FAR ASSUME CS:CODE2 , DS:DATA MOV AX,DATA MOV DS,AX PUSH AX PUSH CX PUSH SI PUSH DI LEA SI, ARY MOV CX, COUNT XOR AX, AX NEXT: ADD AX, SI ADD SI, 2,(如例6.4_1的參數(shù)傳遞可利用段覆蓋),;Source model 1 extern var1 : word extern output: far extern var2 : word public quit local_data segment var dw 5 local_data ends code segment assume cs:code,ds:local_data main proc far start: mov ax,local_data mov ds,ax mov bx,var mov ax,seg var1 mov es,ax add bx,es:var1,主程序和子過程不在同一個模塊的時參數(shù)傳遞方法二, mov ax,seg var2 mov es,ax sub es:var2,50 jmp ouput quit:mov ah,4ch int 21h main endp code ends end start ;Source model 2 public var1 extdata1 segment var1 dw 10 extdata1 ends end,;source model 3 public var2 extern quit: far extdata2 segment var2 dw 3 extdata2 ends public output program segment assume cs:program, ds:extdata2 output: jmp quit program ends end,(例6.6 含三個源模塊),;Source model 1 Global segment public Extern var1:word Extern var2:word Global ends Local_data segment Local_data ends code segment assume cs:code, ds: local_data, es:global main proc far,主程序和子過程不在同一個模塊的時參數(shù)傳遞方法三,start: mov x,local_data mov ds,ax mov ax, global mov es,ax mov bx,es:var1 add es:var2,bx mov ah,4ch int 21h main endp code ends end start,(例6.7 含二個源模塊),;source model 2 Global segment public public var1 public var2 var1 dw ? var2 dw ? Global ends end,6.1.5 增強功能的過程定義偽操作,Procname PROC attributes field USER register list ,parameter field Procname ENDP Attributes field(屬性字段)包括: Distance : near 、far Language type :說明是那種高級語言的子程序 如pascal 、c 等。 Visibility : 說明程序的可見性 是private 或是public。 Prologue :是一個宏的名字,允許用宏來控制過程的入口或出口有關(guān)的代碼 USER:該字段用來指定用戶所需保存和恢復(fù)的寄存器表。 Parameter field: 參數(shù)字段 ,允許用戶指定該過程所用的參數(shù) 。 標識符:類型,標識符:類型,Data segment Ary db 10 dup(?) Count db 10 Sum db ? Data ends Stack segment para stack stack db 100 dup(?) Stack ends Code1 segment assume cs:code1, ds:data, ss:stack Main proc far Start: push ds xor ax, ax push ax mov ax, data mov ds, ax,Mov bx, offset ary Push bx Mov bx, offset count Push bx Mov bx, offset sum Push bx Call far ptr proadd mov al, sum mov dl, al mov ah, 2 int 21h ret Main endp Code1 ends,對例6.4 采用用增強功能過程定義偽操作實現(xiàn),Code2 segment assume cs:code2 Proadd proc far push bp mov bp, sp push ax push cx push si push di mov si, bp+0ah mov di, bp+08h mov cl, di mov di, bp+06h xor al, al Again: add al, si inc si dec cl jnz again mov di, al pop di pop si pop cx pop ax pop bp ret 6 Proadd endp Code2 ends end start,Code2 segment assume cs:code2 Proadd proc pascal user ax cx si di , para:word,parc:word,pars:word mov si, para mov di, parc mov cl, di mov di, pars xor al, al Again: add al, si inc si dec cl jnz again mov di, al ret Proadd endp Code2 ends end start,Sum地址 Count地址 Ary地址,(bp),IP CS,( bp +2),( bp +4),( bp +6),( bp +8),( bp +a),原始bp,pars,para,parc,局部變量,di si cx ax,( bp -2),Code2 segment assume cs:code2 Proadd proc far push bp mov bp, sp push ax push cx push si push di mov si, bp+0ah mov di, bp+08h mov cl, di mov di, bp+06h xor al, al Again: add al, si inc si dec cl jnz again mov di, al pop di pop si pop cx pop ax pop bp ret 6 Proadd endp Code2 ends end start,Code2 segment assume cs:code2 Proadd proc C user ax cx si di , pars:word,parc:word,para:word mov si, para mov di, parc mov cl, di mov di, pars xor al, al Again: add al, si inc si dec cl jnz again mov di, al ret Proadd endp Code2 ends end start,Sum地址 Count地址 Ary地址,(bp),IP CS,( bp +2),( bp +4),( bp +6),( bp +8),( bp +a),原始bp,pars,para,parc,局部變量,di si cx ax,( bp -2),增強功能的過程定義偽操作除了以上功能外 ,還可以在過程中定義局部變量。局部變量是在過程內(nèi)部使用的變量,他是在過程調(diào)用是在堆棧中建立的,在退出過程是被釋放。 可以用 LOCAL 定義 LOCAL 變量:類型,變量:類型,Sum地址 Count地址 Ary地址,(bp),IP CS,( bp +2),( bp +4),( bp +6),( bp +8),( bp +a),原始bp,( bp -2),( bp -4),局部變量,例6.8 編程把以ASCII形式表示的十進制數(shù)轉(zhuǎn)換為二進制數(shù),.model small .386 .stack 200h .data Ascval db 12345 Binval dw ? .code Main proc far Start: mov ax,data mov ds,ax, lea bx,asval push bx lea bx,binval push bx call convaxbin mov ah,4ch int 21h Main endp,Convascbin proc pascal uses ax,bx,cx,dx,si,di,par1:word,par2:word Local asclen:word,mulfact:word mov bx,10 mov si,par1 mov di,par2 sub di,si mov asclen,di mov cx,asclen add si,asclen dec si mov mulfact,1 mov di,par2 mov di,0 Next: mov al,si and ax,000fh,Mul mulfact Add di,ax Mov ax,mulfact Mul bx Mov mulfact,ax Dec si Loop next Ret Convascbin endp end main,push bp mov bp,sp add sp,0fch push ax push bx push cx push dx push si push di mov bx,oah mov si,bp+6 mov di,bp+4 sub di,si mov bp2】,di mov cx,bp-2 add si,bp-2 dec si mov word ptr bp-2,0001 mov di,bp+4 mov word ptr di,0,例6.8 經(jīng)過匯編后的Convascbin子過程程序,next : mov al,si and ax,000fh mul word ptr bp-4 add di ,ax mov ax,bp-4 mul bx mov bp-4, ax dec si loop next pop di pop si pop dx pop cx pop bx pop ax mov sp,bp pop bp ret 0004,6.2 子程序的嵌套 一個子程序可以作為調(diào)用程序去掉用另一個子程序,這種情況稱為子程序的嵌套。嵌套深度不限。但應(yīng)注意的問題是堆棧的溢出:上溢、下溢 遞歸子程序:如果一個子程序調(diào)用的是子程序的本身,就是遞 歸子程序。,例 計算 N!=N*(N-1)*(N-2)* *1 -遞歸子程序,Data segment Num db 3 Result dw ? Data ends Stack segment para stack stack db 100 dup(?) tos label word Stack ends Code segment assume cs:code, ds:data, ss:stack Main proc far Begin: push ds xor ax, ax push ax mov ax, data mov ds, ax,mov ax,stack mov ss,ax mov sp, offset tos mov ah, 0 mov al, num call factor mov result, ax ret Main endp,Factor proc push ax sub ax, 1 jne f_cont pop ax jmp return f_cont: call factor pop cx mul cl return: ret factor endp Code ends end begin,IP1,Mov result, ax 地址,3,IP2,Pop cx 地址,2,IP3,Pop cx 地址,1,ax =1,IP POP CX 地址,cx =2,ax*cx =1*2,IP POP CX 地址,cx =3,ax*cx =1*2*3,IP Mov result, ax 地址,常用的DOS系統(tǒng)功能調(diào)用,1單字符輸入(1號調(diào)用) 2單字符顯示(2號調(diào)用) 3打印輸出(5號調(diào)用) 4結(jié)束調(diào)用(4CH號調(diào)用) 5顯示字符串(9號調(diào)用) 6字符串輸入(10號調(diào)用),1單字符輸入(1號調(diào)用) 格式:MOVAH,1 INT21H 功能:從鍵盤輸入字符的ASCII碼送入寄存器AL中,并送顯示器顯示。 2單字符顯示(2號調(diào)用) 格式:MOV DL,待顯示字符的ASCII碼 MOV AH,2 INT 21H 功能:將DL寄存器中的字符送顯示器顯示.,3打印輸出(5號調(diào)用) 格式:MOVDL,待打印字符的ASCII碼 MOV AH,5 INT 21H 功能:將DL寄存器中的字符送打印機打印。 4結(jié)束調(diào)用(4CH號調(diào)用) 格式:MOVAH,4CH INT21H 功能:終止當前程序并返回調(diào)用程序。,5顯示字符串(9號調(diào)用) 格式:LEA DX,待顯示字符串首偏移地址 MOV AH,9 INT 21H 功能:將當前數(shù)據(jù)區(qū)中以結(jié)尾的字符串送顯示器顯示。 6字符串輸入(10號調(diào)用) 格式:LEA DX,緩沖區(qū)首偏移地址 MOV AH,10 INT 21H 功能:從鍵盤上輸入一字符串到用戶定義的輸入緩沖區(qū)中,并送顯示器顯示。,maxlen db 32 actlen db ? string db 32 dup(?),lea dx , maxlen mov ah,0ah int 21h,說明:緩沖區(qū)的第一個字節(jié)保存最大字符數(shù),這個最 大字符數(shù)由用戶程序給出。如果鍵入的字符數(shù) 比此數(shù)大,機器發(fā)出嘟嘟聲。第二個字節(jié)存放 實際輸入的字節(jié)數(shù),這個不是由用戶填入的而 由功能A填入的。在這兩個字節(jié)之后,才是我們 輸入的字符串。,6.3 子程序舉例,例1:HEXIDEX是一個十六進制數(shù)轉(zhuǎn)換成十進制數(shù)的程序。要求把從鍵盤輸入的0 FFFFH的十六進制正數(shù)轉(zhuǎn)換為十進制數(shù)并在屏幕上顯示出來。,Display equ 2h Key equ 1h Doscall equ 21h Hexidec segment Main proc far assume cs:hexidec Start: push ds sub ax,ax push ax call hexidec call crlf call binidec call crlf jmp main ret main endp,Crlf proc near mov dl ,0ah mov ah,display int boscall mov dl,0dh mov ah,display int doscall ret crlf endp Hexidec ends end start,Hexidec proc near mov bx ,0 Newchar: mov key_in int doscall sub al,30h jl exit cmp al, 10d jl add_to sub al ,27h cmp al,0ah jl exit cmp ah,10h jge exit Add_to: mov cl ,4 shl bx , cl mov ah ,0 add bx,ax jmp Exit: Ret Hexidec endp,Binidec proc near mov cx , 10000d call dec_div mov cx , 1000d call dec_div mov cx,100d call dec_div mov cx,10d call dec_div mov cx,1d call dec_div ret Dec_div proc near mov ax, bx mov dx ,0 div cx mov bx,dx mov dl,al add dl,30h mov ah,display int doscall,ret dec_div endp Binidec endp,例2:一個簡單的信息檢索系統(tǒng)。在數(shù)據(jù)區(qū)里,有10個不同的信息,編號為09,每個信息包括30個字符?,F(xiàn)在要編制一個程序:從鍵盤接收09之間的一個編號,然后在屏幕上顯示相應(yīng)編號的信息的內(nèi)容。,Datarea segment thirty db 30 msg0 db 0 I like my IBM-PC- msg1 db 1 I like my IBM-PC- msg2 db 2 I like my IBM-PC- msg3 db 3 I like my IBM-PC- msg4 db 4 I like my IBM-PC- msg5 db 5 I like my IBM-PC- msg6 db 6 I like my IBM-PC- msg7 db 7 I like my IBM-PC- msg8 db 8 I like my IBM-PC- msg9 db 9 I like my IBM-PC- errmsg db error! Invalid praameter Datarea ends,Stack segment db 256 dup(0) tos lable word Stack ends Prognam segment assume cs:prognam ,ds:datarea,ss:stack Start: push ds xor ax,ax push ax mov ax,stack mov ss,ax mov ax,datarea mov ds,ax mov sp,offset tos Begin:mov ah,1 int 21h sub al,0 jc error cmp al, 9 ja error,Mov bx,offset msg0 Mul thirty Add bx,ax Call display Jmp begin Error: mov bx,offset errmsg call display ret Display proc near mov cx,30 mov dl,bx call dispchar inc bx loop disp1 mov dl,0dh call dispchar mov dl,0ah call dispchar ret Dispchar endp,Dispchar proc naer mov ah,2 int 21h ret Dispchar endp Main endp Prognam ends End start,例3:人名排序程序。先從終端鍵入最多30個人名,當所有人名都進入后,按字母上升的次序?qū)⑷嗣判?,并在屏幕上顯示已經(jīng)排好的人名。,Data segment namepar label byte maxnlen db 21 namelen db ? namefld db 21 dup(?) crlf db 13,10,$ endaddr dw ? messg1 db name?,$” messg2 db sorted names,13,10,$ namectr db 0 nametab db 30 dup (20 dup( ) namesav db 20 dup (?),13,10,$ swapped db 0 Data ends Code segment main proc far assume cs:code,ds:data,es:data start:push ds mov ax,0 push ax,mov ax,data mov ds,ax mov es,ax cld lea di,nametab a20loop:call b10read cmp namelen,0 jz a30 cmp namectr,30 je a30 call d10stor jmp a20loop a30:cmp namectr,1 jbe a40 call g10sort call k10disp a40:mov ah,4ch Int 21h Main endp,b10read proc near mov ah,09 lea dx ,messg1 int 21h mov ah,0ah lea dx,namepar int 21h mov ah,09h lea dx crlf Int 21h mov bx,0 mov bl ,namelen mov cx,21 sub cx,bx b20: mov namefldbx,20h inc bx loop b20 ret b10read endp,d10stor proc near inc namectr cld lea si , namectr mov cx,10 rep movsw ret p10stor endp g10sort proc near sub di ,40 mov endaddr,di g20: mov swapped,0 lea si,nametab g30: mov cx,20 mov di,si add di,20 add ax,di mov ax,di mov bx,si repe cmpsb,jbe g40 call h10 xchg g40: mov si,ax cmp swapped,0 jnz g20 ret G10sort endp,h10 xchg proc near mov cx,10 lea di , namesav mov si,bx rep movsw mov cx,10 mov di,bx rep movsw mov cx ,10 lea si,namesav rep movsw mov swapped,1 ret h10 xchg endp,k10disp proc near mov ah,09 lea dx,messg2 int 21h lea si,nametab lea di,namesav mov cx,10 rep movsw mov ah,09 lea dx, namesav int 21h dec namectr jnz k20 ret K10disp endp end start,第六章 作業(yè),6.1 6.2 6.3 6.7 6.8,