版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、原書筆記80X86匯編語言程序設計教程宏:1. 前言:l 宏是宏匯編語言的主要特征之一!l 若某程序片段需要多次使用,為了避免重復,可以將其定義為一條宏指令,利用宏指令代表該程序片段,匯編過程中,匯編器自動將宏指令替換為原程序片段。l (2015-9-16 20:43:44更新)關于宏的問題的探討,遠不止于這些內容,對于很多的細節(jié)問題,待到以后仔細查閱,此時,就不花太多時間在這些細節(jié)上了。2. 宏指令的定義和使用a. 宏指令在使用之前一定要先定義!b. 宏指令定義的一般格式如下:1. 宏指令名MACRO形式參數表2. 3. 程序片段4. 5. ENDM6. ;以下為示例:7. GETCHARM
2、ACRO;該宏指令無參數8. movah, 19. int21H10. ENDMl MACRO和ENDM是一對偽指令,成對出現,表示宏定義的開始和結束。l 宏定義體:MACRO與ENDM之間的部分是宏定義體,可以是由指令、偽指令、宏指令構成的程序片段l 宏指令名由用戶指定,適用一般標號命名規(guī)則l 形式參數是可選的,并可以有一個或多個,多個形參之間用逗號間隔c. 宏調用:定義宏指令后,就可使用宏指令來表示對應的程序片段,這稱為宏調用。一般格式如下1. 宏指令名實參列表2. ;以下為示例:3. GETCHAR4. movah, al5. ;通過調用宏指令后,將獲得的字符,傳送至ah中d. 宏展開(
3、宏擴展):在對源程序進行匯編時,匯編程序把源程序中的宏指令替換成對應的宏定義體,這稱為宏展開或宏擴展。3. 宏指令的用途a. 縮短源代碼l 將源程序中多次用到的某個程序片段(可以實現一定的功能,如換行、獲得一個輸入、打印一個輸出等)定義成一條宏指令,在源程序中需要的地方,直接使用宏指令即可,有效的縮短了代碼的長度,使得源代碼可讀性增強。b. 擴充指令集l CPU的指令集是確定的。l 利用宏能夠在匯編語言的形式上對指令集進行擴充,擴充后的指令集是 機器指令集 與 宏指令集 的并集。l 方便了源程序的編寫,也增強了源程序的可讀性。c. 改變某些指令助記符的意義l 宏指令名可以與指令助記符或偽操作名
4、相同,同名的情況下,宏指令的優(yōu)先級最高,而同名的指令或偽操作就失效了。l 利用以上原理,就可以實現改變指令助記符的意義了。4. 宏指令中參數的使用a. 宏指令可以不帶參數,但是,帶參數的宏指令往往更加靈活。b. 宏指令的參數很靈活1) 宏指令的參數可以是常數、寄存器和存儲單元,還可以是表達式2) 宏指令的參數可以是操作碼c. 宏調用參數個數可以與定義時不一致l 紅調用時使用的實參個數應該與宏定義時的形參個數一致,但是匯編程序并不要求嚴格相等。l 處理辦法:1) 若實參個數多于形參個數,那么多余的實參將被忽略2) 若實參個數少于形參個數,那么多余的形參將用空代替,即什么也沒有3) 另外,必須保護
5、最能展開后的程序片段是正確的,有效的。5. 特殊的宏運算符a. 特殊的宏運算符運算符使用格式定義 用處&參數強迫替換運算符 宏定義字符串原樣傳遞運算符 宏調用、重復塊、重復匯編、條件匯編!字符文字字符運算符 宏調用%表達式表達式運算符 宏調用;注釋宏注釋 宏定義l 以上宏運算符可用于宏定義、宏調用、重復塊b. 強迫替換運算符&l (用于)宏定義中,如果形參出現在其他字符的緊前或緊后,或者出現在帶引號的字符串中,為了使匯編器識別這是一個形參符號,就必須使用該運算符,以區(qū)分參數。以上標注黑粗體的兩句話說明了使用強迫替換運算符的兩種用法!l 注意:1) 當在宏定義中,形參前或者形參后緊鄰形參的一個(
6、注意!只有一個不會)&符號都不會被識別為其他字符(包括在字符串中的情形),而僅用作區(qū)分形參的作用。(重要)不同的是,在字符串中,多余的&會被認為是一個普通字符,而在字符串之外,&會被認為是多余的字符而出錯2) 強迫替換運算符不能用于變量或標號名!注意!c. 字符串原樣傳遞運算符l 在(用于)宏調用、重復塊和條件匯編中,將它括起來的內容作為一個字符串,也就是作為一個整體;1) 宏調用中,若實參包含逗號或空格等間隔符,則必須使用該運算符,以保證,實參的完整性;2) 若實參是某個有特殊意義的字符,為了使它只表示字符本身,也可使用該運算符,把它括起來。3) 注意!使用字符串作為實參可以有兩種情況1.
7、如果字符串之間沒有逗號或者空格等分隔符,可以將沒有雙引號擴著的字符串直接作為實參,但是,由于在宏展開過程中,是文本替換,所以,要保證,替換處的兩邊有兩個雙引號或者單引號!2. 如果字符串之間有逗號或者空格等分隔符,則必須使用字符串原樣傳遞運算符。3. 總結:實參可以有三種形式:1. 沒有雙引號或者單引號擴著的,并且其間沒有逗號或者空格等分隔符的!2. 利用字符串原樣傳遞運算符括起來的,沒有雙引號或者單引號擴著的!3. 利用字符串原樣傳遞運算符括起來的,并且有雙引號或者單引號擴著的!雙引號或者單引號包含在尖括號之間。4. 雙引號或者單引號括起來的獨立字符串對于每一種形式,對應的宏的編寫是不一樣的
8、,1. 宏中形參兩邊必須用雙引號括起來,并且,形參前必須添加強迫替換運算符!2. 同13. 宏中形參兩邊不必用雙引號括起來!4. 同3上面的論述看起來太過復雜,我們不妨約定:當傳遞字符串實參時,用尖括號括起來,其中不添加引號。在宏定義中,需要在對應的字符串替換形參兩邊添加雙引號或者單引號,并且,需要在形參前添加強迫轉換運算符&。 或者: 當傳遞字符串實參時,用雙引號或者單引號括起來,不添加尖括號。在宏定義中,沒有特殊需要!d. 文字字符運算符l 用于宏調用中的實參中!l 該運算符用于一般字符串中,使其后的一個字符只作為一般字符。e. 表達式運算符%l (用于)宏調用時,使用該運算符能把其后表達
9、式的結果作為實參進行替換,而不是表達式本身。f. 宏注釋;l 用于宏定義時!l 如果只用一個分號表示注釋的話,那么每次宏調用,注釋都會被復制一遍,為了使得宏定義中的注釋不被復制,用兩個分號對宏定義中的注釋部分進行標記。6. 宏與子程序的區(qū)別(主要表現在宏調用時的差異)a. 宏調用是通過宏指令名進行的,多少次調用就復制多少次宏定義體;子程序在源程序中只有一份;b. 宏調用時的參數傳遞方式是通過文本替換的方式進行的;子程序調用傳遞參數的方式只能通過寄存器、堆棧或約定的內存單元進行傳遞c. 宏調用在匯編時完成,不需要額外的時間開銷,但是耗費較多的空間;子程序在程序執(zhí)行時,通過調用返回指令,耗費一定的
10、時間,但是不耗費多余的存儲空間。7. 與宏有關的偽指令a. 局部變量說明偽指令LOCALl LOCAL標號表l 標號表由標號構成,標號間用逗號間隔。l 使用于(宏定義體中含有標號的宏)。l 使用于宏定義體中,必須是宏定義偽指令MACRO后的第一條語句!,MACRO與LOCAL之間不允許有注釋和分號標志b. 清除宏定義的偽指令PURGEl PURGE宏名表l 宏名表由宏名構成,宏名之間用逗號間隔。l 該指令告訴匯編程序取消宏名表中的宏,不再展開它們。該命令之后的對于該宏的調用,也就被匯編器無視掉了。l 該偽指令用于源程序中的任何地方!包括宏定義中和任何段之外,該偽指令不涉及機器指令,只用于匯編器
11、。c. 中止宏擴展的偽指令EXITMl EXITMl 用在宏定義體中,常與條件偽指令一起使用,以便在規(guī)定的條件下跳過宏內的最后的語句。l 該指令通知匯編程序結束當前宏調用的擴展,退出當前宏,回到源程序或回到外層宏。d. 以上三條與宏有關的偽指令中,LOCAL與EXITM用于宏定義體中;PURGE用于其他位置或宏定義體中。8. 宏定義的嵌套(兩種類型的嵌套)a. 宏定義體中調用宏l 宏匯編語言允許在宏定義體中進行宏調用;l 前提:在調用之前,被調用宏已經在之前定義過了b. 宏定義體中定義宏語句l 宏定義體中允許進行宏的定義;l 調用內部宏的前提:只有調用了外部宏之后,才可以調用內部宏;因為:只有
12、調用外部宏之后,內部宏才真正被定義l 當外部宏被調用后,外部宏中的代碼部分被寫入宏調用處,外部宏中的內部宏定義部分并不會被寫入,可以認為,此時,內部宏定義由于外部宏的展開,才生效,所以,內部宏調用的前提是外部宏已經被調用過了。l 這里有一個小問題涉及到匯編程序的匯編過程,以后詳解。(2015-9-16 20:41:19)8.3 重復匯編1. 前言l 程序中有時會需要連續(xù)的重復完全相同或者幾乎完全相同的一組語句,這種情況下,可以考慮使用重復偽指令定義重復塊,來簡化程序。l 重復塊是允許建立重復語句塊的宏的一種特殊形式,是一種特殊的宏。l 沒有被命名的宏,因而不能被調用!;可以有參數;參數在匯編過
13、程中可被實參替換;宏運算符、用偽指令LOCAL說明的符號 等可用于重復塊;由ENDM結束2. 偽指令REPTl 一般格式如下:1. REPT表達式2. 需要重復的語句組3. ENDM4. ;實例5. CHAR=A6. dataSEGMENT7. TABLELABELBYTE;在數據段借助rept定義數據時,前面的變量名必須以這種形式(變量名+LABEL+BYTE)定義,不可以只寫一個變量名,企圖8. REPT26;直接可以連接到下行的定義部分9. DBCHAR10. CHAR = CHAR + 111. ENDM;這是一種經典的使用方法,需要記牢,以后會有更多的更加靈活的方法等著我們去發(fā)現12
14、. dataENDSl 匯編程序將把“需要重復的語句組”連續(xù)地重復匯編由表達式值所決定的次數;l 表達式必須可以求出數值常數(16位無符號數)l 任何有效的匯編語句均可以安排在“需要重復的匯編語句組”中l(wèi) rept語句可以出現在源代碼的任何部分,前提是:被重復的語句在被重復的位置處是有效的;比如說:將指令語句重復在數據段中是無效的。3. 偽指令IRPl 一般格式如下:1. IRP形式參數,2. 需要重復的語句3. ENDM4. ;以下為一實例5. dataSEGMENT6. quartLABELBYTE;類似與上面的用法,這是一個經典的用法7. IRPX,8. DBX*X9. ENDM;定義了
15、一個名為quart的數組,數組中依次存放著09的數的平方值10. dataENDSl 參數的個數決定了重復的次數,匯編程序將把“需要復制的語句”連續(xù)地重復匯編規(guī)定的次數,并在每次匯編過程中,用相應的實參替換“需要重復的語句”中的形參。l 實參放置在一對尖括號中,與形參之間用逗號間隔,各個實參之間也用逗號進行間隔。4. 偽指令IRPCl 一般格式如下:1. IRPC形式參數,字符串2. 需重復的語句組3. ENDM4. ;以下為一個示例:5. dataSEGMENT6. TABLELABELBYTE7. IRPCX, 01234567898. DW(X+1)*29. ENDM10. dataEN
16、DSl IRPC與IRP相似,除了前者的實參數列表是一個字符串以外完全一樣l 字符串的長度規(guī)定了重復的次數,匯編程序將把“需要重復的語句組”連續(xù)地重復匯編指定的次數,并在每次匯編時依次使用“字符串”中的一個字符作為實參代替“需要重復的語句組”中的形式參數,l 如果字符串中含有空格,逗號等分隔符,那么字符串需用一對尖括號括起來!且一定不能使用雙引號或者單引號,否則雙引號或者單引號也會被當做字符串的一部分,也就是當做實參替換形參。l 如果沒有尖括號。1)空格之后的部分將會被忽略2)逗號之后的部分,連同逗號都會作為實參的一部分l 所以只要字符串之間沒有空格字符,所有的部分都會被當做實參進行傳遞,如果
17、這個實參有意義的話(一般逗號沒有意義)l 如果想要將空格作為參數的話,那就按照最初的做法,將所有參數用尖括號括起來。問題描述:在一次測試過程中,我將帶參數的重復匯編偽指令irp和irpc寫入到一個宏中,以期,通過它們在該宏中實現將四個寄存器壓入棧中的功能,如下所示:1. PUSHAMACRO2. irpR,3. pushR&x4. ENDM5. ENDM結果卻不如人意,編譯器提示了錯誤,而錯誤如下:1. Symbol not defined: RX *4這說明:pusha得到了展開,并且重復匯編指令也得到了展開,后者的實參并沒有對形參進行替換!l 如果我們在代碼中直接使用irp指令,則實參會正
18、常替換形參。l 對于具有參數的irpc也具有這樣的情形。l 但是有一種例外情況,如下所示:1. DFSQUAREMACRO2. tableLABELBYTE3. irpX,4. DBX*X5. ENDM6. ENDMl 以上發(fā)生在irp語句中包含的是定義語句時!l 此問題待定,具體原因并不知道是因為什么。以后盡量避免這樣的嵌套行為。8.4 條件匯編1. 前言:a. 條件匯編提供根據某種條件決定是否匯編某段源代碼的功能。b. 在源程序中使用條件匯編語句的主要目的是:1) 通過在匯編前或匯編時改變某種條件,從而方便地產生功能不同的程序;2) 增強宏定義能力,使得宏的適用范圍更廣;3) 改善匯編效率
19、c. 條件匯編語句在形式上與高級語言中的條件語句相似,但本質上卻是完全不同的:1) 條件匯編語句是說明性語句,由偽指令構成,功能上由匯編程序實現;2) 一般情況下,高級語言的條件語句是執(zhí)行語句,由目標程序實現其功能。2. 條件匯編偽指令a. 大概:1) 一般格式如下:1. IFxxxx條件表達式2. 語句組13. ELSE4. 語句組2;條件匯編語句的可選部分5. ENDIF2) 說明:l IFxxxx 是條件偽指令助記符的一般形式,xxxx表示構成條件偽指令助記符的其他字符;l 完整的條件偽指令助記符有:IFIFEIFDEFIFNDEFIF1IF2IFBIFNBIFIDNIFDIFl 每一個
20、條件偽指令助記符都要對應一個條件結束偽指令助記符ENDIF,這個是統(tǒng)一的,必須的l 不同的條件指令助記符形式上可能有所不同,這里僅列出一般格式l 語句組可以包含有任意正確的語句,可以包含其他條件偽指令語句l ELSE語句組2部分是可選的l 條件匯編偽指令語句的一般意義是:如果條件偽指令要求的條件滿足,那么匯編“語句組1”,否則,在ELSE+語句組2存在的情況下,匯編語句組2,如果沒有語句組2,且條件表達式不滿足,那么不進行匯編操作;l 匯編語言允許條件語句偽指令嵌套,且允許的嵌套次數足以滿足一般應用需要;l 一個嵌套的ELSE偽指令,總是與最近的但又沒有ELSE相匹配的IFxxxx偽指令相匹配
21、。b. 偽指令IF和IFE1) 一般格式:1. IF(IFE)表達式2. 語句組13. ELSE4. 語句組25. ENDIF6. ;示例如下:7. ;示例1:8. IFMFLAG;利用一個變量作為判定對象9. movah, 0;該條件匯編偽指令選擇的是是否匯編 匯編指令語句10. int16H11. ELSE12. movah, 113. int21H14. ENDIF15. ;示例2:16. IFPORT EQ0;利用一個關系表達式作為判定對象17. PORTADDR=3F8H;該條件匯編偽指令選擇的是是否匯編 匯編偽指令語句,可以看出來,相當靈活18. IVECTN=0BH19. IMA
22、SKV=11110111B20. ENDIF21. ;示例3(更加復雜的示例,與宏與重復塊相結合):22. SHIFTLMACROOP, N;定義了一個SHIFTL宏23. COUNT=024. REPTN;宏中包含了一個重復塊定義語句,將操作數OP每次向右算術左移一位,直到,移位的次數不小于N為止25. SHLOP, 126. COUNT=count + 127. IFCOUNT GE N;重復塊定義語句中又包含了一個條件匯編語句28. EXITM29. ENDIF;退出條件匯編語句30. ENDM;退出重復塊定義語句31. INCOP32. ENDM;退出宏定義語句2) 說明:l 偽指令I
23、F:如果表達式的值不等于0,則條件滿足,條件為真。非零即為真。這類似于C語言中對于條件表達式的值的判定方法。l 偽指令IFE:如果表達式的值等于0,則條件滿足,條件為真。相當于IF NOT 條件表達式,與IF偽指令恰恰相反。l 上述表達式不能包含向前引用(還不能明確這個意思。),其結果應為一常數值。一般為關系表達式或常數表達式c. 偽指令IFDEF和IFNDEF1) 一般格式:1. IFDEF(IFNDEF)符號2. 語句組13. ELSE4. 語句組25. ENDIF6. ;示例1:7. IFDEFMLARGE8. AXINCPROCFAR;如果MLARGE已被定義,那么將AXINC過程定義
24、為遠過程。9. ELSE10. AXINCPROCNEAR;否則,將AXINC定義為近過程11. ENDIF12. incax13. ret14. AXINCENDP2) 說明:l 偽指令IFDEF:如果符號已定義 或已被說明為外部符號(EXTRN偽指令進行說明),則條件滿足,即條件為真。l 偽指令IFNDEF:如果符號未定義或未被說明成外部符號,則條件滿足,即條件為真。又是一對兒相反的偽指令。l 符號可以在源程序中定義,也可以在匯編命令行中定義,后者參閱匯編器使用手冊。d. 偽指令IF1和IF21) 一般格式:1. IF1(IF2)2. 語句組13. ELSE4. 語句組25. ENDIF6
25、. ;決定匯編程序在第幾趟掃描時,匯編語句組。2) 說明:l 偽指令IF1:若是第一趟則為真l 偽指令IF2:若是第二趟則為真3. 條件匯編與宏結合a. 宏中使用條件匯編1) 條件匯編與宏結合,能大大擴大宏的使用范圍。2) 以下為一示例:1. ADDNUMMACROREG, NUM;定義一個宏2. IF(NUM GT 2) OR (NUM LE 0);3. addREG, NUM4. ELSE5. incREG6. IFNUM EQ 27. incREG8. ENDIF9. ENDIF10. ENDM;退出宏3) 說明:l 以上示例的說明:宏ADDNUM有兩個參數,在對宏調用進行擴展時,可以根
26、據實際參數的不同擴展成不同的指令!l 宏,只有當被調用時,才會在被調用的內存空間,進行宏的展開;既然已經被調用,那么肯定已經有參數向其傳遞了,所以,條件匯編指令中才能根據參數進行一些判斷,而決定展開后的命令!l 根據以上的道理來看,匯編語言提供了有關測試宏參數的條件匯編偽指令,這更加便利了我們將宏與條件匯編語句相結合!b. 用于測試宏參數的條件匯編偽指令1) 偽指令IFB和IFNBl 以下為一般格式:1. IFB2. IFNB3. ;以下為一示例:4. PRINTMACROMSG;該宏的作用:當給定實參(偏移地址)時,顯示指定的字符串,當未給定實參時,使用默認實參,打印默認信息。5. IFB6
27、. movsi, DEFAULTMSG7. ELSE8. movsi, MSG9. ENDIF10. CALLSHOWIT11. ENDM12. ;事實上,以上實現,并沒有那么簡單!以下是正確的實現方法!詳情見注釋13. PRINT MACRO MSG14. LOCAL begin,DEFAULTMSG;所有在宏中定義的標號都必須使用LOCAL聲明,如果你向多次使用該宏的話15. jmp begin16. DEFAULTMSG: DB No Given Message!,0DH,0AH,$;為了使得用戶使用宏時,不用再自定義默認消息,我們這里才宏中定義一個默認字符串17. begin: pus
28、h ds18. push dx19. push ax;要注意保護寄存器!20.21. IFB ;IFB后面的形參必須用尖括號括起來,這里的尖括號并不是字符串原樣輸出運算符!22. mov ax, cs;默認字符串的段,并非程序的數據段,而是代碼段!23. mov ds, ax24. mov ah, 09H25. mov dx, OFFSET DEFAULTMSG26. ELSE27. mov ah, 09H28. mov dx, OFFSET MSG29. ENDIF30. int 21H31. pop ax32. pop dx33. pop ds34. ENDMl 這兩條偽指令一般都用于宏定
29、義體內部。l 偽指令IFB:如果在宏調用時,沒有實參來代替形參,也就是沒有實參,那么條件滿足。l 偽指令IFNB:如果在宏調用時,有實參來代替形參,也就是有實參,那么條件滿足l 又是一對條件相反的指令。2) 偽指令IFIDN和IFDIFl 一般格式:1. IFIDN,2. IFIDNI,3. 4. IFDIF,5. IFDIFI,6. 7. ;以下為示例:8. ;示例1:9. RDWRMACROBUFF,RWMODE10. leadx, BUFF11. IFIDNI,;如果宏參數,讀寫模式字符與READ一致,則匯編調用讀功能子程序部分12. callREADIT13. ENDIF14. IFI
30、DNI,;如果宏參數,讀寫模式與WRITE一致,則匯編調用寫功能子程序部分。15. callWRITEIT16. ENDIF17. ENDM18. ;示例2:19. GETCHMACROCHAR20. movah, 121. int21H22. IFNB23. IFDIFI,24. movCHAR, AL25. ENDIF26. ENDIF27. ENDMl 這兩條指令一般都用在宏定義體內部。l 偽指令IFIDN(IFIDNI):如果字符串參數1與字符串參數2相等,則條件滿足;后面添加的I是忽略大小寫的意思!l 偽指令IFDIF(IFDIFI):如果字符串參數1與字符串參數2不相等,則條件滿足
31、。l 參數1和參數2:有可能是宏的形參,如果是形參,則比較之前,需先用實參進行替換后,再比較。如果不是宏的形參,則直接比較即可。l 參數一定是字符串,不需要添加引號,字符串會逐個比較大??;每一條指令都有兩種格式,普通格式時,大小寫有區(qū)別;+I格式時,大小寫沒有區(qū)別。并且該字符串一定是手動輸入到源代碼中的!Intel匯編語言程序設計1. 概述a. 宏過程(macro procedure):命名語句塊;可被調用多次;調用時,宏的副本被直接插入到程序中b. 宏過程可以必須聲明在調用宏過程之前,或者聲明在單獨的文本文件中,通過INCLUDE包含之。c. 匯編器在預處理階段處理宏的展開。d. 在80X8
32、6匯編語言程序設計教程一書中同樣有關于宏的內容2. 宏的定義a. 方法:使用MACRO和ENDM偽指令在源程序的任意位置定義宏。b. 定義格式:1. macronameMACROparameter-1, parameter-22. statement-list3. ENDM4. ;建議對宏的名字(macroname)和ENDM之間的語句進行縮進5. ;statement-list即語句列表在宏被調用的時候才會被匯編;6. ;宏的定義中可以有任意多的參數,參數之間用逗號間隔c. 宏的參數1) 宏的參數實際上是有名字的容器,以存放調用者傳遞給宏的文本參數。2) 說明:l 宏參數可以是整數、變量名、
33、寄存器名等等l 預處理器把各種參數統(tǒng)一視為文本進行處理l 宏的參數沒有類型,因此預處理器并不檢查實參的類型是否與形參的類型匹配,如果不匹配,則會在匯編時由匯編器檢查。3) 示例:1. mPutcharMACROchar2. pusheax3. moval, char4. callWriteChar5. popeax6. ENDM3. 宏的調用a. 宏的調用:將宏的名字插入到需要調用宏的源碼中,并連接必要的參數,即完成宏的調用。b. 格式:1. 宏名稱參數1,參數22. ;其中宏名稱必須是宏被調用前已經在源代碼中定義號的宏的名字3. ;宏調用時每個實際參數都是一個文本值。4. ;實際參數的順序必
34、須按照宏定義時的參數順序5. ;實際參數的數目不一定與形參的數目一致:6. ;當傳遞的參數多于定義中的形參個數時,匯編器產生一個警告;7. ;當傳遞的參數少于定義中的形參個數時,那么未傳遞的參數用空參數表示。c. 說明:1) 宏代碼的執(zhí)行速度塊于過程代碼執(zhí)行,使用宏代碼可以減少程序在時間上的開銷。2) 重復使用大量的宏,會導致程序源代碼和程序體積增大4. 宏的其他特性a. 必須參數1) REQ修飾符可以指定宏的某個或某幾個參數是必須的,如果在宏展開中沒有獲得與之對應的實參,則顯示一條錯誤信息。2) 示例:1. mPutCharMACROchar:REQ;注意這樣的修飾方法2. pusheax3
35、. moval, char4. callWriteChar5. popeax6. ENDMb. 宏的注釋1) 宏定義中如果有普通注釋,則每次展開時都會將該注釋一起展開。為了避免這樣,利用雙分號寫宏注釋,則不會展開。2) 示例:1. mPutCharMACROchar:REQ2. pusheax;注意保護寄存器3. moval, char4. callWriteChar5. popeax6. ENDMc. ECHO偽指令1) 匯編器匯編源碼的過程中,ECHO偽指令可以在控制臺顯示一條消息。2) 示例:1. mPutcharMACRO char:REQ2. ECHO“Expanding the m
36、Putchar macro!”3. pusheax4. moval, char5. callWriteChar6. popeax7. ENDM3) 注意:l 顯示消息是在匯編過程中!而不是在程序執(zhí)行過程中l(wèi) 顯式的字符串不需要添加雙引號,否則會連同雙引號一同輸出。d. LOCAL偽指令1) 問題:宏定義中如果使用了標號,在多次調用之后,標號在宏展開后的源代碼中便會多次出現,導致符號重定義的錯誤!2) 使用LOCAL偽指令可以完美解決上述問題:3) 使用方法:1. makeStringMACROtext2. LOCALstring3. .data4. stringBYTEtext,05. END
37、M6. ;另一個例子:7. AgainMACRO8. LOCALloop09. movecx, 1010. loop0:11. inceax12. looploop013. ENDM4) LOCAL后可以跟多個標號,標號之間用逗號間隔e. 包含代碼和數據的宏1) 一般方法:在宏定義中,同時定義一個數據段和一個代碼段,即完成了包含數據和代碼的操作。2) 示例:1. mWriteMACROtext2. LOCALstring3. .data4. stringBYTEtext,05. .code6. pushedx7. movedx, OFFSET string8. callWriteString9
38、. popedx10. ENDMf. 宏的嵌套1) 在另外一個宏內被調用的宏稱為嵌套宏(nested macro)2) 盡量使用模塊化的方法創(chuàng)建宏,保持每個宏的簡短,以便用于創(chuàng)造更復雜的宏,這樣做有助于減少程序中的重復代碼。3) 示例:1. mWriteLnMACROtext2. mWritetext;宏mWrite已經在上一段代碼中定義過了3. callCrlf4. ENDM5. 使用本書附帶的宏庫a. 大概1) .inc文件是文本文件,即包含文件,我們可以將很多宏定義在一個獨立的文本文件中,然后在需要調用它們的源代碼文件中包含該文件即可!2) 本節(jié)所羅列的所有宏:宏的名字參數描述mDump
39、varName,useLabel顯示一個變量,使用變量名及變量的默認屬性mDumpMemaddress,itemCount,componentSize顯示一塊內存的內容mGotoxyx,y設置控制臺緩沖區(qū)中光標的位置mShowvarName從鍵盤讀取一個字符串mReadStringitsName,fomat以多種格式顯示一個變量或寄存器mShowRegisterregName,regValue顯示一個32位的寄存器的名字及其內容,以十六進制格式mWritetext在控制臺窗口中顯示一個字符串mWriteSpacecount在控制臺窗口中顯示一個或多個空格mWriteStringbuffer在控
40、制臺窗口中顯示一個字符變量的內容b. mDumpMem1) 功能描述:在控制臺窗口顯示一塊內存的內容2) 參數解釋:l 第一個參數包含要顯示的內存偏移地址的常量、寄存器或變量l 第二個參數:要顯示的項目的數量l 第三個參數:單個項目的字節(jié)數,該參數也指明了最后顯示結果的形式!3) 實現1. mDumpMemMACROaddress:REQ,itemCount:REQ,componentSize:REQ2. pushebx3. pushecx4. pushesi5. movesi, address6. movecx, itemCount7. movebx, componentSize8. cal
41、lDumpMem9. popesi10. popecx11. popebx12. ENDMc. mDump1) 功能描述:以十六進制格式顯示變量的地址和內容2) 參數解釋:l 第一個參數:變量的名字l 第二個參數:(可選的)傳遞一個字符Y或者是N表示是否顯示變量的名字3) 實現1. mDumpMACROvarName:REQ, useLabel2. callCrlf3. IFNBuseLabel4. mWrite “Variable name: &varName”5. ENDIF6. mDumpMemOFFSET varName,LENGTHOF varName,TYPE varName7.
42、ENDMd. mGotoxy1) 功能描述:把光標定位在屏幕上指定的位置2) 參數解釋:l 第一個參數:Xl 第二個參數:Y,X和Y可以是8位的立即數或內存操作數或寄存器3) 實現1. mGotoxyMACRO X:REQ,Y:REQ2. pushedx3. movdh, Y4. movdl, X5. callGotoxy6. popedx7. ENDMe. mReadString1) 功能描述:從鍵盤上讀取一個字符串并把該字符串存儲在一個緩沖區(qū)中2) 參數解釋:l 第一個參數:緩沖區(qū)的名字,或者是存儲緩沖區(qū)偏移地址的寄存器3) 實現1. mReadStringMACROvarName:REQ
43、2. pushecx3. pushedx4. movedx, OFFSET varName5. movecx, SIZEOF varName6. callReadString7. popedx8. popecx9. ENDMf. mShow1) 功能描述: 以調用者選定的格式顯示任意寄存器或變量的名字和內容2) 參數解釋:l 第一個參數:寄存器或變量名l 第二個參數:輸出參數:H = 十六進制 D = 無符號十進制整數 I = 有符號十進制整數 B = 二進制 N = 添加一個換行符 可以組合多種輸出格式,也可以指定多個換行符默認格式:HIN3) 實現該宏的實現過長,該宏定義在Macros.i
44、nc包含文件中g. mShowRegister1) 功能描述:以十六進制格式顯示一個32位寄存器的內容2) 參數解釋:l 第一個參數:對于該寄存器要顯示的名字,被用作字符串。l 第二個參數:該寄存器的名字,被用來取值3) 實現1. mShowRegisterMACROregName,regValue2. LOCAL tempStr3. .data4. tempStrBYTE“®Name=”,05. .code6. pushedx7. movedx, OFFSET tempStr8. callWriteString9. popedx10. 11. moveax, regValue12. c
45、allWriteHex13. popeax14. ENDMh. mWriteString1) 功能描述:在控制臺窗口顯示一個字符串的內容2) 參數解釋:l 第一個參數:字符串名3) 實現1. mWriteStringMACRO buffer:REQ2. pushedx3. movedx, OFFSET buffer4. callWriteString5. popedx6. ENDMi. mWriteSpace1) 功能描述:在控制臺窗口顯示一個或多個空格2) 參數解釋:l 第一個參數:一個數字,指定空格的數量,默認個數是13) 實現1. mWriteSpaceMACROcount:=;默認實參
46、的寫法2. LOCAL spaces3. .data4. spacesBYTEcount DUP( ),05. .code6. pushedx7. movecx, OFFSET spaces8. callWriteString9. popedx10. ENDM6. 例子程序:封裝10.3 條件匯編偽指令 與 宏0.前言a. 條件匯編偽指令和宏聯(lián)合使用可以使得宏更加靈活。b. 本節(jié)看似在講述關于條件匯編偽指令的相關內容,但是無不聯(lián)系了宏的應用!c. 一般格式1. IFcondition2. statement3. ELSE4. statement5. ENDIFd. 本章介紹的是:常量條件偽指令
47、;6.7節(jié)介紹的是:運行時偽指令e. 條件匯編偽指令概況偽指令說明IF 表達式如果表達式為真(非0)則允許匯編。可以使用的相關操作符有LT,GT,NE,LE,GEIFB如果參數為空則允許匯編,參數名必須用尖括號()括起來IFNB如果參數不為空則允許匯編,參數名必須用尖括號括起來IFIDN,如果兩個參數相同則允許匯編,參數比較是大小寫敏感的IFIDNI,如果兩個參數相同則允許匯編,參數比較是不區(qū)分大小寫的。IFDIF,如果兩個參數不同則允許匯編,參數比較是大小寫敏感的。IFDIFI,如果兩個參數不同則允許匯編,參數比較是不區(qū)分大小寫的。IFDEF 名字如果名字已經定義則允許匯編IFNDEF 名字
48、如果名字未定義則允許匯編ENDIF結束一個條件匯編偽指令開始的語句塊ELSE如果前面的條件匯編偽指令的條件均為假,則匯編該偽指令至ENDIF偽指令之間的語句ELSEIF 表達式如果前面的條件匯編偽指令的條件均為假,則匯編該偽指令至下一條匯編偽指令之間的語句EXITM立即退出宏,組織其后任何語句的展開1. 檢查缺少的參數(介紹使用了IFB條件匯編偽指令的用途?。゛. 宏可以通過條件匯編偽指令檢查其任何一個參數是否為空。b. 背景:當宏的用戶使用宏,某個參數為空時,有可能生成錯誤的指令,在匯編時產生錯誤。為了減少宏的用戶產生此類錯誤,需要檢查缺失參數,并做防范措施。c. 示例:1. mWriteStrMACRO string2. IFB;當用戶未提供參數時,在預處理階段就顯示出錯信息,并不展開宏3. ECHO -4. ECHO * Error: parameter missing in mWriteStr5. ECHO * (no code
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度智能家居加盟品牌授權合同3篇
- 二零二五年度新能源儲能系統(tǒng)購買合同3篇
- 二零二五年度林業(yè)人才培養(yǎng)合作造林協(xié)議3篇
- 2025年度老舊房屋漏水檢測與賠償專項協(xié)議3篇
- 2025年度股東退出與公司知識產權保護合同3篇
- 二零二五年度模特服裝租賃拍攝合同3篇
- 2025年度房地產公司合伙人項目合作協(xié)議3篇
- 二零二五年度循環(huán)水養(yǎng)殖養(yǎng)魚合作合同3篇
- 2025年度體育場館物業(yè)用房移交及賽事運營服務合同3篇
- 2025年度企業(yè)年會活動宣傳片制作服務合同模板3篇
- 合伙經營木材加工廠協(xié)議書
- 寫作思路要清晰省公開課一等獎新名師比賽一等獎課件
- 前列腺癌根治術護理查房課件
- AQ 1017-2005 煤礦井下安全標志(正式版)
- 甘肅2024年甘肅省公安廳招聘輔警109人筆試歷年典型考題及考點附答案解析
- 小升初數學《選擇題》100道有答案解析
- 2024年中考英語真題-帶答案
- 剪映專業(yè)版:PC端短視頻制作(全彩慕課版) 課件 第3章 短視頻剪輯快速入門
- (高清版)JTG 6310-2022 收費公路聯(lián)網收費技術標準
- 儲能一體柜技術協(xié)議
- 設備間火災應急預案
評論
0/150
提交評論