80x86匯編子程序和庫_第1頁
80x86匯編子程序和庫_第2頁
80x86匯編子程序和庫_第3頁
80x86匯編子程序和庫_第4頁
80x86匯編子程序和庫_第5頁
已閱讀5頁,還剩25頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第7章子程序和庫子程序是程序設(shè)計(jì)所常見的基本概念,匯編語言也提供了編寫子程序的方法。本章主要介紹子程序的定義、調(diào)用和返回、子程序的參數(shù)傳遞等知識(shí)。此后,還將講解如何構(gòu)造自己的子程序庫。7.1子程序的定義如果某程序段在源程序內(nèi)反復(fù)出現(xiàn),那么,就可把該程序段定義為子程序。這樣可以縮短源程序長度、節(jié)省目標(biāo)程序的存儲(chǔ)空間,也可提高程序的可維護(hù)性和共享性。定義子程序的一般格式如下:子程序PROC[NEAR|FAR]名… ;子程序體子程序ENDP名對子程序定義的具體規(guī)定如下:、“子程序名”必須是一個(gè)合法的標(biāo)識(shí)符,并前后二者要一致;、PROC和ENDP必須是成對出現(xiàn)的關(guān)鍵字,它們分別表示子程序定義開始和結(jié)束;、子程序的類型有近(NEAR)、遠(yuǎn)(FAR)之分,其缺省的類型是近類型;、如果一個(gè)子程序要被另一段的程序調(diào)用,那么,其類型應(yīng)定義為FAR否則,其類型可以是NEAR。顯然,NEAR類型的子程序只能被與其同段的程序所調(diào)用;、子程序至少要有一條返回指令,也可有多條返回指令。返回指令是子程序的出口語句,但它不一定是子程序的最后一條語句;、子程序名有三個(gè)屬性:段值、偏移量和類型。其段值和偏移量對應(yīng)于子程序的入口地址,其類型就是該子程序的類型。編寫子程序除了要考慮實(shí)現(xiàn)子程序功能的方法外,還要養(yǎng)成書寫子程序說明信息的好習(xí)慣。其說明信息一般包括以下幾方面內(nèi)容:、功能描述、入口和出口參數(shù);可選項(xiàng),最好采用寄存器的保護(hù)和恢復(fù)方法,使、所用寄存器 之使用透明化、所用額外存儲(chǔ)單;可選項(xiàng),可以減少為子程序定義自己的局部變量元、子程序的所米用;可選項(xiàng),如果算法簡單,可以不寫的算法、調(diào)用時(shí)的注意事;可選項(xiàng),盡量避免除入口參數(shù)外還有其它的要求項(xiàng)、子程序的編寫者;可選項(xiàng),為將來的維護(hù)提供信息、子程序的編寫日;可選項(xiàng),用于確定程序是否是最新版本期這些說明性信息雖然不是子程序功能的一部分,但其他程序員可通過它們對該子程序的整體信息有一個(gè)較清晰認(rèn)識(shí),為準(zhǔn)確地調(diào)用它們提供直接的幫助,與此同時(shí),也為實(shí)現(xiàn)子程序的共享提供了必要的資料。7.2子程序的調(diào)用和返回指令子程序的調(diào)用和返回是一對互逆操作,也是一種特殊的轉(zhuǎn)移操作。一方面,之所以說是轉(zhuǎn)移,是因?yàn)楫?dāng)調(diào)用一個(gè)子程序時(shí),程序的執(zhí)行順序被改變,CPU將轉(zhuǎn)而執(zhí)行子程序中的指令序列,在這方面,調(diào)用子程序的操作含有轉(zhuǎn)移指令的功能,子程序的返回指令的轉(zhuǎn)移特性與此類似;另一方面,轉(zhuǎn)移指令是一種“一去不復(fù)返”的操作,而當(dāng)子程序完后,還要求CPU能轉(zhuǎn)而執(zhí)行調(diào)用指令之下的指令,它是一種“有去有回”的操作。為了滿足子程序調(diào)用和返回操作的特殊性,在指令系統(tǒng)中設(shè)置了相應(yīng)的特定指令。7.2.1調(diào)用指令(CALL)調(diào)用子程序指令的格式如下:CALL子程序名/Reg/Mem子程序的調(diào)用指令分為近(near)調(diào)用和遠(yuǎn)(far)調(diào)用。如果被調(diào)用子程序的屬性是近的,那么,CALL指令將產(chǎn)生一個(gè)近調(diào)用,它把該指令之后地址的偏移量(用一個(gè)字來表示的)壓棧,把被調(diào)用子程序入口地址的偏移量送給指令指針寄存器IP即可實(shí)現(xiàn)執(zhí)行程序的轉(zhuǎn)移。近調(diào)用指令的堆棧操作如圖7.1所示。圖7.1近調(diào)用指令進(jìn)棧操作示意圖如果被調(diào)用子程序的屬性是遠(yuǎn)的,那么,CALL指令將產(chǎn)生一個(gè)遠(yuǎn)調(diào)用。這時(shí),調(diào)用指令不僅要把該指令之后地址的偏移量壓進(jìn)棧,而且也要把段寄存器CS的值壓進(jìn)棧。在此之后,再把被調(diào)用子程序入口地址的偏移量和段值分別送給IP和CS,這樣完成了子程序的遠(yuǎn)調(diào)用操作。遠(yuǎn)調(diào)用指令的堆棧操作如圖7.2所示。圖7.2遠(yuǎn)調(diào)用指令進(jìn)棧操作示意圖子程序調(diào)用指令本身的執(zhí)行不影響任何標(biāo)志位,但子程序體中指令的執(zhí)行會(huì)改變標(biāo)志位,所以,如果希望子程序的執(zhí)行不能改變調(diào)用指令前后的標(biāo)志位,那么,就要在子程序的開始處保護(hù)標(biāo)志位,在子程序的返回前恢復(fù)標(biāo)志位。例如:[BX][BX]CALLDISPLAYCALLBXCALLWORD1[BX][BX]CALLDISPLAYCALLBXCALLWORD1CALLDWORD1CALLwordptr;DISPLAY是子程序名;BX的內(nèi)容是子程序的偏移量;WORD1是內(nèi)存字變量,其值是子程序的偏移量;DWORD1是雙字變量,其值是子程序的偏移量和段值;BX所指內(nèi)存字單元的值是子程序的偏移量CALLdwordptr;BX所指內(nèi)存雙字單元的值是子程序的偏移量和段值7.2.2返回指令(RET)當(dāng)子程序執(zhí)行完時(shí),需要返回到調(diào)用它的程序之中。為實(shí)現(xiàn)此功能,指令系統(tǒng)提供了一條專用的返回指令。其格式如下:RET/RETN/RETF[Imm]子程序的返回在功能上是子程序調(diào)用的逆操作。為了與子程序的遠(yuǎn)、近調(diào)用相對應(yīng),子程序的返回也分:遠(yuǎn)返回和近返回。返回指令在堆棧操作方面是調(diào)用指令的逆過程(如圖7.3所示)。其具體規(guī)定如下:、在近類型的子程序中,返回指令RET是近返回,其功能是把棧頂之值彈出到指令指針寄存器IP中,SP會(huì)被加2(如圖7.3所示);、在遠(yuǎn)類型的子程序中,返回指令RET是遠(yuǎn)返回,其功能是:先彈出棧頂之值到IP中,再彈出棧頂之值到CS之中,SP總共會(huì)被加4(如圖7.4所示)。圖7.3近返回指令的出棧操作示意圖圖7.4遠(yuǎn)返回指令的出棧操作示意圖如果返回指令后面帶有立即數(shù)(其值通常為偶數(shù)),則表示在得到返回地址之后,SP還要增加的偏移量,它不是類似于高級(jí)語言中子程序的返回值(如圖7.5所示)。圖7.5帶立即數(shù)的返回指令的出棧操作示意圖在MASM5.0及其以后版本中,可用指令RETN或RETF來顯式地告訴匯編程序是本子程序的返回是近返回,還是遠(yuǎn)返回。例如:RET;可能是近返回,也可能是遠(yuǎn)返回RETN;近返回指令RETF;遠(yuǎn)返回指令RET6;子程序返回后,(SP)^(SP)+6例7.1編寫一個(gè)子程序UPPER,實(shí)現(xiàn)把寄存器AL中存放的字符變大寫。解:;子程序功能:把AL中存放的字符變大寫;入口參數(shù):AL;出口參數(shù):AL;算法描述:判斷AL中字符必須在'a'~'z'之間才能把該字符變?yōu)榇髮慤PPERPROCCMPAL,'a' ;書寫'a'的ASCII碼61H也可以JBoverCMPAL,'z'JAoverSUBAL,20H ;書寫指令A(yù)NDAL,0DFH也可以over:RETUPPERENDP例7.2編寫一個(gè)求字符串長度的子程序StrLen,該字符串以0為結(jié)束標(biāo)志,其首地址存放在DS:DX,其長度保存在CX中返回。解:;子程序功能:求字符串的長度;入口參數(shù):DS:DX存放字符串的首地址,該字符串以0為結(jié)束標(biāo)志;出口參數(shù):CX存放該字符串的長度;算法描述:用BX來指針來掃描字符串中的字符,如果遇到其結(jié)束標(biāo)志,則停止掃描字符串操作StrLenPROCPUSHAXPUSHBX;用堆棧來保存子程序所用到的寄存器內(nèi)容XORCX,CXXORAL,ALMOVBX,DXagain:CMP[BX],ALJZoverINCCX;增加字符串的長度INCBX;訪問字符串的指針向后移JMPagainover:POPBX;恢復(fù)在子程序開始時(shí)所保存的寄存器內(nèi)容POPAXRETStrLenENDP7.3子程序的參數(shù)傳遞子程序一般都是完成某種特定功能的程序段。當(dāng)一個(gè)程序調(diào)用一個(gè)子程序時(shí),通常都向子程序傳遞若干個(gè)數(shù)據(jù)讓它來處理;當(dāng)子程序處理完后,一般也向調(diào)用它的程序傳遞處理結(jié)果,我們稱這種在調(diào)用程序和子程序之間的信息傳遞為參數(shù)傳遞。用程序向子程序傳遞的參數(shù)稱為子程序的入口參數(shù),子程序向調(diào)用它的程序傳遞的參數(shù)稱為子程序的出口參數(shù)。子程序的入口參數(shù)和出口參數(shù)都是任意項(xiàng),對某個(gè)具體的子程序來說,要根據(jù)具體情況來確定其入口和出口參數(shù),也可以二者都沒有。程序和被調(diào)用子程序之間的參數(shù)傳遞方法是程序員自己或和別人事先約定好的信息傳遞方法。這種信息傳遞方法可以是多種多樣的,在本節(jié),我們只介紹

常用的、行之有效的參數(shù)傳遞方法有:寄存器傳遞參數(shù)、約定存儲(chǔ)單元傳遞參數(shù)和堆棧傳遞參數(shù)等。如果對其它的參數(shù)傳遞方法感興趣的話,可參考其它《匯編語言程序設(shè)計(jì)》書籍。7.3.1寄存器傳遞參數(shù)一方面,由于CPU中的寄存器在任何程序中都是“可見”的,一個(gè)程序?qū)δ臣拇嫫髻x值后,在另一個(gè)程序中就能直接使用,所以,用寄存器來傳遞參數(shù)最直接、簡便,也是最常用的參數(shù)傳遞方式。但另一方面,CPU中寄存器的個(gè)數(shù)和容量都是非常有限,所以,該方法適用于傳遞較少的參數(shù)信息。例7.1是用寄存器傳遞參數(shù)的例子,子程序處理的數(shù)據(jù)被保存在寄存器AL中。假設(shè)有下列的程序段:MOVCALLAL,'b'UPPER;子返回時(shí),MOVCALLAL,'b'UPPER;子返回時(shí),(AL)='B'MOVCALLAL,'2'UPPER;子返回時(shí),AL的值不變,因?yàn)?2'不是字母例7.3按五位十進(jìn)制的形式顯示寄存器BX中的內(nèi)容,如果BX的值小于0,則應(yīng)在顯示數(shù)值之前顯示負(fù)號(hào)'-'。例如:(BX)=123,顯示:00123;(BX)=-234,顯示:-00234;解:;子程序功能:把寄存器BX的內(nèi)容按十進(jìn)制有符號(hào)數(shù)顯示出來;入口參數(shù):BX;出口參數(shù):無,只有顯示信息;算法描述:1、定義6個(gè)字節(jié)的存儲(chǔ)單元2、 先判斷BX是否小于零,如果是,則先顯示負(fù)號(hào)'-',再取BX的絕對值;3、 采用除10,得余數(shù)的方法,從低位向高位求出每位十進(jìn)制位;4、 輸出數(shù)據(jù)的字符串。SubDataSEGMENTDB5DB5DUP('0'),0ah,0dh,'$';0ah、0dh:換行、回車SubDataDISPBXSubDataDISPBXENDSPROCDSDSDXCXAXASSUMEDS:SubDataPUSHPUSHPUSHPUSH

MOVAX,SubData;取子程序所用的數(shù)據(jù)區(qū)段地址MOVDS,AXCMPBX,0JGEnextMOVDL,'-'MOVAH,2INT21H;顯示負(fù)號(hào)'-'NEGBX;求-BX,使其值為正數(shù)next:MOVSI,4MOVAX,BXMOVCX,10Dagain:XORDX,DXIDIVCX;DX存放余數(shù),AX存放商ADDDL,'0'MOV[SI],DLDECSIJGEagainXORDX,DXMOVAH,9INT21H;調(diào)用中斷21的功能9,顯示DS:DX指向的字符串POPAXPOPCXPOPDXPOPDSRETDISPBXENDP7.3.2約定存儲(chǔ)單元傳遞參數(shù)在調(diào)用子程序時(shí),當(dāng)需要向子程序傳遞大量數(shù)據(jù)時(shí),因受到寄存器容量的限制,就不能采用寄存器傳遞參數(shù)的方式,而要改用約定存儲(chǔ)單元的傳送方式。這種參數(shù)傳遞方式有點(diǎn)象情報(bào)人員和聯(lián)絡(luò)人員之間的傳遞信息方式,一個(gè)向指定地點(diǎn)放情報(bào),另一個(gè)從指定地點(diǎn)取情報(bào)。例7.2是采用約定存儲(chǔ)單元傳遞參數(shù)的例子,所處理的數(shù)據(jù)不是直接傳給子程序,而是把存儲(chǔ)它們的地址告訴子程序。例7.4:編寫一個(gè)子程序分類統(tǒng)計(jì)出一個(gè)字符串中數(shù)字字符、字母和其它字符的個(gè)數(shù)。該字符串的首地址用DS:DX來指定(以0為字符串結(jié)束),各類字符個(gè)數(shù)分別存放BX、CX和DI中。解:;子程序功能:分類統(tǒng)計(jì)出字符串中數(shù)字字符、字母和其它字符的個(gè)數(shù);入口參數(shù):DS:DX指向被統(tǒng)計(jì)的字符串

;出口參數(shù):BX、CX和DI分別保存數(shù)字字符、字母和其它字符的個(gè)數(shù);算法描述:1、當(dāng)字符在'0'~'9'范圍時(shí),數(shù)字字符個(gè)數(shù)BX加1;2、 為了判斷簡單,先把字字母變成大寫字母;3、 當(dāng)字符在'A'~'Z'范圍時(shí),字母個(gè)數(shù)CX加1;4、 否則,其它字符個(gè)數(shù)DI加1。COUNTPROCPUSHAXPUSHSIXORBX,BXXORCX,CXXORDI,DI;上三條指令使各類字符計(jì)數(shù)清零MOVSI,DXagain:MOVAL,[SI]INCSICMPAL,0JEoverCMPAL,'0'JLotherCMPAL,'9'JGnextINCBX;數(shù)字字符個(gè)數(shù)加1JMPagainnext:CALLUPPER;調(diào)用子程序把AL中的字母變成大寫字母CMPAL,'A'JLotherCMPAL,'Z'JGotherINCCX;字母個(gè)數(shù)加1JMPagainother:INCDI;其它字符個(gè)數(shù)加1JMPagainover:POPSIPOPAXRETCOUNTENDP例7.5顯示出任意字符串中數(shù)字字符、字母和其它字符的個(gè)數(shù)。解:.MODELSMALL.DATAMSGDB'KSDJL0984/[]3oiuOIUOIU(*&(5341',0.CODE.STARTUPLEADX,MSG;DS:DX指向待統(tǒng)計(jì)的字符串CALLCOUNT;調(diào)用子程序統(tǒng)計(jì)出各類字符的個(gè)數(shù)CALLDISPBXMOVBX,CX;調(diào)用子程序顯示數(shù)字字符的個(gè)數(shù)CALLDISPBXMOVBX,DI;調(diào)用子程序顯示字母的個(gè)數(shù)CALLDISPBX.EXIT0END;調(diào)用子程序顯示其它字符的個(gè)數(shù)7.3.3堆棧傳遞參數(shù)堆棧是一個(gè)特殊的數(shù)據(jù)結(jié)構(gòu),它通常是用來保存程序的返回地址。當(dāng)用它來傳遞參數(shù)時(shí),勢必會(huì)造成數(shù)據(jù)和返回地址混合在一起的局面,用起來要特別仔細(xì)。具體做法如下:、當(dāng)用堆棧傳遞入口參數(shù)時(shí),要在調(diào)用子程序前把有關(guān)參數(shù)依次壓棧,子程序從堆棧中取到入口參數(shù);、當(dāng)用堆棧傳遞出口參數(shù)時(shí),要在子程序返回前,把有關(guān)參數(shù)依次壓棧(這里還需要做點(diǎn)額外操作,要保證返回地址一定在棧頂),調(diào)用程序就可以從堆棧中取到出口參數(shù)。在通常情況下,我們用堆棧傳入口參數(shù),用寄存器傳出口參數(shù)。1、用堆棧傳遞入口參數(shù)的調(diào)用方法:PUSHPara1???PUSHParan;把n個(gè)字的參數(shù)壓棧CALLSUBPRO;調(diào)用子程序SUBPRO2、在子程序中取入口參數(shù)的方法:、段內(nèi)調(diào)用子程序由于是段內(nèi)調(diào)用,所以,CALL指令只把返回地址的偏移量(即IP的內(nèi)容)壓棧,如圖7.6(a)所示。在進(jìn)入子程序后,為了能讀取傳遞過來的參數(shù),需要用BP來訪問堆棧,所以要先保護(hù)BP原來的值,再把當(dāng)前SP的值傳送給BP。于是,當(dāng)前BP所指向的堆棧單元與最后一個(gè)參數(shù)Paran之間隔著BP的原值和返回地址的偏移量,也就是說:二者之間相差4個(gè)字節(jié)。具體情況如圖7.6(b)所示。(a)、進(jìn)入子程序時(shí)堆棧情況 (b)、子程序寄存器保護(hù)后的堆棧情況圖7.6在段內(nèi)調(diào)用情況下子程序所能訪問的堆棧情況SUBPROPROCNEARPUSHBPMOVBP,SPSUBPROPROCNEARPUSHBPMOVBP,SPMOVParan,[BP+4];保護(hù)寄存器BP;用寄存器BP來訪問堆棧,讀取參數(shù);保護(hù)其它寄存器的指令;保護(hù)其它寄存器的指令MOVPara1,[BP+4+2*(n-1)]SUBPROENDP、段間調(diào)用子程序在段間調(diào)用子程序時(shí),CALL指令會(huì)把返回地址的偏移量和段寄存器CS的內(nèi)容都?jí)簵?,如圖7.7(a)所示。在進(jìn)入子程序后,與前面“段內(nèi)調(diào)用子程序”一樣,也需要用BP來讀取傳遞過來的參數(shù),所以,也要先保護(hù)BP原來的值,再把當(dāng)前SP的值傳送給BP。這時(shí),當(dāng)前BP所指向的堆棧單元與最后一個(gè)參數(shù)Paran之間隔著BP的原值、返回地址的偏移量和段地址,所以,二者之間相差6個(gè)字節(jié)。具體情況如圖7.7(b)所示。(a)、進(jìn)入子程序時(shí)堆棧情況 (b)、子程序寄存器保護(hù)后的堆棧情況圖7.7在段間調(diào)用情況下子程序所能訪問的堆棧情況在段間調(diào)用時(shí),除了多一個(gè)返回段地址外,其它的內(nèi)容與“段內(nèi)調(diào)用”的情況完全一致,所以,在讀取第i個(gè)參數(shù)時(shí),只要用[BP+6+4*(n-i)]代替[BP+4+2(n-i)]即可(假設(shè)每個(gè)參數(shù)都是字類型)。7.4寄存器的保護(hù)與恢復(fù)由于計(jì)算機(jī)的硬件資源只有一套,當(dāng)子程序修改了寄存器的內(nèi)容后,返回到調(diào)用它的程序時(shí),這些寄存器的內(nèi)容也就不會(huì)是調(diào)用子程序前的內(nèi)容。這樣,子程序修改寄存器內(nèi)容就可能變成了調(diào)用它的副作用,這種副作用常常會(huì)導(dǎo)致調(diào)用程序的出錯(cuò)。為此,在編寫子程序時(shí),除了能對作為入口和出口參數(shù)的寄存器進(jìn)行修改外,對其它寄存器的修改對調(diào)用程序來說都要是透明的,也就是說,在調(diào)用子程序指令的前后,除了作為入口和出口參數(shù)的寄存器內(nèi)容可以不同外,其它寄存器的內(nèi)容要保持不變。有時(shí),也要求作為入口參數(shù)的寄存器內(nèi)容保持不變。在子程序中,保存和恢復(fù)寄存器內(nèi)容的主要方法是:在子程序的開始把它所用到的寄存器壓進(jìn)棧,在返回前,再把它們彈出棧。這樣編寫的好處是該子程序可以被任何其它程序來調(diào)用。在調(diào)用指令前,不需要保存寄存器,在調(diào)用指令后,也無需恢復(fù)寄存器。XXXXXPROCPUSHREG1XXXXXPROCPUSHREG1…PUSHREGn………POPREGn;把子程序要使用的寄存器壓棧,REGi代表某個(gè)寄存器;子程序的處理功能語句;把前面壓棧的寄存器彈出,注意它們的次序POPREG1RETXXXXXENDP例7.2就是一個(gè)在子程序中利用堆棧來保存和恢復(fù)寄存器內(nèi)容的例子。利用堆棧來實(shí)現(xiàn)此項(xiàng)功能時(shí),應(yīng)注意以下幾點(diǎn):、用堆棧保存和恢復(fù)寄存器的內(nèi)容,要注意堆?!跋冗M(jìn)后出”的操作特點(diǎn);、通常情況下不保護(hù)入口參數(shù)寄存器的內(nèi)容,當(dāng)然,也可以根據(jù)事先的約定而對它們加以保護(hù);、如果用寄存器帶回子程序的處理結(jié)果,那么,這些寄存器就一定不能加以保護(hù);、整個(gè)子程序的執(zhí)行幾乎肯定要改變標(biāo)志位,可用PUSHF和POPF來保護(hù)和恢復(fù)標(biāo)志位,但一般在子程序中不保護(hù)標(biāo)志位,除非有此特殊需要;7.5子程序的完全定義在7.1節(jié)所給出的子程序定義格式是一個(gè)最基本的、最簡單的定義格式,它不能為子程序提供更簡潔的調(diào)用方式。在宏匯編MASM6.11系統(tǒng)中,為微機(jī)匯編語言的子程序提供了更加豐富的定義方式。雖然子程序的這種定義方式顯得稍微有點(diǎn)復(fù)雜,但它不僅為子程序的調(diào)用帶來了極大的方便,而且其調(diào)用方式與高級(jí)語言中子程序的調(diào)用方式相一致,這就大大地降低了程序員熟練掌握它的難度。7.5.1子程序完全定義格式子程序PROC[distance][langtype][visibility][<prologuearg>]名 [USES寄存器列表〕[,參數(shù)[:數(shù)據(jù)類型]]...[LOCALvarlist]子程序的程序體子程序-ENDP名定義子程序時(shí),可使用參數(shù)表來直接指明其所要的參數(shù),但程序員必須先用也些也指令,或使用<langtype>參數(shù)來說明本子程序所使用的程序設(shè)計(jì)語言類型。程序員在定義子程序時(shí),最好能象在高級(jí)語言(如:C/C++)定義過程那樣,先說明該子程序的原型(用偽指令PROTO),這樣,在調(diào)用時(shí),系統(tǒng)可以自動(dòng)進(jìn)行類型檢查,也可以使用更方便的調(diào)用偽指令I(lǐng)NVOKE來調(diào)用該子程序。有關(guān)子程序的原型說明偽指令和調(diào)用偽指令在隨后第7.5.8和7.5.9小節(jié)中加以介紹。子程序通常用RET指令來結(jié)束其執(zhí)行,也可用指令“RETn”來指明在結(jié)束子程序執(zhí)行后從堆棧彈出n個(gè)字節(jié)。有關(guān)返回指令請參閱7.2.2節(jié)中的敘述。匯編程序在處理子程序時(shí)能自動(dòng)產(chǎn)生“起始”代碼(PROLOGUECode)和“結(jié)束”代碼(EPILOGUEcode)。這兩段特殊的代碼分別完成:在調(diào)用子程序時(shí),能把傳遞給子程序的參數(shù)壓棧,在子程序結(jié)束時(shí)能把先前壓棧的參數(shù)彈出。有了這兩段代碼,程序員在調(diào)用子程序時(shí)就不用自行考慮子程序的參數(shù)傳遞問題。若子程序用指令RETN、RETF或IRETF作為子程序的結(jié)束指令,那么,匯編程序?qū)⒉簧伞敖Y(jié)束”代碼。程序員可以用自己定義宏來替代缺省的“起始”和“結(jié)束”的代碼段。這種替代方法是使用偽指令:OPTIONPROLOGUE和OPTIONEPILOGUEo若子程序沒有參數(shù)、局部變量,沒使用USES子句,也不會(huì)產(chǎn)生新的段或段組,那么,子程序是可以嵌套定義的。程序員也可以使用返回指令RETN和RETF來避免子程序的嵌套。在子程序內(nèi)部,可以在指令之前使用偽指令LOCAL來說明其局部變量,有關(guān)規(guī)定在隨后的第7.5.10節(jié)中有詳細(xì)的說明。下面就來介紹該定義格式中各個(gè)說明項(xiàng)的作用。7.5.2子程序的位距子程序的位距(Distance)有:Near、Far、Near16、Far16、Near32和Far32。子程序位距描述符告訴匯編程序該子程序是在本段之內(nèi)(Near),還是在本段之外(Far)。Near和Far描述符表示使用當(dāng)前的段規(guī)模(SegmentSize),Near16、Far16、Near32和Far32描述符是告訴匯編程序忽略當(dāng)前的段規(guī)模,而使用指定16位或32位的段規(guī)模。若選用類型Near或Far,那么,匯編程序?qū)⒏鶕?jù)當(dāng)前段的規(guī)模來決定選用16位,還是32位的Near或Far。若程序員不指定該選項(xiàng),那么匯編程序?qū)⒏鶕?jù)當(dāng)前的存儲(chǔ)模式(由.MODEL來決定)和處理機(jī)類型來決定子程序類型。若不使用偽指令.MODEL,那么,Near是缺省的類型。7.5.3子程序的語言類型子程序語言類型(LanguageType)可以是任何一種有效的程序設(shè)計(jì)語句類型,由它來告訴匯編程序?qū)⑹褂檬裁礃拥臉?biāo)識(shí)符的命名風(fēng)格、子程序的調(diào)用和返回約定。該語言類型說明可使匯編語言程序與其它語言程序達(dá)到共享的目的。所有有效的語言類型及其書寫規(guī)定如表7.1所列。表7.1語言類型及其書寫規(guī)定SYSCALLSTDCALLBasicFortranPascalXXXnXXXXXXXXXX字母大寫化XXXXXXXXXX參數(shù)從左到右參數(shù)從右到左調(diào)用程序清空堆棧保存指針寄存器BP使用VARARG參數(shù)*若使用:VARARG參數(shù),則調(diào)用程序清空堆棧,否則,被調(diào)用的子程序清空堆棧。程序員可用另外三種方法來設(shè)置程序的語言類型:.MODEL、OPTIONLANGTYPE:和命令行選項(xiàng)/Gx。若在程序和命令行中都說明了語言類型,那么,前者的說明優(yōu)先。另外,程序員也可用命令行選項(xiàng)/H來限定標(biāo)識(shí)符的最大長度。例如:Pascal語言風(fēng)格:OPTIONLANGUAGE:PASCAL、/GcC語言風(fēng)格:OPTIONLANGUAGE:C、/Gd7.5.4子程序的可見性子程序的可見性(Visibility)決定該子程序?qū)ζ渌K是否可用。它共有三個(gè)屬性值:PRIVATE、PUBLIC和EXPORToPUBLIC屬性是子程序標(biāo)準(zhǔn)的缺省屬性,但該缺省屬性可以用偽指令OPTIONPROC來修改。EXPORT屬性意味著該子程序是一個(gè)“遠(yuǎn)”的、具有PUBLIC屬性的子程序,并要求連接程序在生成可執(zhí)行文件時(shí)把其入口地址放入導(dǎo)出入口地址表中。例如:OPTIONPROC:PRIVATE ;說明子程序的可見性為:PRIVATEOPTIONPROC:EXPORT ;說明子程序的可見性為:EXPORT7.5.5子程序的起始和結(jié)束操作當(dāng)程序員想用自己定義的宏來替代缺省的“起始”和“結(jié)束”的代碼段時(shí),可用下列說明語句來實(shí)現(xiàn):OPTIONPROLOGUE:MacroNamelOPTIONEPILOGUE:MacroName2PROLOGUE和EPILOGUE分別指定MacroName1和MacroName2為“起始”和“結(jié)束”代碼段的宏名。匯編程序?qū)τ脩舳x的宏MacroName1和MacroName2的形式有較嚴(yán)格的規(guī)定,要求宏的定義形式如下:MacroNameMACROProcName,flags,argbytes,localbytes,<reglist>,userparms:VARARG該宏定義的每個(gè)參數(shù)都有詳細(xì)的說明,感興趣的讀者可看有關(guān)技術(shù)資料或MASM6.11中的幫助,詳細(xì)的說明在此從略,但建議使用缺省的宏。如果想取消當(dāng)前指定的宏名,而恢復(fù)使用缺省的“起始”和“結(jié)束”代碼段的宏名,那么,可用下列說明語句,即指定二個(gè)缺省的宏名PrologueDef和EpilogueDef。OPTIONPROLOGUE:PrologueDefOPTIONEPILOGUE:EpilogueDef若程序員不要匯編程序自動(dòng)產(chǎn)生“起始”和“結(jié)束”代碼,則可用NONE來代替說明語句中的宏名,即:OPTIONPROLOGUE:NONEOPTIONEPILOGUE:NONE7.5.6寄存器的保護(hù)和恢復(fù)保護(hù)寄存器說明子句的說明格式:USES寄存器列表該說明子句要求匯編程序?yàn)槠渖杀Wo(hù)和恢復(fù)寄存器的指令序列,即:在進(jìn)入子程序執(zhí)行指令之前,把寄存器列表中的寄存器壓進(jìn)堆棧,在結(jié)束子程序執(zhí)行時(shí),把先前壓進(jìn)堆棧的寄存器彈出,以達(dá)到保護(hù)寄存器的目的。寄存器列表:列舉出在子程序中需要保護(hù)的寄存器名,即:在子程序開始時(shí)需要把內(nèi)容進(jìn)棧的寄存器名。若有多個(gè)寄存器名,則在寄存器名之間要用“空格”來分開。例如:DsipPROCUSESAXDX,FUNC:WORD,MSG:PTRBYTEMOVDX,MSGMOVAX,FUNCINT21HRETDispENDP匯編程序在處理該子程序時(shí),會(huì)根據(jù)子句USES的作用,在第一條指令“MOVDX,MSG”之前,插入把寄存器AX和DX進(jìn)棧的指令序列,即:PUSHAXPUSHDX而在返回指令RET之前插入把寄存器DX和AX的值彈出的指令序列,即:POPDXPOPAX注意:若子程序含有多個(gè)RET或IRET指令,那么,匯編程序在每個(gè)RET或IRET指令前都將增加相應(yīng)的彈出堆棧指令序列。從子句USES的功能來看,它與前面7.4節(jié)“寄存器的包含與恢復(fù)”中所用的方法完全一致,所不同的是:用USE子句進(jìn)行寄存器保護(hù)和恢復(fù)的代碼是由匯編程序自動(dòng)產(chǎn)生的,程序員不用關(guān)心如何去做,有點(diǎn)象高級(jí)語言的編程風(fēng)格,而7.4節(jié)中的代碼則是由程序員自己來安排的。7.5.7子程序的參數(shù)傳遞子程序參數(shù)是用來向子程序傳遞信息的數(shù)據(jù)。若有多個(gè)參數(shù),則參數(shù)之間要用逗號(hào)分割。為了能說明子程序的參數(shù),程序員必須事先指定參數(shù)所遵循的語言類型或使用“語言類型”參數(shù)。參數(shù)的數(shù)據(jù)類型可以是任何一個(gè)有效的數(shù)據(jù)類型說明符或VARARG。VARARG數(shù)據(jù)類型允許向子程序傳遞“個(gè)數(shù)”不定的參數(shù),其參數(shù)之間要用逗號(hào)“,”來分開。若參數(shù)表中含有VARARG說明的參數(shù),那么,該參數(shù)一定是該子程序的最后一個(gè)參數(shù)。其規(guī)定隱含地說明了在參數(shù)表中只能有一個(gè)用VARARG說明的參數(shù)。當(dāng)子程序的語言類型是C、SYSCALL和STDCALL時(shí),在其參數(shù)表中才能使用VARARG數(shù)據(jù)類型的參數(shù)。見前面的表7.1中所列。如果沒有顯式地指定某個(gè)參數(shù)的數(shù)據(jù)類型,那么,在16位段規(guī)模的情況下,其缺省的數(shù)據(jù)類型是WORD;在32位段規(guī)模的情況下,其缺省的數(shù)據(jù)類型是DWORDo7.5.8子程序的原型說明子程序原型的說明格式如下:子程序名PROTO[distance][langtype][,[parameter]:tag]...該說明語句告訴匯編程序該子程序的若干屬性,如:位距、語語言類型、參數(shù)個(gè)數(shù)及其類型等。這樣,匯編程序就可以對其定義進(jìn)行適當(dāng)?shù)臋z查。如果對所有基于堆棧的過程都定義一個(gè)原型,那么,就可把這些原型存放在一個(gè)獨(dú)立的包含文件(用偽指令I(lǐng)NCLDUE來裝入)中。使用這種方法對將來把所有子程序放入自定義的庫文件中是非常方便的。該原型說明語句中參數(shù)distance、langtype、parameter和tag等的含義與前面的敘述相一致,在此不再重復(fù)。7.5.9子程序的調(diào)用偽指令子程序調(diào)用偽指令I(lǐng)NVOKE與子程序的調(diào)用指令CALL在功能上是一致的,但它使匯編語言的子程序調(diào)用方法高級(jí)語言化,程序員可不用理會(huì)一些調(diào)用細(xì)節(jié)問題。調(diào)用偽指令I(lǐng)NVOKE的使用格式如下:INVOKEexpression[,arguments]其中:expression—地址表達(dá)式,通常為子程序名;arguments-傳遞的各參數(shù)之間用逗號(hào)',’分開,參數(shù)可以是寄存器、表達(dá)式或ADDR標(biāo)識(shí)符等。該偽指令是調(diào)用基于堆棧的子程序的方法,它把所有參數(shù)壓棧,子程序結(jié)束時(shí),又把參數(shù)自動(dòng)彈出堆棧。在參數(shù)傳遞時(shí),匯編程序?qū)⒏鶕?jù)子程序的原型進(jìn)行數(shù)據(jù)類型檢查。若需要進(jìn)行參數(shù)類型轉(zhuǎn)換的話,匯編程序則會(huì)自動(dòng)生成一段代碼來滿足其數(shù)據(jù)類型轉(zhuǎn)換的要求。例如:INVOKETEST,AX,12+34,ADDRMSG其中:TEST是子程序名,寄存器AX和表達(dá)式“12+34”是參數(shù),“ADDRMSG”是傳遞變量MSG的地址。例7.6編寫一個(gè)累加參數(shù)數(shù)值的子程序。其中參數(shù)的個(gè)數(shù)不定,參數(shù)的個(gè)數(shù)由第一個(gè)參數(shù)來確定。解:.MODELSMALL.STACK256.CODE;第一個(gè)參數(shù)parmcount確定其后面參數(shù)parmvalues中所含參數(shù)的個(gè)數(shù)ADDUPPROCNEARC,parmcount:WORD,parmvalues:VARARGXORAX,AXXORSI,SIMOVCX,parmcount.REPEATADDAX,parmvalues[SI]ADDSI,2.UNTILCXZRETADDUPENDP.STARTUPINVOKEADDUP,3,5,2,4 ;調(diào)用子程序ADDUP,計(jì)算5+2+4INVOKEADDUP,4,1,2,3,4 ;調(diào)用子程序ADDUP,計(jì)算1+2+3+4.EXIT0.END7.5.10局部變量的定義局部變量的定義格式:LOCAL變量名[[數(shù)量]][:數(shù)據(jù)類型][,變量名[[數(shù)量]][:數(shù)據(jù)類型]]...偽指令LOCAL的作用是說明一個(gè)或多個(gè)臨時(shí)的局部變量(位于堆棧中)。局部變量必須在任何指令之前加以說明,并可用多個(gè)LOCAL偽指令來說明其局部變量。在子程序中,若說明了某個(gè)局部變量,則子程序體中的指令就可使用該局部變量。匯編程序會(huì)把對它的引用轉(zhuǎn)換成用指針寄存器BP來訪問其在堆棧中的實(shí)際存儲(chǔ)單元。在局部變量的作用域與高級(jí)語言中局部變量的作用域相一致,即:局部變量只能在當(dāng)前子程序中使用,離開該子程序,它們就不能再被引用。但在局部變量的命名規(guī)則上有所不同,高級(jí)語言中的局部變量可與外層變量同名,而匯編語言中的局部變量不能與其它任何變量同名,否則,在匯編時(shí),將會(huì)給出“重定義”(Symbolredefinition)的錯(cuò)誤信息?!皵?shù)量”用來說明該變量所具有的元素個(gè)數(shù)。象高級(jí)語言的數(shù)組定義一樣,該數(shù)量必須寫在括號(hào)“[]”之中?!皵?shù)量”說明項(xiàng)是可選項(xiàng)。局部變量的類型說明符可以是任何合法的數(shù)據(jù)類型說明符。在16位段環(huán)境下,該缺省的數(shù)據(jù)類型是WORD,而在32位段環(huán)境下,該缺省的數(shù)據(jù)類型是DWORD。此處偽指令LOCAL的作用與9.3.1節(jié)中偽指令LOCAL的作用是完全不同的,具體的差異請見9.3.1節(jié)中的比較。例如:LOCALdata[20]:BYTE,num:WORD在上例的說明中,定義了二個(gè)局部變量:data和num。前者是字節(jié)類型,并有20個(gè)元素,后者是字類型,只有其自身1個(gè)元素。7.6子程序庫庫文件對學(xué)過C/C++語言程序設(shè)計(jì)的讀者來說應(yīng)該是不會(huì)陌生的,該語言的程序設(shè)計(jì)環(huán)境提供了大量的庫文件,也就是說,提供了大量的標(biāo)準(zhǔn)函數(shù)或過程。在本節(jié)里,介紹讀者如何創(chuàng)建自己的庫文件。7.6.1建立庫文件命令LIB宏匯編MASM系統(tǒng)提供了建立庫文件的命令文件LIB.EXE。其通常是在命令行環(huán)境(MS-DOS方式)下使用的,當(dāng)然,也可在Windows95/98等環(huán)境下利用其“開始”菜單下的“運(yùn)行”功能項(xiàng)來使用。一、 MS-DOS系統(tǒng)顯示命令LIB用法的命令如下:???>lib/?該命令的顯示結(jié)果如圖7.9中所示。二、 Windows系統(tǒng)圖7.8運(yùn)行LIB命令的畫面圖7.9顯示LIB命令功能的畫面命令LIB的使用方式和顯示結(jié)果如圖7.8和7.9所示。三、命令顯示內(nèi)容的解釋1)、各選項(xiàng)的解釋選項(xiàng)含義/?、/HELP顯示LIB命令的用法,描述各命令行參數(shù)的含義/IGNORECASE/NOIGNORECASE忽略子程序名中的大小寫 在實(shí)踐中,作用不明不忽略子程序名中的大顯小寫/NOEXTDICTIONARY不建立擴(kuò)展的目錄/NOLOGO不顯示版本號(hào)和版權(quán)信息/PAGESIZE:n設(shè)置庫文件的每頁字節(jié)數(shù)為n2)、命令項(xiàng)的解釋:選項(xiàng)含義+name向庫文件中加一個(gè)新的目標(biāo)文件name從庫文件中刪除一個(gè)指定的目標(biāo)文件+name用新的目標(biāo)文件替換掉庫文件中原有的目標(biāo)文件*name拷貝出指定的目標(biāo)文件*name從庫文件中移出指定的目標(biāo)文件在弄懂了LIB的各項(xiàng)功能含義后,讀者就可根據(jù)自己的需要來建立庫文件了。7.6.2建立庫文件舉例假設(shè)現(xiàn)有目標(biāo)文件subl.obj、sub2.obj和sub3.obj,要用它們建立庫文件mylib.lib??捎孟铝蟹椒▉斫⒃搸煳募悍椒?:所有目標(biāo)文件都準(zhǔn)備好了,可一次性把它們加入到庫文件中???>libmylib+sub1+sub2+sub3方法2:隨著目標(biāo)文件的逐個(gè)生成,而依次把它們加入到庫文件中???>libmylib+sub1???>libmylib+sub2???>libmylib+sub3假如源文件sub3.asm已修改,并也生成了新的目標(biāo)文件sub3.obj,這時(shí),就需要把庫文件mylib.lib中的sub3.obj替換成新的目標(biāo)文件。于是,可用下面命令來實(shí)現(xiàn)替換:???>libmylib-+sub3當(dāng)提示輸入目標(biāo)庫文件名(Outputlibrary)時(shí),可按“回車”用默認(rèn)的原庫文件名。如果想查看庫文件mylib.lib中各文件的大小和存放的先后次序,可用下列命令:???>libmylib,list ;把庫文件mylib.lib中的文件結(jié)構(gòu)生成到文件list中…〉typelist7.6.3庫文件的應(yīng)用在開發(fā)一個(gè)功能較弱的應(yīng)用程序時(shí),其執(zhí)行文件通??捎梢粋€(gè)目標(biāo)文件連接而成,當(dāng)開發(fā)一個(gè)功能較強(qiáng)、關(guān)系較復(fù)雜的應(yīng)用程序時(shí),其執(zhí)行文件很難由一個(gè)目標(biāo)文件連接而成,常常是由多個(gè)目標(biāo)文件(模塊)連接而成的。各模塊之間無疑會(huì)存在著相互調(diào)用、相互訪問數(shù)據(jù)單元等內(nèi)在聯(lián)系,各模塊之間的相互聯(lián)系就產(chǎn)生了這樣的問題:程序員如何在源程序中來表達(dá)這種聯(lián)系?為了解決描述各模塊之間的聯(lián)系,匯編語言提供了二條偽指令PUBLIC和EXTRN,它們的作用有點(diǎn)象C/C++語言說明變量、過程和函數(shù)是“全局的”或“外部的”。這二條偽指令的具體用法和含義如下:1、 偽指令PUBLIC偽指令PUBLIC是用來說明:當(dāng)前模塊中哪些標(biāo)識(shí)符是能被其它模塊引用的公共標(biāo)識(shí)符。其說明的一般格式如下:PUBLIC標(biāo)識(shí)符1,標(biāo)識(shí)符2,……其中:“標(biāo)識(shí)符”可以是變量名、過程名和程序標(biāo)號(hào),各標(biāo)識(shí)符之間要用逗號(hào)分開。上面說明語句說明了標(biāo)識(shí)符1、標(biāo)識(shí)符2等是公共標(biāo)識(shí)符,可以被其它模塊引用。在一個(gè)模塊中,可用多條PUBLIC偽指令來說明公共標(biāo)識(shí)符。2、 偽指令EXTRN偽指令EXTRN是用來說明:在當(dāng)前模塊所使用的標(biāo)識(shí)符中,哪些標(biāo)識(shí)符是已在其它模塊中被定義為指定類型的標(biāo)識(shí)符。如果當(dāng)前模塊使用了其它模塊的標(biāo)識(shí)符,而對它又不加以說明的話,那么,在匯編時(shí),匯編程序?qū)?huì)給出下列出錯(cuò)信息:errornnnnn:undefinedsymbol:XXXXXX其中:“nnnnn”是錯(cuò)誤號(hào),“XXXXXX”是當(dāng)前模塊中沒有定義的標(biāo)識(shí)符。偽指令EXTRN的一般說明格式如下:EXTRN標(biāo)識(shí)符1:類型1,標(biāo)識(shí)符2:類型2,……其中:“標(biāo)識(shí)符”和“類型”之間要用冒號(hào)“:”連接。上面語句說明了標(biāo)識(shí)符1、標(biāo)識(shí)符2等是外部標(biāo)識(shí)符,它們在其它模塊中已被分別定義為類型1、類型2等,該類型說明符可以是:NEAR、FAR、BYTE、WORD、DWORD等之一。如果在一條說明偽指令中說明了多個(gè)標(biāo)識(shí)符,那么,各標(biāo)識(shí)符之間要用逗號(hào)分開。在一個(gè)模塊中,可用多條EXTRN偽指令來說明本模塊所引用的外部標(biāo)識(shí)符。注意:偽指令EXTRN中所說明的標(biāo)識(shí)符必須在其定義的模塊中被PUBLIC偽指令說明為公共標(biāo)識(shí)符,并且其說明的標(biāo)識(shí)符類型要與該標(biāo)識(shí)符在定義是的類型相一致,否則,要么不能生成其可執(zhí)行文件,要么其執(zhí)行文件不能正確運(yùn)行。例7.7把例7.3、7.4和7.5合并在一起生成一個(gè)可執(zhí)行文件,假設(shè)它們所對應(yīng)的源程序名分別為Count.ASM、DispBX.ASM和Main.ASM。解:由于在源文件Count.ASM中調(diào)用了子程序UPPER,所以,例7.1的程序也必須加入到本題中。假設(shè)其源文件名為Upper.ASM。由于生成本題的執(zhí)行文件需要四個(gè)模塊,模塊之間存在著調(diào)用關(guān)系,所以,在有關(guān)源文件中需要說明某些標(biāo)識(shí)符為外部屬性,或說明其為公共屬性。為了把前面例子中的子程序改寫成可匯編的程序,需要添加一些簡單的說明語句或進(jìn)行簡單修改,其添加或改寫的部分已在下面用“下劃線”表示出來。;源文件Upper.ASM;子程序說明信息:……PUBLICUPPERSegUprSEGMENT'code'UPPERPROCFAR ;例7.1中的程序段,在此從略UPPERENDPSegUprENDSEND;源文件DispBX.ASM;子程序說明信息:……PUBLICDISPBXSubDataSEGMENTDB5DUP('0'),0ah,0dh,'$'SubDataENDSSegDispSEGMENT'code'DISPBXPROCFAR ;例7.3中的程序段,在此從略DISPBXENDPSegDispENDSEND;源文件Count.ASM;子程序說明信息:……PUBLICCOUNTEXTRNUPPER:FARSegCountSEGMENT'code'COUNTPROCFAR ;例7.4中的程序段,在此從略COUNTENDPSegCountENDSEND;源文件Main.ASMEXTRNCOUNT:FAR,DISPBX:FAR.MODELSMALL.DATASTRDB'KSDJL0984/[]3oiuOIUOIU(*&(5341',0.CODE.STARTUPLEADX,STRCALLCOUNT ;調(diào)用子程序統(tǒng)計(jì)出各類字符的個(gè)數(shù)CALLDISPBX ;調(diào)用子程序顯示數(shù)字字符的個(gè)數(shù)MOVBX,CXCALLDISPBX ;調(diào)用子程序顯示字母的個(gè)數(shù)MOVBX,DICALLDISPBX ;調(diào)用子程序顯示其它字符的個(gè)數(shù).EXIT0END經(jīng)過以上改寫后,可用下列命令把它們分別匯編成目標(biāo)文件(假設(shè)已安裝了MASM編程環(huán)境):…〉MASMupper…〉MASMdispbx…〉MASMcount…〉MASMmain有了這些目標(biāo)文件后,可用以下二種方法來生成可執(zhí)行文件。方法1:把所有的目標(biāo)文件連接在一起???>linkmain+upper+count+dispbx方法2:把目標(biāo)文件upper.obj、count.obj和dispbx.obj加到自己開發(fā)的庫文件中,然后在連接時(shí),與該庫文件連接。???>libmylib+upper+count+dispbx???>linkmainMicrosoft(R)SegmentedExecutableLinkerVersion5.31.009Jul131992Copyright(C)MicrosoftCorp1984-1992.Allrightsreserved.RunFile[main.exe]:ListFile[nul.map]:Libraries[.lib]:mylib ;輸入要連接的庫文件,可用加號(hào)“+”連接多個(gè)庫文件DefinitionsFile[nul.def]:LINK:warningL4021:nostacksegment…〉main ;運(yùn)行生成

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論