匯編學習筆記(13) - 宏指令(MASM)


結構

    說明:

    是一堆數據的定義的集合

    基本格式:

    結構名稱       STRUC
      字段的定義
    結構名稱       ENDS
        
    舉例:
    STUDENT    STRUC
      ID       DW         ?
      SCORE   DB          1
      NAME     DB          'STUDENTNAME'
    STUDENT    ENDS
        

    定義變量:

    變量名         結構類型    < 參數表 >
        
    舉例:    
      S1     STDUENT        <1,50,'zhao'>
      S2     STDUENT        <1,60,'zhang'>
      S3     STDUENT        <1,70,'wang'>
        

    結構使用:

    1. MOV AX, P1.ID
        
    2. MOV BX, OFFSET P1
           MOV AL, [BX].SCORE

    總結:

    使用起來還是和C/C++ 的結構比較類似的,實際上  P1.ID  和 [BX].SCORE 的兩種引用方式本質上是匯編器幫我們轉換了地址。
        

記錄

    說明:

    結構是將將一堆定義結合起來,方便管理,那么記錄就是講一個字或者一個字節拆分成各種按照位的定義
    實際上記錄就是一個字或者字節的按位定義,所以長度最長不超過16位,右對齊。
        

    基本格式:

    記錄名稱       RECORD           字段1:位寬=初始值,字段2:位寬=初始值,….
        
    舉例:
      ABCD    RECORD     AA:5=12, BB:3=6, CC:4=3
            
    內存結構:
            
      15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0
      0   0   0   0   aa  aa  aa  aa  aa  bb  bb  bb  cc  cc  cc  cc
        

    定義變量:

    變量名         結構類型    < 參數表 >
        
    舉例:    
              S2     ABCD        <1,2,3>
              S1     ABCD        <1,2,3>
              S3     ABCD        <3,2,1>
        

    記錄使用:

     WIDTH
      返回一個記錄整體的位寬或者一個字段的位寬
      MOV AX, WIDTH ABCD
      MOV AX, WIDTH AA
        
        
     MASK
      返回對應字段的掩碼
      MOV BX, MASK AA;       BX = 0001111100000000B
    

    總結:

    和結構的功能有點類似,相當於在字節尺度尺度上的結構定義,相當於定義 標志位, 而MASK 就是提取標志位的掩碼。
        

宏定義

    說明:

    宏定義的本質和C/C++ 一樣就是字符替換,用定義的內容替換掉宏標識符
        

    基本格式:

    宏名稱      MACRO      參數1,參數2,………
        local      標號1, 標號2 ……
        標號1: xxxxx
            xxxxx
            xxxxx
        ENDM

        舉例:

      M1    MACRO      OPR, X, Y
          LOCAL          P1, P2
          P1:         OPR    AX, BX
              MOV  AX,  X
              MOV  BX,  Y
              TEST   AX, BX
              JNZ   P1
              JMP  P2
          P2:         MOV AX, BX
                    ENDM
        

    宏的使用:

    M1      MOV, 5, 1
    這條指令會被展開如下結果大致上就是字符替換
        
    ??0001:    MOV   AX, BX
                               MOV   AX, 5
                     MOV   BX, 1
                    TEST   AX, BX
                    JNZ    ??0001
                    JMP    ??0002
    ??0002:   MOV  AX, BX
        
    其中值得注意的是標號被替換成了  ??0001 ??0002   這是因為 宏如果在同一段代碼里多次展開,標號也會跟着被多次展開,那么就會出現一段代碼里同一個標號被多次定義,就會報錯,所以如果在宏定義里面有標號定義,那么在 開頭要使用 LOCAL 指令聲明本地標號,這樣匯編器會自動累加數字來代替標號
    另外,使用的時候參數多傳少傳都可以,多傳了就舍棄,少傳了就默認用空代替,之后介紹的命令 IFB 可以判斷參數是否為空
        

    參數傳遞的說明:

   &     連接參數用的,應該與C中的用法差不多,通常用於字符拼接以及字符串中
        定義:
        JUMP   MACRO    CON,LAB
             J&CON      LAB            ;;  這里就是將 字符 J 和 CON 的傳入的內容拼接起來
                ENDM
      使用:
        JUMP     NZ, EXIT
      展開為
        JNZ  EXIT
      同理如果是定義在'' 字符串中頁需要用& 表明是參數
      定義:
        MSG MACRO A,B
          A    DB 'MR.&B'
          ENDM
      使用
                   MSG   A1,HELLO
      展開為
                   A1     DB  'MR.HELLO'
        
         <>  字符串原樣傳遞,如果字符串中報個各種字符,比如空格 特殊字符等,就用 <> 包起來,
                 匯編就會把他們統統當成一個完整字符串而不會去解析含義了 
                 比如   < 包含各種內    容的字符,串--//123!@#$%^ > 中間有逗號,如果不用<> 匯編器會以為是兩個參數
        
         !    轉義符號在上面的, 相當於c在字符串中的 \ , 這里比如 有一段字符串   1>2   ,如果用<> 包起來 就變成   <1>2>, 那就不對了,
             匯編器會以為到1后邊的> 就結束了,所以要用  <1!>2>, 用!來個后面的 > 轉義.
        
         %  在參數傳遞的時候是可以傳入表達式的, 用%() 包起來,就是告訴匯編器闖入的是表達式的值而不是標的是本身。
              比如
      定義:
        MSG MACRO A,B
                          A    DB 'MR.&B'
                         ENDM
      使用
        MSG   A1, 1+2
      展開為
        A1     DB  'MR.1+2'
                
      使用 
                    MSG   A1, %(1+2)
                 展開為
                    A1     DB  'MR.3'

    其他說明:

     PURGE   消除宏定義
      比如前面定義了 宏  MSG, 那么在使用 PURGE MSG 之后的代碼里,MSG這個宏就不能使用了,但是之前還是能使用的。
     EXITM   終止宏的展開
      這個偽指令用在宏定義里面,當宏展開的時候遇到這個命令就停止展開了,相當於階段宏的內容。

    總結:

    宏的功能有點像子過程調用,但是由於它是在匯編階段就展開的,沒有像CALL 一樣的壓棧轉跳等的開銷,所以實際上他比CALL高效,實際上就有點像C++ 中的 INLINE 函數。
    宏中可以使用宏,宏定義中頁可以嵌套定義宏,但是嵌套定義的宏,需要使用一次宏才會生效,比如
      DEF     MACRO   A
        A    MACRO   
                                    push    ax
                              ENDM
                    ENDM
            
    如果不使用DEF宏定義,那么DEF宏定義不會被展開,那么根本就沒有 A的宏定義,如果順序是這樣的
        
      DEF   DEF2
      被展開為
      DEF2  MACRO
          PUSH AX
         ENDM
    這個使用宏定義中的宏定義才被真正定義
    之后才可以使用DEF2的宏定義
        

重復匯編

    說明:

    用途就是相當於寫了個循環
    如下場景
      db     0
      db     0
      .
      20 個這樣的內容,目的是定義20個byte變量,或者說就是定義   BYTE    LIST[20]
      .
      db     0
      db     0
      那就可以用 重復匯編  宏指令了
        

    基本格式:

  RPET
    格式 
      REPT    NUM
          XXXXXX
                                  ENDM
    說明   
      功能就是將里面的內容直接復制粘貼多少遍
    比如
        rept   5
          db 0
        endm
      展開為
                       db  0
                       db  0
                       db  0
                       db  0
                       db  0
 
       可以用來定義數據   比如 BYTE LIST[20], 直接就是
        rept  20
        db  0
        endm
                
         IRP
     格式
      IRP    待替換參數<參數表1,參數表2,參數表3,參數表4,參數表5,參數表6>
        xxxxxxx
        endm
             說明
      本質還是一樣的,但是功能豐富了一點,在復制的時候,會逐一使用參數表內容替換待替換參數
             比如
      IRP   P1<1,2,3,4,5,6>
        DB   P1
        ENDM
      展開為
        DB 1
                        DB 2
                        DB 3
                        DB 4
                        DB 5
                        DB 6
            
         IRPC
             格式
      IRPC   待替換參數,字符串
          xxxxxxx
        endm
             說明
      其實和IRP 是一樣的,就是用參數表逐一替換,不同的是給出這里給出的參數是字符串,這個偽指令會用字符串的字符來逐一代替
             比如
      IRP   P1 abcdef
        DB   P1
        ENDM
      展開為
                       DB 'a'
                       DB 'b'
                       DB 'c'
                       DB 'd'
                       DB 'e'
                       DB 'f'

 總結:

        這三個偽指令只要是在定義數據的時候使用的
    

條件匯編

    說明:

    和C/C++ 中的
    #Ifxxx  
    #else  
    #endfi 
    是一樣的東西

    基本格式:

    IFXXX
    ELSE
    ENDIF

    IF/IFE

    判斷標的是的值,用法和LINUX SHELL中的用法蠻相似的
    IF    (表達式)
      表達式 != 0 的時候內容有效
    ELSE
      表達式 == 0 的時候內容有效
    ENDIF
        
     表達式的計算使用  https://www.cnblogs.com/alwaysking/p/7623781.html 中介紹的內容

    IFDEF/IFNDEF

    和C/C++ 中的#ifdef 與#ifndef 意義完全相同

    IFB

    用在宏定義中的,用於判斷某個參數 是否為空的
    比如
    MSG MACRO A,B
      ifb   <B>
        A    DB 'MR.&B'
      else
        A     DB 'MR.UNKNOW'
      endif
     ENDM
  

INCLUDE

    說明

    沒錯與C/C++ 中的含義一致,就是在INCLIDE 的位置直接將INCLUDE的文件的拼接(復制粘貼)進來

    用法

    INCLUDE  A.ASM

    說明

    include后面可以跟路徑,和C/C++ 一樣,匯編器會首先在當前目錄找,之后會在編譯參數指定的尋找路徑查找文件

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM