第5章 子程序課件_第1頁
第5章 子程序課件_第2頁
第5章 子程序課件_第3頁
第5章 子程序課件_第4頁
第5章 子程序課件_第5頁
已閱讀5頁,還剩55頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

5.1 子程序 5.2 參數(shù)的傳遞

5.3 嵌套和遞歸子程序

5.4 多模塊程序設(shè)計 5.5 匯編語言與C語言混合編程 5.6 DOS和BIOS調(diào)用第五章 子程序IPCS指令存放在內(nèi)存中,處理器從內(nèi)存取指令分析執(zhí)行指令一般是從前到后順序執(zhí)行的CPU執(zhí)行當(dāng)前指令時,IP被更改為下條指令的地址,CS和IP不能用MOV等傳送指令直接修改跳轉(zhuǎn)類指令可以通過修改IP和CS實現(xiàn)程序的不同流程本章的子程序調(diào)用和返回指令也是通過修改IP和CS實現(xiàn)的?;仡櫍簩S眉拇嫫飨乱粭l指令的段地址下一條指令的偏移地址把程序需要完成的任務(wù)分解為若干個“子任務(wù)”,每個“子任務(wù)”由一段相對獨立的程序完成,稱為“子程序”。子程序也稱為“過程”(Procedure),在高級語言里還稱作“函數(shù)”(Function)。子程序(Subroutine)概念一個簡單子程序;顯示回車換行的子程序dispcrlfprocnear movah,02h ;2號子功能

movdl,0dh ;回車的ascii碼 int21h ;顯示 movah,02h ;2號子功能

movdl,0ah ;換行的ascii碼 int21h ;顯示 ret;返回主程序dispcrlf endpcodesegment assumecs:codestart: calldispcrlf;調(diào)用子程序 movah,4c00h int21h ;返回DOScodeendsendstart1.程序結(jié)構(gòu)清晰,提高了程序的可閱讀性和可維護性。2.每個子程序可以獨立地進(jìn)行調(diào)試,由于程序規(guī)模較小,降低了調(diào)試難度。3.每個子程序就是一個具有特定功能的獨立的程序,提高程序的“可重用性”,提高了軟件開發(fā)效率。

子程序結(jié)構(gòu)程序的優(yōu)點

主程序:…………

CALLPROC1MOVAX,BX……

子程序PROC1………………RET把下一條指令地址壓入堆棧保存按照堆棧保存的地址返回子程序的調(diào)用和返回示意近程子程序:只能在同一個代碼段內(nèi)調(diào)用的子程序。由于主程序和子程序處于同一個代碼段,調(diào)用和返回時只需要改變IP寄存器的值,CS寄存器的值保持不變。近程子程序的入口地址用16位段內(nèi)偏移地址表示。遠(yuǎn)程子程序:能夠被不同代碼段的程序調(diào)用。調(diào)用時,需要同時改變CS和IP寄存器的值,返回時,需要從堆棧里彈出32位的返回地址送入IP,CS寄存器。遠(yuǎn)程子程序的入口地址用16位段基址和16位段內(nèi)偏移地址表示。子程序的類型5.1.1CALL和RET指令

5.1.2子程序的定義5.1.3子程序文件5.1.4子程序應(yīng)用

5.1 子程序

CALL(Call,調(diào)用)指令段內(nèi)直接調(diào)用 格式:CALL 子程序名操作:SP←SP-2,SS:[SP]←IP(保存16位返回地址)

IP←子程序入口的偏移地址段內(nèi)間接調(diào)用 格式:CALL REG16/MEM16

操作:SP←SP-2,

SS:[SP]←IP(保護16位返回地址)

IP←REG16/MEM16

段內(nèi)調(diào)用段間直接調(diào)用

格式:CALLFARPTR 子程序名操作: SP←SP-2,SS:[SP]←CS SP←SP-2,SS:[SP]←IP

(以上是保存32位返回地址,偏移地址保存在較小地址處)

IP←子程序入口的偏移地址,

CS←子程序入口的段基址段間間接調(diào)用格式:CALL MEM32操作:SP←SP-2, SS:[SP]←CS SP←SP-2, SS:[SP]←IP IP←[MEM32],CS←[MEM32+2]

段間調(diào)用(1) CALL PROC1(2) LEA CX, PROC1 CALL CX (3)ADDR_PROC1DWPROC1;子程序偏移地址 …… CALL ADDR_PROC1 ;調(diào)用近程子程序PROC1(4) LEA BX,ADDR_PROC1 CALL WORDPTR[BX] ;調(diào)用近程子程序PROC1調(diào)用子程序的四種方法無參數(shù)段內(nèi)返回 格式:RET

操作:IP←SS:[SP],SP←SP+2

有參數(shù)段內(nèi)返回 格式:RETD16 ;其中D16代表16位數(shù)據(jù) 操作:IP←SS:[SP],SP←SP+2

SP←SP+D16

無參數(shù)段間返回

格式:RET

操作: IP←SS:[SP],SP←SP+2 CS←SS:[SP],SP←SP+2有參數(shù)段間返回 格式:RETD16

;其中D16代表16位數(shù)據(jù) 操作: IP←SS:[SP],SP←SP+2 CS←SS:[SP],SP←SP+2

SP←SP+D16

RET指令5.1.2子程序的定義

子程序名 PROC [NEAR/FAR]

;子程序體

RET子程序名

ENDP

子程序名應(yīng)該是合法的標(biāo)識符。用NEAR說明的是“近程子程序”,只能在同一代碼段內(nèi)調(diào)用。用FAR說明的是“遠(yuǎn)程子程序”,能在其它代碼段調(diào)用。子程序的遠(yuǎn)近屬性選項可以省略(省略時為近程子程序)子程序的定義要寫在代碼段內(nèi)[例5.1]子程序FRACTOR用來計算一個數(shù)的階乘。主程序利用它

計算1~5的階乘,存入FRA數(shù)組。

DATA SEGMENT FRADW5DUP(?)DATA ENDSCODE SEGMENT ASSUMECS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX MOV BX,1 ;BX中存放待求階乘的數(shù) MOVSI,0 MOV CX,5 ;求階乘次數(shù)(循環(huán)次數(shù))LOOP0:CALL FRACTOR ;調(diào)用FRACTOR求階乘 MOV FRA[SI],AX ;保存結(jié)果(階乘) ADD SI,2 INC BX ;產(chǎn)生下一個待求階乘的數(shù) LOOP LOOP0 ;循環(huán)控制 MOV AX,4C00H INT 21HCODE ENDS END START思考題:這個程序正確么?;輸入?yún)?shù):BX:對哪個數(shù)求階乘;輸出參數(shù):AX:結(jié)果FRACTOR PROCNEAR MOV CX,BX ;待求階乘的數(shù)轉(zhuǎn)入CX寄存器 MOV AX,1 ;“累乘器”置初值1FRALOOP: MUL CX ;累乘 LOOP FRALOOP ;循環(huán)控制 RETFRACTOR ENDPFRACTOR PROCNEAR PUSH CX ;CX壓入堆棧保護

MOV CX,BX ;待求階乘的數(shù)轉(zhuǎn)入CX寄存器 MOV AX,1 ;“累乘器”置初值1FRALOOP: MUL CX ;累乘 LOOP FRALOOP ;循環(huán)控制 POP CX ;從堆棧里彈出CX的原值

RETFRACTOR ENDP

子程序名 PROC [NEAR/FAR] PUSH …… ;保護現(xiàn)場(寄存器/存儲器) PUSH …… ;個數(shù)根據(jù)具體情況決定 …… ;子程序主體 …… POP …… ;恢復(fù)現(xiàn)場,注意出棧次序 POP …… ;先進(jìn)棧的寄存器后出棧 RET ;返回

子程序名 ENDP在子程序入口處把相關(guān)寄存器的值入棧保護,程序返回前再恢復(fù)它們的值,這個操作稱為“保護現(xiàn)場”和“恢復(fù)現(xiàn)場”。子程序的一般格式5.1.3子程序文檔設(shè)計一個子程序之前,首先應(yīng)該明確:子程序的名字;子程序的功能;入口參數(shù):為了運行這個子程序,主程序為它準(zhǔn)備了哪幾個“已知條件”?這些參數(shù)存放在什么地方?出口參數(shù):這個子程序的運行結(jié)果有哪些?存放在什么地方?影響寄存器:執(zhí)行這個子程序會改變哪幾個寄存器的值?其它需要說明的事項。

上述內(nèi)容連同子程序源代碼等合稱為“子程序文檔”。常常把上述內(nèi)容以“程序注釋”的方式書寫在一個子程序的首部。給使用者提供調(diào)用信息。;名稱:Square;功能:求16Bit無符號數(shù)的平方根;入口參數(shù):16Bit無符號數(shù)在AX中;出口參數(shù):8Bit平方根數(shù)在AL中;影響寄存器:AX(AL);方法:利用公式:N^2=1+3+……+(2N-1)求平方根SQUARE PROC NEAR PUSH CX ;保護現(xiàn)場 PUSH BX MOV BX,AX ;要求平方根的數(shù)送BX MOV AL,0 ;AL中存放平方根,初值0

MOV CX,1 ;CX置入第一個奇數(shù)1

;利用公式:N^2=1+3+……+(2N-1)求平方根NEXT: SUB BX,CX JB DONE ADD CX,2 ;形成下一個奇數(shù) INC AL ;AL存放已減去奇數(shù)的個數(shù) JMP NEXTDONE: POP BX ;恢復(fù)現(xiàn)場 POP CX RET ;返回SQUARE ENDP“SQUARE”的子程序,求一個數(shù)的平方根5.1.4子程序應(yīng)用每調(diào)用一次子程序,主程序需要做三件事:(1)為子程序準(zhǔn)備入口參數(shù)(2)調(diào)用子程序(3)處理子程序的返回參數(shù)DATA SEGMENT X DW 59,3500,139,199,77 ;欲求平方根的數(shù)組 ROOT DB 5DUP(?) ;存放平方根內(nèi)存區(qū)DATA ENDSCODE SEGMENT ASSUME CS:CODE,DS:DATASTART:MOV AX,DATA MOV DS,AX

LEA BX,X ;初始化指針 LEA SI,ROOT MOV CX,5 ;設(shè)置計數(shù)器初值ONE: MOV AX,[BX]

;設(shè)置入口參數(shù) CALL SQUARE ;調(diào)用子程序

MOV [SI],AL

;保存返回參數(shù)(平方根) ADD BX,2 ;修改指針 INC SI ;修改指針 LOOP ONE ;循環(huán)控制

MOV AX,4C00H ;返回DOS INT 21H[例]求5個無符號數(shù)的平方根。子程序;名稱:Square;功能:求16Bit無符號數(shù)的平方根;入口參數(shù):16Bit無符號數(shù)在AX中;出口參數(shù):8Bit平方根數(shù)在AL中;影響寄存器:AX(AL);方法:利用公式:N^2=1+3+……+(2N-1)求平方根SQUARE PROC NEAR PUSH CX ;保護現(xiàn)場 PUSH BX MOV BX,AX ;要求平方根的數(shù)送BX MOV AL,0 ;AL中存放平方根,初值0

MOV CX,1 ;CX置入第一個奇數(shù)1NEXT: SUB BX,CX JB DONE ADD CX,2 ;形成下一個奇數(shù) INC AL ;AL存放已減去奇數(shù)的個數(shù) JMP NEXTDONE: POP BX ;恢復(fù)現(xiàn)場 POP CX RET ;返回SQUARE ENDPCODEENDS ENDSTART5.2 參數(shù)的傳遞 傳遞的參數(shù)有兩種類型:(1)值傳遞:把參數(shù)的值放在約定的寄存器或存儲單元傳遞給子程序,或者,由子程序返回給主程序。

如果一個入口參數(shù)是用值傳遞的,子程序使用這個值,但是不改變它自身的值。(2)地址傳遞:把參數(shù)事先存放在某個存儲單元,把這個存儲單元的地址作為參數(shù)傳遞給子程序。

如果一個參數(shù)使用它的地址來傳遞,子程序可以改變這個參數(shù)的值。例如,把存放結(jié)果的存儲單元的地址作為“入口參數(shù)”傳遞給子程序,子程序可以把運算結(jié)果直接存入這個單元。利用寄存器傳遞參數(shù)利用主、子程序“共享”的數(shù)據(jù)段傳遞參數(shù)利用堆棧傳遞參數(shù)三種常用的參數(shù)傳遞方法:

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

[例5.3] 求菲波那契數(shù)列的前n項。分析:菲波那契數(shù)列的前兩項為1,1,以后的每一項都是其前兩項之和。 X0=1, X1=1, Xi=Xi-1+Xi-2(i>=2)。方法1:利用寄存器傳遞參數(shù)的值。方法2:利用寄存器傳遞參數(shù)的地址。.MODEL SMALL.DATA FIBLST DW 1,1,18DUP(?) N DW 20.CODESTART: MOV AX,@DATA MOV DS,AX LEA SI,FIBLST MOV CX,N SUB CX,2ONE: MOV AX,[SI] MOV BX,[SI+2] CALL FIB MOV [SI+4],AX ADD SI,2 LOOP ONE MOV AX,4C00H INT 21H方法1:利用寄存器傳遞參數(shù)的值。;子程序FIB;功能:求菲波那契數(shù)列數(shù)列的一項;入口參數(shù):AX=Xi-1,BX=Xi-2;出口參數(shù):AX=Xi=Xi-1+Xi-2FIB PROC ADD AX,BX RETFIB ENDP END START.MODEL SMALL.DATA FIBLST DW 1,1,18DUP(?) N DW 20 .CODESTART:MOV AX,@DATA MOV DS,AX LEA SI,FIBLST MOV CX,N SUB CX,2ONE: CALL FIB ADD SI,2 LOOP ONE MOV AX,4C00H INT 21H方法2:利用寄存器傳遞參數(shù)的地址。;子程序FIB;功能:求菲波那契數(shù)列數(shù)列的一項;入口參數(shù):SI=Xi-2的段內(nèi)偏移地址;出口參數(shù):無(結(jié)果已由子程序存入數(shù)組內(nèi))

FIB PROC PUSH AX MOV AX,[SI] ;取XI-2 ADD AX,[SI+2] ;加XI-1 MOV [SI+4],AX ;存入XI POP AX RETFIB ENDP END START .MODEL SMALL .DATA FIBLSTDW 1,1,18DUP(?) N DW 20 XI1 DW ?;存放XI-1 XI2 DW ?;存放XI-2 XI DW ?;存放XI .CODE START:MOV AX,@DATA MOV DS,AX

LEA SI,FIBLST;設(shè)置地址指針 MOV CX,N SUB CX,2 ;設(shè)置計數(shù)器初值ONE: MOV AX,[SI+2]

MOV XI1,AX

;Xi-1置入XI1

MOV AX,[SI] MOV XI2,AX

;Xi-2置入XI2 CALL FIB ;調(diào)用子程序

MOV AX,XI ;取出計算結(jié)果Xi MOV [SI+4],AX;置入FIBLST數(shù)組 ADD SI,2 ;修改地址指針 LOOP ONE ;循環(huán)控制 MOV AX,4C00H INT 21H2.變量(共享數(shù)據(jù)段)傳遞參數(shù)

;子程序FIB;功能:計算菲波那契數(shù)列數(shù)列的一項;入口參數(shù):XI1=XI-1,XI2=XI-2;出口參數(shù):XI=XI-1+XI-2FIB PROC PUSH AX ;保護現(xiàn)場 MOV AX,XI1 ;AX=XI-1 ADD AX,XI2 ;AX=XI-1+XI-2 MOV XI,AX ;XI←AX POP AX ;恢復(fù)現(xiàn)場 RETFIB ENDP END START26.MODEL SMALL.DATA FIBLSTDW1,1,18DUP(?) N DW 20 .CODESTART: MOVAX, @DATA MOV DS, AX LEA SI, FIBLSTMOV CX, N SUB CX, 2ONE:PUSH AX

;為保存結(jié)果,在堆?!邦A(yù)留”單元

PUSH WORDPTR[SI]

;XI-2入棧

PUSH WORDPTR[SI+2]

;XI-1入棧

CALL FIB ;調(diào)用子程序,執(zhí)行后堆棧狀態(tài)1

POP AX

;從堆棧彈出結(jié)果,執(zhí)行后堆棧狀態(tài)4

MOV [SI+4],AX

;把結(jié)果存入FIBLST數(shù)組 ADD SI,2 LOOP ONE MOV AX,4C00H INT 21H3.堆棧傳遞參數(shù);子程序FIB;功能:計算菲波那契數(shù)列數(shù)列的一項;入口參數(shù):XI-1,XI-2在堆棧中;出口參數(shù):XI在棧頂FIB PROC PUSH BP MOV BP,SP ;堆棧狀態(tài)2PUSHAX MOV AX,[BP+4] ;從堆棧取出XI-1 ADD AX,[BP+6] ;AX=XI-1+XI-2 MOV [BP+8],AX ;結(jié)果存入堆棧POPAX POP BP ;恢復(fù)BP RET 4

;返回,SP+4,執(zhí)行后堆棧狀態(tài)3FIB ENDP END START思考:1。修改參數(shù)壓棧的順序,程序如何修改?2。改用堆棧傳入?yún)?shù),寄存器返回參數(shù),程序如何修改?5.3 嵌套和遞歸子程序5.3.1 子程序嵌套

5.3.2遞歸子程序5.3.1 子程序嵌套 被調(diào)用的子程序在返回前又調(diào)用了其他子程序,稱為子程序嵌套。

(也稱過程嵌套NestProcedureCall);主程序 ……. CALL SUBA ;① …….;子程序SUBA

……. CALL SUBB ;② ……. RET;子程序SUBB ……. RET5.3.2遞歸子程序遞歸過程(RecursiveProcedure):一個直接或間接調(diào)用自身的過程。 如果一個問題可以分解為幾個子問題,而這些子問題又和原問題有相同的算法時,遞歸過程是非常方便的表達(dá)方式。 遞歸過程可以使用堆棧傳遞參數(shù),也可以用寄存器傳遞參數(shù)或存儲單元傳遞參數(shù)。計算1~N自然數(shù)之和可以定義為:SUM(N)= N=1時,SUM函數(shù)直接返回1。 N>1時,計算SUM(N)分成兩步: (1)計算SUM(N-1):設(shè)置入口參數(shù)為N-1,

調(diào)用SUM函數(shù)(調(diào)用自身) (2)進(jìn)行加法運算:N+SUM(N-1)也可以定義為:SUM(N)=1+2+3+……+N.MODEL SMALL.STACK 100 ;定義100字節(jié)用作堆棧.CODETOTAL DW ?START:

MOV CX,3 ;為子程序準(zhǔn)備參數(shù) CALL SUM ;調(diào)用子程序SUM

MOV CS:TOTAL,AX;保存結(jié)果 MOV AX,4C00H INT 21H ;返回;遞歸過程SUM;入口參數(shù):CX=N,出口參數(shù):AX=1~N的和SUM PROC PUSH CX ;保存入口參數(shù)(N)

CMP CX,1 ;判CX(N)是否為1 JE BACK ;CX(N)為1,轉(zhuǎn)BACK DEC CX ;CX-1,為下一次調(diào)用準(zhǔn)備參數(shù) CALL SUM ;遞歸調(diào)用,計算1~N-1的和 INC CX ;恢復(fù)CX為N ADD AX,CX ;加到AX中 JMP EXITBACK: MOV AX,1 ;N=1時,通過AX返回1EXIT: POP CX ;恢復(fù)入口參數(shù) RETSUM ENDP END START

這個程序使用寄存器進(jìn)行參數(shù)的傳遞。主程序中的“CALLSUM”指令執(zhí)行了一次。子程序SUM中的指令“CALL SUM”執(zhí)行了2次。CALL指令先后共執(zhí)行了3次,先后3次進(jìn)入同一個子程序

SUM。遞歸調(diào)用和返回示意圖編寫遞歸程序時,必須保證要有一個終止條件,而且,經(jīng)過有限次執(zhí)行這個子程序,這個終止條件能夠?qū)崿F(xiàn)。否則,程序?qū)a(chǎn)生“死循環(huán)”或者其它的錯誤狀態(tài)。.MODEL SMALL.STACK 100 ;定義100字節(jié)用作堆棧.CODETOTAL DW ?START: PUSH AX ;為返回結(jié)果預(yù)留單元, ;AX中內(nèi)容無意義 MOV CX,3 ;為子程序準(zhǔn)備參數(shù)

PUSH CX ;入口參數(shù)壓入堆棧 CALL SUM ;調(diào)用子程序SUM

POP CS:TOTAL ;③保存結(jié)果 MOV AX,4C00H INT 21H ;返回 高級語言中的遞歸程序普遍使用堆棧傳遞參數(shù)。上面的例子改寫如下:;遞歸過程SUM;入口參數(shù):[SP+2]=N,出口參數(shù):1~N的和在堆棧棧頂;影響寄存器:BP,AX,CXSUM PROC

PUSH BP MOV BP,SP ;根據(jù)BP訪問堆棧中的參數(shù)PUSHAXPUSHCX MOV CX,[BP+4] ;取出入口參數(shù)N,存入CX CMP CX,1 ;N=1? JE BACK ;N=1,轉(zhuǎn)BACK DEC CX ;CX-1,為下一次調(diào)用準(zhǔn)備參數(shù)

PUSH AX ;為保留下一次調(diào)用結(jié)果預(yù)留單元,AX中內(nèi)容無意義 PUSH CX ;入口參數(shù)(N-1)壓入堆棧 CALL SUM ;遞歸調(diào)用,計算1~N-1的和

POP AX ;從堆棧彈出子程序運算結(jié)果(1~N-1的和) ADD AX,[BP+4] ;把N加到AX中,得到1~N的和 MOV [BP+6],AX ;1~N的和存入堆棧預(yù)留單元 JMP EXITBACK:MOV WORDPTR[BP+6],1 ;N=1時,返回1EXIT:POPCXPOPAXPOP BP RET 2SUM ENDP END START例:將字符串反序輸出

movbx,offsetstr

pushbx

callrevers

popbxmovdl,[bx]movah,2int21hreversprocnearpushbpmovbp,spmovbx,[bp+4]moval,[bx]cmpal,'$'jereturnincbx

pushbx

callrevers

popbxmovdl,[bx]movah,2int21hreturn:

popbpret;不能寫成:ret2(?)reversendp上機4:按照學(xué)號的順序輸入20個學(xué)生的成績(0~100)存入一維數(shù)組SCORE,然后統(tǒng)計每一個學(xué)生的名次并在屏幕輸出。要求:1、顯示形式為“學(xué)號:名次”;2、輸入每個成績、統(tǒng)計每個成績的名次、顯示結(jié)果數(shù)據(jù)(學(xué)號或名次)分別定義為子程序;3、傳參方式:寄存器或堆棧。5.4 多模塊程序設(shè)計

5.4.1 段的完整定義5.4.2簡化段定義

5.4.3創(chuàng)建多模塊程序1.一個應(yīng)用程序的開發(fā)由一個小組,而不是一個人完成的。

每個程序員編制的源程序自然地構(gòu)成一個(或者是多個)源程序文件。

每個源程序文件內(nèi)包括了一個或多個“子程序”。這些源程序文件常常被稱為模塊(Module)。

有時候也把位于同一個源程序文件內(nèi)的各個“子程序”,或者一個“數(shù)據(jù)段”定義等稱為模塊。

一個可供實際使用的應(yīng)用程序,它的源程序基本上都是由若干個程序文件組成的。2.源程序文件規(guī)模過大,會造成管理,維護上的困難。

即便是一個人開發(fā)的應(yīng)用程序,也應(yīng)把一個大的程序分解成多個源代碼文件。

這樣,每個文件長度適中,容易閱讀和維護,如果修改了某個模塊,只需對該模塊重新匯編,然后再和其他模塊鏈接,無須把每個模塊重新匯編一次。

3.許多“子程序”可以重復(fù)使用,獨立為一個源程序文件便于“子程序庫”的管理。

5.4.1 段的完整定義段名 SEGMENT[對齊方式][組合方式][使用類型][‘類’] 語句段名 ENDS完整的段定義格式如下:方括號括起來的內(nèi)容稱為“可選項”,可以由使用者根據(jù)需要決定。1.對齊方式 一個新的段開始時,對齊方式通知連接程序怎樣確定這個段的起始地址。對齊方式可以有下面幾種選擇:BYTE 使本段從前面段結(jié)束之后的下一個字節(jié)地址開始。WORD 使本段從前面段結(jié)束之后的下一個字地址開始。DWORD 使本段從前面段結(jié)束之后的下一個雙字地址開始。PARA 使本段從前面段結(jié)束之后的下一個節(jié)的地址(16的整數(shù)倍)開始存放,是默認(rèn)的對齊方式。如果沒有出現(xiàn)對齊方式說明,自動按照“PARA”來對齊。PAGE 使本段從前面段結(jié)束之后的下一個頁地址(256的整數(shù)倍)開始。

對齊方式段基址起始偏移地址段間空隙(字節(jié))BYTE3020H0005H0WORD3020H0006H1DWORD3020H0008H3PARA3021H0000H11PAGE3030H0000H251

假設(shè)前面一個段的結(jié)束地址為30204H,用不同對齊方式的結(jié)果如下表所示。2. 組合方式 組合方式通知連接程序以何種方式處理不同程序文件中名稱相同的段。組合方式可以有下面幾種選擇:PRIVATE 這個段不與其他同名段合并,每個段都有自己的段基地址,是默認(rèn)的組合方式。PUBLIC 將該段和其他名稱相同,組合方式同為“PUBLIC”的段前后連接在一起,合并成一個段,產(chǎn)生一個新的段基地址,所有標(biāo)號的偏移地址都進(jìn)行調(diào)整。STACK 將所有的STACK段連接為一個新的STACK段,類似于PUBLIC。COMMON所有同名的段使用相同的起始地址,這樣,這些段“共享”這一片共同的存儲區(qū)間。AT表達(dá)式 段的起始地址由表達(dá)式的值來指定,用于設(shè)定一些特殊的段。使用(USE)類型使用類型僅僅使用于使用80386以上指令系統(tǒng)的匯編程序(例如,在程序首部使用.386說明符)使用16位尋址方式時,段內(nèi)偏移地址16位,每個段最大64KB。運行在實模式下的程序使用16位段。使用32位尋址方式時,段內(nèi)偏移地址為32位,一個段最大可達(dá)4GB。運行在保護模式下的程序使用32位段。使用80386以上CPU并且工作在實模式下的程序不能遺漏“USE16”說明。

例如:mulax,5imulax,bx,-14.類名稱 一個段除了有一個段名之外,還可以有一個類名稱。類名稱是以引號引起來的任意字符串。 類名稱相同的段被放在一片相鄰的存儲區(qū)間,但不會合并成同一個段。

CSEGSEGMENT 'CODE'ASSUMECS:CSEG,DS:DATA1ASSUMESS:MYSTACKMAIN PROC MOV AX,DATA1 MOV DS,AX MOV AX,SEGVAL2 MOV ES,AX

MOV AX,VAL1 LEA SI,VAL2 MOV BX,ES:[SI] CMP AX,BX JB L1 CALL FARPTRSUB1L1: MOV AX,4C00H INT 21HMAIN ENDPCSEG ENDS

[例5.5]本例中有兩個代碼段、兩個數(shù)據(jù)段和一個堆棧段,SUBCODE SEGMENT ‘CODE’ ASSUMECS:SUBCODE,DS:DATA2,SS:MYSTACKSUB1 PROC FAR

; 過程體 RETSUB1 ENDPSUBCODE ENDS;==================================

DATA1 SEGMENT 'DATA';類名稱為DATA VAL1 DW 1001HDATA1 ENDS;=============================

DATA2 SEGMENT 'DATA’;類名稱為DATA VAL2 DW 1002HDATA2 ENDS;=============================MYSTACK SEGMENTPARASTACK'STACK' DB 100HDUP(?)MYSTACK ENDS;=============================

END MAIN52 經(jīng)過鏈接,從對應(yīng)的MAP文件中可以看到程序有兩個代碼段、兩個數(shù)據(jù)段和一個堆棧段:Start Stop Length NameClass00000H 00022H 00023H CSEGCODE00030H 00030H 00001H SUBCODECODE00040H 00041H 00002H DATA1DATA00050H 00051H 00002H DATA2DATA00060H 0015FH 00100H MYSTACKSTACK由于使用默認(rèn)的“PARA”對齊方式,段間有間隙。同類型名的段相鄰存放。如果將SUBCODE的段名改為CSEG,將DATA2段名改為DATA1,則鏈接器創(chuàng)建的MAP文件是這樣的:Start Stop Length NameClass00000H00023H 00024H CSEGCODE00030H00033H 00004H DATA1DATA00040H0013FH 00100H MYSTACKSTACK由此可見,在同一個程序文件中,相同段名的代碼段合并成一個段,兩個同名的數(shù)據(jù)段也合并成一個段。5.4.2 簡化段定義

1.內(nèi)存模式定義偽指令使用簡化段定義時,需要首先定義所使用的內(nèi)存模式等參數(shù)。格式如下:.MODEL內(nèi)存模式[,語言類型][,操作系統(tǒng)類型][,堆棧選項]

2.近數(shù)據(jù)段定義偽指令 .DATA.DATA? .CONST.DATA創(chuàng)建一個數(shù)據(jù)段,段名是_DATA,主要定義有初值的變量。.DATA?用來定義沒有初值的變量,段名為_BSS。定義在.DATA?段的無初值變量不占用可執(zhí)行文件的空間。.CONST定義只讀數(shù)據(jù)段,段名是_CONST。一個源文件中可以包含多個由.DATA、.DATA?和.CONST定義的數(shù)據(jù)段,TASM自動將其合并為一個物理段,使它們具有相同的段基址。3.遠(yuǎn)數(shù)據(jù)段定義偽指令

.FARDATA[段名]和.FARDATA?[段名] 分別用來定義已有初值的數(shù)據(jù)段和沒有初值的數(shù)據(jù)段。如果段名缺省,默認(rèn)段名分別為FAR_DATA和FAR_BSS。通過指定段名,可在源文件中定義多個獨立的數(shù)據(jù)段。遠(yuǎn)數(shù)據(jù)段不會被合并。

4.代碼段定義偽指令 .CODE [段名]

如果內(nèi)存模式為SMALL,.CODE偽指令不需要給出“段名”,編譯器生成一個名為_TEXT的代碼段,對于多個代碼段的內(nèi)存模式,則應(yīng)該指明段名。

5.堆棧段定義偽指令 .STACK [堆棧大小]定義一個堆棧段,缺省大小為1024字節(jié),段名為STACK。6.TASM預(yù)定義符號 @CODE和@DATA@CODE表示由.CODE定義的代碼段的段名,在指令中表示段基址。@DATA表示由.DATA、.DATA?和.CONST定義的數(shù)據(jù)段的段名,在指令中表示段基址。注意:使用簡化段定義時,沒有段結(jié)束偽指令。一個新的段開始,就意味著上一個段到此結(jié)束。

.MODEL MEDIUM;

內(nèi)存模式為中型.STACK 100H.DATAMSG1 DB"FIRSTMESSAGE”,0DH,0AH,"$".DATA? ;定義第二個數(shù)據(jù)段,未初始化 X DB 10DUP(?).CODEMAIN PROC MOV AX,@DATA MOV DS,AX LEA DX,MSG1 CALL FARPTRDISP ;遠(yuǎn)調(diào)用 MOV AX,4C00H INT 21HMAIN ENDP[例5.6] 本例中有兩個代碼段。.CODE OTHER;再定義一個代碼段DISPPROCFAR MOV AH,9 INT 21H RETDISP ENDP ENDMAIN ;入口地址MAIN59經(jīng)過鏈接,從對應(yīng)的MAP文件中可以看到程序有兩個代碼段、兩個數(shù)據(jù)段和一個堆棧段:Start StopLength Name Class00000H00011H00012HEX506_TEXT CODE00012H00016H00005HOTHER CODE00020H0002FH00010H_DATA DATA00030H0012FH00100HSTACK STACK00130H00130H00001H_BSS BSS用TD觀察這個程序,發(fā)現(xiàn)_DATA和_BSS段使用相同的段基址,被合并為一個物理段。5.4.3 創(chuàng)建多模塊程序

模塊

:由不同的程序員編寫,以不同的文件名存放在磁盤中,這樣的源程序文件稱為“模塊”

模塊內(nèi)部由若干個段的定義組成,其中僅有一個模塊包含有主程序,其它的模塊包含了一些子程序和數(shù)據(jù)段、堆棧段等。

幾個源程序文件在連接、合并成為一個完整的可執(zhí)行程序時需要解決兩個問題:不同源程序文件中的段如何排列、組合?一個源程序文件怎樣調(diào)用/訪問位于另一個文件中的子程序、變量?

同名段的組合方式: 組合方式通知連接程序以何種方式處理不同程序文件中名稱相同的段。組合方式可以有下面幾種選擇:PRIVATE 這個段不與其他同名段合并,每個段都有自己的段基地址,是默認(rèn)的組合方式。PUBLIC 將該段和其他名稱相同,組合方式同為“PUBLIC”的段前后連接在一起,合并成一個段,產(chǎn)生一個新的段基地址,所有標(biāo)號的偏移地址都進(jìn)行調(diào)整。STACK 將所有的STACK段連接為一個新的STACK段,類似于PUBLIC。COMMON所有同名的段使用相同的起始地址,這樣,這些段“共享”這一片共同的存儲區(qū)間。AT表達(dá)式 段的起始地址由表達(dá)式的值來指定,用于設(shè)定一些特殊的段。 為了使模塊B中的子程序、變量能夠被外部模塊訪問,在模塊B中用PUBLIC偽指令申明相應(yīng)的子程序或變量。 模塊A為了能夠訪問在模塊B中的子程序或者變量,要用EXTRN偽指令申明要調(diào)用的過程名或變量名是外部的。;模塊aextrnx:byteextrndisp:farcode1segment … movx,6 calldisp …code1ends;模塊bpublicxpublicdispdatasegment xdb5dataendscode2segmentdispprocfar …dispendp

code2ends

63兩條偽指令的格式如下:EXTRN 符號名1:TYPE[,……]如果是變量,則TYPE應(yīng)該是BYTE、WORD、DWORD等;如果標(biāo)號或子程序名,則TYPE為NEAR或FAR。PUBLIC 符號名1,符號名2,…

本模塊可以被其它模塊引用子程序名、標(biāo)號、變量名。

[例5.7] 計算ARRAY數(shù)組元素之和,存放到SUM單元。;MODULA.ASM

;模塊A源程序EXTRNARRAYSUM:FAR

;聲明ARRAYSUM是外部函數(shù),將在本模塊中被調(diào)用PUBLICARRAY

;聲明全局變量,可供其他模塊使用DSEG1 SEGMENTPUBLIC

ARRAY DW 2,4,6,8 LENTH EQU ($-ARRAY)/2DSEG1 ENDSDSEG2 SEGMENT SUM DW ?DSEG2 ENDSCSEG SEGMENT ASSUME CS:CSEG,DS:DSEG2 MAIN PROC FAR MOV AX,DSEG2 MOV DS,AX

MOV CX,LENTH

CALL ARRAYSUM;調(diào)用外部函數(shù)

MOV SUM,AX MOV AX,4C00H INT 21H MAIN ENDPCSEG ENDS

END MAIN

65;MODULB.ASM

模塊B源程序EXTRNARRAY:WORD

;聲明外部變量PUBLICARRAYSUM

;該模塊沒有數(shù)據(jù)段STAK SEGMENT 'STACK' DW 10DUP(?)STAK ENDS

CSEG SEGMENT ASSUME CS:CSEGARRAYSUM PROC FAR PUSH DS ;保留原DSPUSH SI MOV AX,SEGARRAY

;把外部變量的段基址放入 MOV DS,AX ;段寄存器DS

MOV AX,0 LEA SI,ARRAYL1: ADD AX,[SI] ADD SI,2 LOOP L1 POP SI POP DS ;恢復(fù)原DS RET ARRAYSUM ENDPCSEG ENDS

END ;模塊B不需要填寫“入口地址”注:兩個模塊中的代碼段同名,但在內(nèi)存中對應(yīng)著兩個不同的邏輯段,具有不同的段地址。方法2:;MODULA.ASM

;模塊A源程序EXTRNARRAYSUM:FAR ;聲明ARRAYSUM是外部函數(shù),將在本模塊中被調(diào)用PUBLICARRAY ;聲明全局變量,可供其他模塊使用DSEG1 SEGMENTPUBLIC ;和其它模塊中的同名邏輯段合并,共用相同的段地址 ARRAY DW 2,4,6,8 LENTH EQU ($-ARRAY)/2DSEG1 ENDSDSEG2 SEGMENT SUM DW ?DSEG2 ENDSCSEG SEGMENT ASSUME CS:CSEG,DS:DSEG2 MAIN PROC FAR MOV AX,DSEG2 MOV DS,AX MOV CX,LENTH CALL ARRAYSUM;調(diào)用外部函數(shù) MOV SUM,AX MOV AX,4C00H INT 21H MAIN ENDPCSEG ENDS END MAIN67;M

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論