




已閱讀5頁,還剩21頁未讀, 繼續免費閱讀
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
87第4章 8086/8088的匯編程序設計第4章 8086/8088的匯編程序設計匯編語言是用意義明確的助記符來表示指令的操作碼、操作數。匯編語言是面向機器的語言,不同的機器有不同的匯編語言。用匯編語言編寫的程序具有執行速度快、占用存儲空間小、實時性能好等特點。匯編語言被大量用于編寫計算機系統程序、實時控制程序等。本章是在掌握了8086/8088 CPU指令的基礎上,重點學習如何設計匯編程序,以及構成匯編程序所需要的偽指令。4-1 匯編語言的基本概念1機器語言(Machine Language)機器語言是一種用二進制表示指令和數據,能被機器直接識別的計算機語言。它的缺點是不直觀,不易理解和記憶,因此編寫、閱讀和修改機器語言程序都比較繁瑣。但機器語言程序是計算機惟一能夠直接理解和執行的程序,具有執行速度快、占用內存少等特點。 2高級語言(High Level Language)如果說機器語言是面向機器的,那么高級語言(如BASIC,FORTRAN等)則是“面向過程”的語言。利用這些語言編程,程序員可以完全不考慮機器的結構特點,不必了解和熟記機器的指令系統,僅使用一些接近人們書寫習慣的英語和數學表達式形式的語句去編制程序。這樣編寫的程序與問題本身的數學模型之間有著良好的對應關系,可在各種機器上通用(不同機器之間僅做少量修改)。但是,這種用高級語言編寫的源程序并不能在機器上直接執行,需要被翻譯成對應的目標程序(即機器語言程序),機器才能運行。把具有這種翻譯作用的程序稱為解釋程序或編譯程序,見圖4-1。 圖4-1 編譯程序的功能示意圖 由于高級語言程序是在未考慮機器的結構特點的條件下編寫的,因而它就不能充分利用某種具體CPU所具有的某些特性,而通過編譯或解釋程序生成的目標程序往往比較冗長, 占有較多的內存空間,執行時間也比較長,這就限制了它在某些場合下的運用。例如,實時的數據采集、檢測和在線的實時控制等,往往要求程序的目標代碼盡可能少占內存并有盡可能快的執行速度,在這些場合下,使用高級語言編寫的程序常常不能滿足要求。 3匯編語言(Assembly Language)匯編語言是一種采用助記符表示的程序設計語言,即用助記符來表示指令的操作碼和操作數,用標號或符號代表地址、常量或變量。助記符一般都是英文字的縮寫,以方便人們書寫、閱讀和檢查。實際上,用匯編語言編寫的匯編語言源程序就是機器語言程序的符號表示,匯編語言源程序與其經過匯編所產生的目標代碼程序之間有明顯的一一對應關系,故也稱匯編語言為符號語言。用匯編語言編寫程序能夠直接利用硬件系統的特性(如寄存器、標志、中斷系統等)直接對位、字節、字寄存器或存儲單元、I/O端口進行處理,同時也能直接使用CPU 指令系統和指令系統提供的各種尋址方式,編制出高質量的程序,這樣的程序不但占用內存空間少,而且執行速度快。當然,由于源程序和所要解決的問題的數學模型之間的關系不夠直觀,使得匯編語言程序設計需要較多的軟件開發時間,也增加了程序設計過程中出錯的可能性。用匯編語言編寫的源程序也需要翻譯成目標程序才能被機器執行。這個翻譯過程稱為匯編,完成匯編任務的程序稱為匯編程序,見圖4-2。 圖4-2 匯編程序的功能示意圖匯編程序是最早也是最成熟的一種系統軟件。它除了能夠將匯編語言源程序翻譯成機器語言程序這一主要功能外,還能夠根據用戶的要求自動分配存儲區域(包括程序區、數據區、暫存區等);自動地把各種進位制數轉換成二進制數,把字符轉換成ASCII碼,計算表達式的值等;自動對源程序進行檢查,給出錯誤信息(如非法格式,未定義的助記符、標號,漏掉操作數等)等。具有這些功能的匯編程序又稱為基本匯編(或小匯編ASM)。 在基本匯編的基礎上,進一步允許在源程序中把一個指令序列定義為一條宏指令的匯編程序,就叫做宏匯編(MASM)。它包含全部ASM功能,還增加了宏指令、結構、記錄等高級匯編語言功能。 4-2 匯編語言源程序的格式 下面是一個完整的匯編語言的源程序及相關的注釋。例4.1 要求將兩個5字節十六進制數相加,可以編寫出以下匯編語言源程序。 DATASEGMENT ;定義數據段 DATA1 DB 0F8H,60H,0ACH,74H,3BH;被加數 DATA2 DB 0C1H,36H,9EH,0D5H,20H ;加數 DATAENDS ;數據段結束 CODE SEGMENT ;定義代碼段 ASSUME CS:CODE,DS:DATA START:MOV AX,DATA MOV DS,AX ;初始化DS MOV CX,5 ;循環次數送CX MOV SI,0 ;置SI初值為0 CLC ;清CF標志LOOPER:MOV AL,DATA2SI ;取一個字節加數 ADC DATA1SI,AL ;與被加數相加 INC SI ;SI加1 DEC CX ;CX減1 JNZ LOOPER ;若不等于0,轉LOOPER MOV AH,4CH INT 21H ;返回DOSCODE ENDS ;代碼段結束 END START ;源程序結束 4-2-1 分段結構 由上面的例子可以看出,匯編語言源程序的結構是分段結構形式,一個匯編語言源程序由若干段(SEGMENT)組成,每個段以SEGMENT語句開始,以ENDS語句結束。整個源程序的結尾是END語句。 這里所說的匯編語言源程序中的段與前面討論的CPU管理的存儲器的段,既有聯系,又在概念上有所區別。我們已經知道,微處理器對存儲器的管理是分段的,因此,在匯編語言程序中也要求分段組織指令、數據和堆棧,以便將源程序匯編成為目標程序后,可以分別裝入存儲器的相應段中。 但是,以8086/8088 CPU為例,它有四個段寄存器(CS,ES,SS和DS),因此CPU對存儲器按照四個物理段進行管理,即數據段、附加段、堆棧段和代碼段。任何時侯CPU只能訪問四個物理段。而在匯編語言源程序中,設置段的自由度比較大。例如,一個源程序中可以有多個數據段或多個代碼段等等。一般來說,匯編語言源程序中段的數目可以根據實際需要而設定。為了和CPU管理的存儲器物理段相區別,我們將匯編語言程序中的段稱為邏輯段。在不致發生混淆的地方,有時簡稱為段。在上面的簡單源程序中只有兩個邏輯段,一個邏輯段的名字是DATA,其中存放著與程序有關的數據,稱為邏輯數據段;另一個邏輯段的名字是CODE,其中包含著程序的指令,稱為邏輯代碼段。每個段內均有若干行語句(STATEMENT),因此,可以說一個匯編源程序是由一行一行的語句組成的。下面我們來討論匯編語言語句的類型和組成。 4-2-2 匯編語言語句的類型和格式 1語句的類型 匯編語言源程序中的語句可以分為兩種類型:指令語句和偽指令語句。 (1) 指令語句:它是能產生目標代碼,CPU 可以執行的能完成特定功能的語句。 (2) 偽指令語句:它是一種不產生目標代碼的語句,它僅僅在匯編過程中告訴匯編程序應如何匯編。例如,告訴匯編程序已寫出的匯編語言源程序有幾個段,段的名字是什么;定義變量,定義過程,給變量分配存儲單元,給數字或表達式命名等。顯然,偽指令語句是匯編程序在匯編時使用的。 2. 語句的格式 指令語句與偽指令語句的格式是類似的。一般情況下,匯編語言的語句可以由部分構成: 名字 助記符 操作數 ;注釋其中帶方括號的部分表示任選項,可以有,也可以沒有。例5.1中有如下語句: LOOPER: MOV AL,DATA2SI; 取一個字節加數 DATA1 DB 0F8H,60H,0ACH,74H,3BH;被加數 第一條語句是指令語句,其中“LOOPER:”是名字,“MOV”是指令助記符,“AL,DATA2SI”是操作數,“;”后面是注釋部分。第二條語句是偽指令語句,其中“DATA1”是名字,“DB”是偽指令定義符,“0F8H,60H,0ACH,74H,3BH”是操作數,“;”后面是注釋部分。下面對匯編語言中的各個組成部分進行討論。 1) 名字 匯編語言語句的第一個組成部分是名字(Name)。在指令語句中,這個名字是一個標號。指令語句中的標號實質上是指令的符號地址。并非每條指令語句必須有標號,但如果一條指令前面有一標號,則程序中其他地方就可以引用這個標號。在例4-1中,START、LOOPER就是標號。標號后面通常有一個冒號。 標號有三種屬性:段、偏移量和類型。 標號的段屬性是定義標號在程序段的段地址。當程序中引用一個標號時,該標號的段值應在CS寄存器中。 標號的偏移量屬性表示標號所在段的起始地址到定義該標號的地址之間的字節數。偏移量是一個16位無符號數。 標號的類型屬性有兩種:NEAR和FAR。前一種標號可以在段內被引用,地址指針為2字節;后一種標號可以在其他段被引用,地址指針為4字節。如果定義一個標號時后跟冒號,則匯編程序確認其類型為NEAR。 偽指令語句中的名字可以是變量名、段名、過程名。與指令語句中的標號不同,這些偽指令語句中的名字并不總是任選的,有些偽指令規定前面必須有名字,有些則不允許有名字,也有一些偽指令的名字是任選的。即不同的偽指令對于是否有名字有不同的規定。偽指令語句的名字后面通常不跟冒號,這是它和標號的一個明顯區別。 很多情況下偽指令語句中的名字是變量名。變量名代表存儲器中一個數據區的名字。例如,例4-1中的DATA1、DATA2就是變量名。 變量也有三種屬性:段、偏移量和類型。 變量的段屬性是變量所代表的數據區所在段的段地址。由于數據區一般在存儲器的數據段中,因此變量的段地址常常在DS和ES寄存器中。 變量的偏移量屬性是該變量所在段的起始地址與變量的地址之間的字節數。 變量的類型屬性有BYTE(字節)、WORD(字)、 DWORD (雙字)、 QWORD (四字)、TBYTE(十字)等,表示數據區中存取操作對象的大小。 2) 助記符匯編語言語句中的第二個組成部分是助記符(Memonic)。 在指令語句中的第二部分是CPU指令系統中指令的助記符,如MOV、ADC等。助記符約有90多種,在第3章中已經進行了詳細的討論。 在偽指令語句中的第二部分是偽指令的定義符,如DB、SEGMENT、ENDS、END等。它們在程序中的作用是定義變量的類型、定義段以及告訴匯編程序結束匯編等。關于偽指令的作用和使用方法,將在本章4-3節中進行討論。 3) 操作數 匯編語言語句中的第三個組成部分是操作數。在指令語句中是指令的操作數,可能有單操作數或雙操作數,也可能無操作數;而在偽指令中可能有更多個操作數。當操作數不止一個時,相互之間應該用逗號隔開。 可以作為操作數的有常數、寄存器、標號、變量和表達式等。 (1) 常數。常數就是指令中出現的那些固定值,可以分為數值常數和字符串常數兩類。例如,立即數尋址時所有的立即數、直接尋址時所有的地址、ASCII字符串等都是常數。常數是除了自身的值以外,沒有其他屬性的數值。在源程序中,數值常數按其基數的不同,可有二進制數、八進制數、十進制數、十六進制數等幾種不同表示形式。匯編語言用不同的后綴加以區別。 還應指出,匯編語言中的數值常數的第一位必須是數字,否則匯編時將被看成是標識符,如常數B7H應寫成0B7H,FFH應寫成0FFH。字符串常數是由單引號括起來的一串字符。例如ABCDEFG和179。單引號內的字符在匯編時都以ASCII的代碼形式存放在存儲單元中。如上述兩字符串的ASCII代碼為41H,42H,43H,44H,48H和31H,37H,39H。字符串最長允許有255個字符。 (2) 寄存器。8086/8088CPU的寄存器可以作為指令的操作數。 (3) 標號。由于標號代表一條指令的符號地址,因此可以作為轉移(無條件轉移或條件轉移)、過程調用CALL以及循環控制LOOP指令的操作數。 (4) 變量。因為變量是存儲器中某個數據區的名字,所以在指令中可以作為存儲器操作數。 (5) 表達式。匯編語言語句中的表達式,按其性質可分為兩種:數值表達式和地址表達式。數值表達式產生一個數值結果,只有大小,沒有屬性。地址表達式的結果不是一個單純的數值,而是一個表示存儲器地址的變量或標號,它有三種屬性:段、偏移量和類型。 表達式中常用的運算符有以下幾種: 算術運算符。常用的算術運算符有:+(加),(減),*(乘),/(除)和MOD(模除,即兩個整數相除后取余數)等。 以上算術運算符可用于數值表達式,運算結果是一個數值。在地址表達式中通常只使用其中的和(加和減)兩種運算符。 邏輯運算符。邏輯運算符有:AND(邏輯“與”),OR(邏輯“或”),XOR(邏輯“異或”)和NOT(邏輯“非”)。 邏輯運算符只用于數值表達式中對數值進行按位邏輯運算,并得到一個數值結果。對地址進行邏輯運算是沒有意義的。 關系運算符。關系運算符有:EQ(等于),NE(不等),LT(小于),GT(大于),LE(小于或等于),GE(大于或等于)等。 參與關系運算的必須是兩個數值或同一段中的兩個存儲單元地址,但運算結果只可能是兩個特定的數值之一:當關系不成立(假)時,結果為0(全0);當關系成立(真)時,結果為0FFFFH(全1)。例如: MOV AX,4 EQ 3 ;關系不成立,故(AX)0 MOV AX,4 NE 3 ;關系成立,故(AX)0FFFFH 分析運算符。分析運算符用于分析一個存儲器操作數的屬性,如段值、偏移量和類型等,或取得它所定義的存儲空間的大小。分析運算符有SEG、OFFSET、TYPE、SIZE和LENGTH等。 SEG運算符。利用SEG運算符可以得到一個標號或變量所在段的段地址。例如,下面兩條指令將變量ARRAY的段地址送DS寄存器。 MOV AX,SEG ARRAY MOV DS,AX OFFSET運算符。利用OFFSET運算符可以得到一個標號或變量的偏移地址。例如: MOV DI,OFFSET DATA1 TYPE運算符。TYPE運算符的運算結果是一個數值,這個數值與存儲器操作數類型屬性的對應關系見表4-1。 下面是使用TYPE運算符的例子: VAR DW ?;變量VAR的類型為字 ARRAY DD 10 DUP(?) ;變量ARRAY的類型為雙字 STR DB THIS IS TEST;變量STR的類型為字節 MOVAX,TYPE VAR ;(AX)2 MOV BX,TYPE ARRAY ;(BX)4 MOV CX,TYPE STR ;(CX)1 表4-2 TYPE指令返回值與類型的關系 LENGTH運算符。如果一個變量已用重復操作符DUP說明其變量的個數,則利用LENGTH 運算符可得到這個變量的個數。如果未用DUP說明,則得到的結果總是1。例如,上面的例子中已經用“10 DUP(?)”說明變量ARRAY的個數,則LENGTH ARRAY的結果為10。 SIZE運算符。如果一個變量已用重復操作符DUP說明,則利用SIZE 運算符可得到分配給該變量的字節總數。如果未用DUP說明,則得到的結果是TYPE運算的結果。例如,上面的例子中變量ARRAY的個數為10,類型為DWORD(雙字),因此,SIZE ARRAY的結果為10440。由此可知,SIZE的運算結果等于LENGTH的運算結果乘以TYPE 的運算結果。 合成運算符。合成運算符可以用來建立或臨時改變變量或標號的類型或存儲器操作數的存儲單元類型。合成運算符有PTR、THIS、SHORT等。 PTR運算符。PTR運算符可以指定或修改存儲器操作數的類型,例如:INC BYTE PTRBXSI指令中利用PTR運算符明確規定了存儲器操作數的類型是BYTE(字節),因此, 本指令將一個字節型存儲器操作數加1。 利用PTR運算符可以建立一個新的存儲器操作數,它與原來的同名操作數具有相同的段和偏移量,但可以有不同的類型。不過這個新類型只在當前語句中有效。例如: STUFF DD ? ;定義STUFF為雙字類型變量 MOV BX,WORD PTR STUFF ;從STUFF中取一個字到BX THIS運算符。THIS運算符也可指定存儲器操作數的類型。使用THIS運算符可以使標號或變量更具靈活性。例如,要求對同一個數據區既可以字節為單位,又可以字為單位進行存取,則可用以下語句:TAB1 EQU THIS WORDTAB2 DB 100 DUP(?)上面TAB1和TAB2實際上代表同一個數據區,其中共有100個字節,但TAB1的類型為WORD(字類型),而TAB2的類型為BYTE(字節類型)。 SHORT運算符。SHORT運算符指定一個標號的類型為SHORT(短標號),即標號到引用該標號指令之間的距離在128+127個字節的范圍內。短標號可以被用于無條件轉移指令中。使用短標號的指令比使用缺省的近標號的指令少一個字節。 其他運算符。 段超越運算符“:”。運算符“:”(冒號)跟在段寄存器名(DS,ES,SS和CS)之后,表示段超越,用以給一個存儲器操作數指定一個段屬性,而不管其原來隱含的段是什么。例如: MOV AX,ES:DI 字節分離運算符LOW和HIGH。運算符LOW和HIGH分別得到一個數值或地址表達式的低位和高位字節。例如:STUFF EQU 0ABCDHMOVAH,HIGH STUFF ;(AH)0ABH MOV AL,LOW STUFF ;(AL)0CDH 以上介紹了表達式中使用的各種運算符,如果一個表達式同時具有多個運算符,則按以下規則運算:見表5-2。表5-2 運算符的優先級 優先級高的先運算,優先級低的后運算。 優先級相同時按表達式中從左到右的順序運算。 括號可以提高運算的優先級,括號內的運算總是在相鄰的運算之前進行。 4) 注釋 匯編語言語句的最后一個組成部分是注釋。對于一個匯編語言語句來說,注釋部分并不是必要的,但是加上適當的注釋以后,可以增加源程序的可讀性。一個較長的實用程序,如果從頭到尾沒有任何注釋,可能很難讀懂。因此,最好在重要的程序段前面以及關鍵處加上簡明扼要的注釋。注釋前面要求加上分號(;)。如果注釋的內容較多,超過一行,則換行以后前面還要加上分號。注釋也可以從一行的最前面開始,以表示對一個程序段的說明。匯編程序對于注釋不予理會,即注釋對匯編后產生的目標程序沒有任何影響。4-3 偽指令語句偽指令無論表示形式或其在語句中所處的位置,都與指令相似。但二者之間有著重要的區別。首先,指令是給CPU的命令,在運行時由CPU執行,每條指令對應CPU的一種特定的操作,例如傳送、加法等;而偽指令是給匯編程序的命令,在匯編過程中由匯編程序進行處理,例如定義數據、分配存儲區、定義段以及定義過程等。其次,匯編以后,每條指令產生一一對應的目標代碼;而偽指令則不產生與之相應的目標代碼。宏匯編程序MASM提供了幾十種偽指令,其中有一些偽指令小匯編ASM不能支持,如宏處理其等。根據其功能,偽指令大致可以分為以下幾類: 數據定義偽指令 符號定義偽指令 段定義偽指令 過程定義偽指令 宏處理偽指令 模塊定義與連接偽指令 處理器選擇偽指令 條件偽指令 列表偽指令 其他偽指令 4-3-1 數據定義偽指令數據定義偽指令的用途是定義一個變量的類型,給變量賦初值,或者僅僅給變量分配存儲單元,而不賦予特定的值。數據定義偽指令有DB,DW,DD,DF,DQ,DT等,而常用的是前三種。數據定義偽指令的一般格式為:變量名 偽指令定義符 操作數,操作數其中方括號中的變量名為任選項,可以有,也可以沒有。變量名后面不跟冒號。偽指令定義符后面的操作數可以不止一個。如有多個操作數,相互之間應該用逗號分開。 1. DB (Define Byte)定義變量的類型為字節(BYTE),給變量分配字節或字節串。 DB偽指令定義符后面的操作數每個占有1個字節。2DW (Define Word)定義變量的類型為字(WORD)。DW偽指令定義符后面的操作數每個占有1個字,即2個字節。在內存中存放時,低位字在前,高位字在后。 3DD (Define Double word)定義變量的類型為雙字(DWORD)。DD后面的操作數每個占有2個字,即4個字節。在內存中存放時,低位字在前,高位字在后。數據定義偽指令定義符后面的操作數可以是常數、表達式或字符串,但每項操作數的值不能超過由偽指令定義符所定義的數據類型限定的范圍。例如,DB偽指令定義數據的類型為字節,則其范圍為無符號數:0255;帶符號數:128+127,等等。字符串必須放在單引號中。另外,超過兩個字符的字符串只能用DB偽指令定義。請看下列語句: DATADB 101,0F0H ;存入65H,F0H EXPRDB 2*8+7 ;存入17H STR DB WELCOME! ;存入8個字符的ASCII碼值AB DB AB ;存入41H,42HBADW AB ;存入42H,41HABDD DD AB ;存入42H,41H,00,00OFFAB DW AB ;存入變量AB的偏移地址ADRS DW STR,STR3,STR5 ;存入3個偏移地址 TOTAL DD DATA ;先存DATA的偏移地址,再存段地址 以上第一和第二句中,分別將常數和表達式的值賦予一個變量。 第三句的操作數是包含8個字符的字符串(只有DB偽指令才能用)。在第四、五、六句,注意偽指令DB、DW和 DD的區別,雖然操作數均為 AB 兩個字符,但存入變量的內容各不相同。第七句的操作數是變量AB,而不是字符串,此句將AB的16位偏移地址存入變量OFFAB。 第八句存入三個等距的偏移地址,共占6字節。第九句中的 DD 偽指令定義符將 DATA 的偏移地址和段地址順序存入變量TOTAL,共占2個字。 除了常數、表達式和字符串外,問號“?”也可以作為數據定義偽指令的操作數,此時僅給變量保留相應的存儲單元,而不賦予變量某個確定的初值。當同樣的操作數重復多次時,可用重復操作符“DUP”表示,其形式為:n DUP(初值 ,初值,)其中圓括號中為重復的內容,n為重復次數。如果用“n DUP(?) ”作為數據定義偽指令定義符的惟一操作數,則匯編程序產生一個相應的數據區,但不賦任何初值。重復操作符“DUP”可以嵌套。下面是用問號或“DUP”表示操作數的幾個例子: FILLERDB ?SUM DW ? DB ?,?,?BUFFERDB 10 DUP(?)ZERODW 30 DUP(0)MASKDB 5 DUP(OK!)ARRAYDB 100 DUP(3 DUP(8),6) 其中第一、第二句分別給字節變量FILLER和字變量SUM分配存儲單元,但不賦予特定的值。第三句給一個沒有名稱的字節變量賦予3個不確定的值。第四句給變量BUFFER分配10個字節的存儲空間,但不賦任何初值。第五句給變量ZERO分配一個數據區,共30個字(即60字節),每個字的內容均為零。第六句定義一個數據區,其中有5個重復的字符串OK!,共占15字節。最后一句將變量ARRAY定義為一個數據區,其中包含重復100次的內容:8,8,8,6,共占400個字節。 通常把用DUP作為惟一操作數而定義的變量稱為數組。下面是幾個錯誤的數據定義偽指令語句:ERROR1: DW 99 ;變量名后有冒號ERROR2 DB 25*90 ;DB的操作數超過255ERROR3 DD 1234 ;DD的操作數是超過2個字符的字符串 4-3-2 符號定義偽指令符號定義偽指令的用途是給一個符號重新命名,或定義新的類型屬性等。符號包括匯編語言的變量名、標號名、過程名、寄存器名以及指令助記符等。常用的符號定義偽指令有EQU、(等號)和LABLE。1EQU 格式: 名字 EQU 表達式 EQU偽指令將表達式的值賦予一個名字。以后可用這個名字來代替上述表達式。 格式中的表達式可以是一個常數、符號、數值表達式或地址表達式等。例如: CR EQU 0DH ;常數LF EQU 0AH A EQU ASCII_TABLE ;變量STR EQU 64*1024 ;數值表達式 ADR EQU ES:BP+DI+5 ;地址表達式CBD EQU AAM ;指令助記符 利用EQU偽指令,可以用一個名字代表一個數值,或用一個較簡短的名字來代替一個較長的名字。如果源程序中需要多次引用某一表達式,則可以利用EQU偽指令定義符給其賦一個名字,以代替程序中的表達式,從而使程序更加簡潔,便于閱讀。將來如果改變表達式的值,也只需修改一處,使程序易于維護。需要注意一個問題:EQU偽指令不允許對同一符號重復定義。 2=(等號) 格式: 名字=表達式 = (等號)偽指令的功能與EQU偽指令基本相同,主要區別在于它可以對同一個名字重復定義。例如: COUNT=100 MOV CX,COUNT ;(CX)100 COUNT=COUNT10 MOV BX,COUNT ;(BX)903LABLE 格式: 名字 LABLE 類型LABLE偽指令的用途是定義標號或變量的類型。變量的類型可以是BYTE、WORD、DWORD等;標號的類型可以是NEAR或FAR。利用LABEL偽指令可以使同一個數據區兼有BYTE和WORD兩種屬性,這樣,在以后的程序中可根據不同的需要分別以字節或字為單位存取其中的數據。例如: AREAW LABEL WORD ;變量AREAW的類型為WORD AREAB DB 100 DUP(?) ;變量AREAB的類型為BYTE MOV AREAW,AX ;AX送第1和第2字節中 MOV AREAB49,AL ;AL送第50字節中 LABEL偽指令也可以將一個屬性已經定義為NEAR或者后面跟有冒號 (隱含屬性為NEAR)的標號再定義為FAR。例如:AGAINF LABEL FAR ;定義標號AGAINF的屬性為FAR AGAIN: PUSH AX ;定義標號AGAIN的屬性為NEAR上面的過程既可以利用標號AGAIN在本段內被調用,也可以利用標號AGAINF被其他段調用。 4-3-3 段定義偽指令段定義偽指令的用途是在匯編語言源程序中定義邏輯段。常用的段定義偽指令有SEGMENT/ENDS和ASSUME等 。 1SEGMENT/ENDS 格式: 段名 SEGMENT 定位類型 組合類型 類別 段名 ENDS SEGMENT 偽指令用于定義一個邏輯段,給邏輯段賦予一個段名,并以后面的任選項(定位類型、組合類型、類別)規定該邏輯段的其他特性。SEGMENT 偽指令位于一個邏輯段的開始部分,而ENDS偽指令則表示一個邏輯段的結束。在匯編語言源程序中,這兩個偽指令定義符總是成對出現的,二者前面的段名必須一致。兩個語句之間的部分即是該邏輯段的內容。例如,對于代碼段,其中主要有指令及其他偽指令;對于數據段和附加段,主要有定義數據區的偽指令等等。一個源程序中不同邏輯段的段名可以各不相同。 SEGMENT偽指令后面還有三個任選項:定位類型、組合類型和類別。在上面的格式中,它們都放在方括號內,表示可有可無。如果有,三者的順序必須符合格式中的規定。這些任選項是給匯編程序(MASM)和連接程序(LINK)的命令。SEGMENT偽指令后面的任選項告訴匯編程序和連接程序,如何確定段的邊界,以及如何組合幾個不同的段等。下面分別進行討論。 1) 定位 (Align) 類型定位類型任選項告訴匯編程序如何確定邏輯段的邊界在存儲器中的位置。定位類型共有以下四種: BYTE (邊界起始地址= B)該類型表示邏輯段從一個字節的邊界開始,即可以從任何地址開始。此時本段的起始地址可緊接在前一個段的后面。 WORD (邊界起始地址= 0B)該類型表示邏輯段從字的邊界開始。2字節為1個字,此時本段的起始地址必須是偶數。 PARA (邊界起始地址= 0 0 0 0B)該類型表示邏輯段從一個節(Paragraph)的邊界開始(一節等于16個字節),也即段的起始地址能被16整除。故本段的起始地址(十六進制)應為0H。如果省略定位類型任選項,則默認其為PARA。 PAGE (邊界起始地址= 0 0 0 0 0 0 0 0B) 該類型表示邏輯段從頁邊界開始(一頁等于256個字節),也即段的起始地址能被256整除。故本段的起始地址(十六進制)應為00H。 例5.2 SEGMENT偽指令定義符的定位類型應用舉例。STACKSEGMENT STACK ;STACK段,定位類型缺省 DB 100 DUP(?) ;長度為100字節STACK ENDS ;STACK段結束DATA1SEGMENT BYTE ;DATA1段,定位類型BYTE STRING DB This is an example! ;長度為19字節 DATA1 ENDS ;DTAT1段結束DATA2SEGMENT WORD ;DATA2段,定位類型WORD BUFFER DW 40 DUP(0) ;長度為40個字,即80字節 DATA2 ENDS ;DATA2段結束CODE1 SEGMENT PAGE ;CODE1段,定位類型PAGE ;假設CODE2段長度為13字節CODE1 ENDS ;CODE1段結束CODE2 SEGMENT ;CODE2段,定位類型缺省 START: MOV AX,STACK MOV SS,AX ;假設CODE2段長度為52字節CODE2 ENDS ;CODE2段結束 END START ;源程序結束 本例的源程序中共有五個邏輯段,它們的段名和定位類型分別如下:STACK段 PARADATA1段 BYTEDATA2段 WORDCODE1段 PAGECODE2段 PARA 已經知道其中STACK段的長度為100字節(64H),DATA1段的長度為19字節(13H),DATA2段的長度為40個字,即80字節(50H)。假設CODE1段占用13字節(0DH),CODE2段占用52字節(34H)。如果將以上邏輯段進行匯編和連接,然后再來觀察各邏輯段的目標代碼或數據裝入存儲器的情況。由表4-3可清楚地看出,當SEGMENT偽指令的定位類型不同時,對段起始邊界的規定也不相同。 表4-3 例4-2各邏輯段的起始地址和結束地址 段 名定位類型字節數起始地址結束地址STACKPARA100(64H)00000H00063HDATA1BYTE19(13H)00064H00076HDATA2WORD80(50H)00078H000C7HCODE1PAGE13(0DH)00100H0010CHCODE2PARA52(34H)00110H00143H2) 組合(Combine)類型 SEGMENT偽指令的第二個任選項是組合類型,它告訴匯編程序當裝入存儲器時各個邏輯段如何進行組合。組合類型共有以下六種。(1) 不組合。如果SEGMENT偽指令的組合類型任選項缺省,則匯編程序認為這個邏輯段是不組合的。也就是說,不同程序中的邏輯段,即使具有相同的段名,也分別作為不同的邏輯段裝入內存,不進行組合。但是,對于組合類型任選項缺省的同名邏輯段,如果屬于同一個程序模塊,則被集中成為一個邏輯段。 (2) PUBLIC。連接時,對于不同程序模塊中的邏輯段,只要具有相同的段名,就把這些段集中成為一個邏輯段裝入內存。(3) STACK。組合類型為STACK時,其含意與PUBLIC基本一樣,即不同程序中的邏輯段,如果段名相同,則集中成為一個邏輯段。不過組合類型STACK僅限于作為堆棧區域的邏輯段使用。順便提一下,在執行程序(.EXE)中,堆棧指針SP設置在這個集中以后的堆棧段的(最終地址1)處。 (4) COMMON。連接時,對于不同程序中的邏輯段,如果具有相同的段名,則都從同一個地址開始裝入,因而各個邏輯段將發生重疊。最后,連接以后段的長度等于原來最長的邏輯段的長度,重疊部分的內容是最后一個邏輯段的內容。(5) MEMORY。該類型表示當幾個邏輯段連接時,本邏輯段定位在地址最高的地方。如果被連接的邏輯段中有多個段的組合類型都是MEMORY,則匯編程序只將首先遇到的段作為MEMORY段,而其余的段均當作COMMON段處理。 (6) AT表達式。這種組合類型表示本邏輯段根據表達式的值定位段地址。例如AT 8A00H,表示本段的段地址為8A00H,則本段從存儲器的物理地址8A000H開始裝入。 3) 類別(Class)SEGMENT偽指令的第三個任選項是類別,類別必須放在單引號內。類別的作用是在連接時決定各邏輯段的裝入順序。當幾個程序模塊進行連接時,其中具有相同類別名的邏輯段被裝入連續的內存區,類別名相同的邏輯段,按出現的先后順序排列。沒有類別名的邏輯段,與其他無類別名的邏輯段一起連續裝入內存。 例如,假設一個主程序中有五個邏輯段,段名和類別名分別為:STK1段 STACKCODE1段 無DATA1段 BUFFER DATA2段 TABLE DATA3段 BUFFER 還有一個子程序,包括四個邏輯段,段名和類別名分別為: DATA4段 TABLE DATA5段 BUFFER STK2段 STACK CODE2段 無 當將上述主程序和子程序進行連接時,兩個程序模塊中各邏輯段裝入內存的順序見圖4-3。圖4-3 邏輯段按類別裝入內存的示意圖 2. ASSUME 格式:ASSUME 段寄存器名:段名,段寄存器名:段名,ASSUME偽指令告訴匯編程序,將某一個段寄存器設置為存放某一個邏輯段的段地址,即明確指出源程序中的邏輯段與物理段之間的關系。當匯編程序匯編一個邏輯段時,即可利用相應的段寄存器尋址該邏輯段中的指令或數據。在一個源程序中,ASSUME偽指令定義符應該放在可執行程序開始位置的前面。還需指出一點,ASSUME偽指令只是通知匯編程序有關段寄存器與邏輯段的關系,并沒有給段寄存器賦予實際的初值。例如: CODE SEGMENTASSUME CS:CODE,DS:DATA1,SS:STACKMOVAX,DATA1MOV DS,AX ;給DS賦值MOV AX,STACKMOV SS,AX ;給SS賦值CODE ENDS 4-3-4 過程定義偽指令過程也就是子程序,所以過程定義偽指令也就是子程序定義偽指令。 格式: 過程名 PROC NEAR/FAR RET 過程名 ENDP 其中PROC偽指令定義一個過程(子程序),賦予過程一個名字,并指出該過程的屬性為NEAR或FAR。如果沒有特別指明類型,則認為過程的類型是NEAR。偽指令ENDP標志過程的結束。上述兩個偽指令前面的過程名必須一致,且成對出現。當一個程序段被定義為過程后,程序中其他地方就可以用CALL指令調用這個過程。調用一個過程的格式為: CALL 過程名 過程名實質上是過程入口的符號地址,它和標號一樣,也有三種屬性:段、偏移量和類型。過程的類型屬性可以是NEAR或FAR。一般來說,被定義為過程的程序段中應該有返回指令RET,但不一定是最后一條指令,也可以有不止一條RET指令。執行RET指令后,控制返回到原來調用指令的下一條指令。NAME1PROC FAR CALL NAME2 RETNAME2PROC NEAR RETNANE2ENDPNAME1ENDP 過程的定義和調用均可嵌套。例如: 4-3-5 模塊定義與連接偽指令在編寫規模比較大的匯編語言程序時,可以將整個程序劃分成為幾個獨立的源程序(或稱模塊),然后將各個模塊分別進行匯編,生成各自的目標程序,最后將它們連接成為一個完整的可執行程序。各個模塊之間可以相互進行符號訪問。也就是說,在一個模塊中定義的符號可以被另一個模塊引用。通常稱這類符號為外部符號,而將那些在一個模塊中定義,只在同一模塊中引用的符號稱為局部符號。為了進行連接以及在這些將要連接在一起的模塊之間實現互相的符號訪問,以便進行變量傳送,常常使用以下幾個偽指令:NAME、END、PUBLIC和EXTRN。 1. NAMENAME偽指令用于給源程序匯編以后得到的目標程序指定一個模塊名,連接時需要使用這個目標程序的模塊名。其格式為:NAME 模塊名NAME的前面不允許再加上標號,例如下面的表示方式是非法的:BEGIN:NAME MODNAME如果程序中沒有NAME偽指令,則匯編程序將TITLE偽指令(TITLE屬于列表偽指令)后面“標題名”中的前六個字符作為模塊名。如果源程序中既沒有使
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 柔性微型機器人市場分析:預計年復合增長率(2025-2031)為16.8%
- 2025年6月大類資產配置報告:審慎情緒延續聚焦結構性機會
- 2025年山東省煙臺市中考道德與法治試卷及答案
- 教育行業質量評價改革:2025年認證體系構建與實施策略報告
- 自動駕駛卡車在農產品物流運輸中的保鮮技術市場前景報告
- 基于人工智能的公路貨運行業數字化轉型與物流行業智能化技術應用案例研究報告
- 2025年互聯網金融平臺資金存管安全風險管理策略與實踐案例研究
- 2025年電商平臺大數據驅動的用戶忠誠度提升與品牌形象塑造策略研究
- 2025年文化娛樂市場細分策略與消費者需求分析報告
- 電動汽車電池熱管理技術熱管理系統冷卻效率提升與2025年技術創新報告
- 2025年新疆維吾爾阿克蘇地區沙雅縣小升初數學檢測卷含解析
- 變頻器應用課件
- 人工智能在地球觀測中的應用-深度研究
- 2023年中小學心理健康教育課程標準
- 關于八段錦的英語對話
- 核心制度:安全輸血制度
- 《中華人民共和國職業分類大典》(2022年版)各行業職業表格統計版(含數字職業)
- 煤礦各類重大災害預兆
- 《銀行業金融機構安全評估標準》
- 邏輯思維訓練500題(帶答案)
- 政務公開培訓課件模板
評論
0/150
提交評論